[azl397985856/leetcode]【秋招】牛客2019 字节跳动秋招编程题汇总

2023-12-08 851 views
3

题目地址

https://www.nowcoder.com/test/16516564/summary

1. 大锤的自动校对程序

题目描述

我叫王大锤,是一家出版社的编辑。我负责校对投稿来的英文稿件,这份工作非常烦人,因为每天都要去修正无数的拼写错误。但是,优秀的人总能在平凡的工作中发现真理。我发现一个发现拼写错误的捷径:

  1. 三个同样的字母连在一起,一定是拼写错误,去掉一个的就好啦:比如 helllo -> hello
  2. 两对一样的字母(AABB型)连在一起,一定是拼写错误,去掉第二对的一个字母就好啦:比如 helloo -> hello
  3. 上面的规则优先“从左到右”匹配,即如果是AABBCC,虽然AABB和BBCC都是错误拼写,应该优先考虑修复AABB,结果为AABCC

我特喵是个天才!我在蓝翔学过挖掘机和程序设计,按照这个原理写了一个自动校对器,工作效率从此起飞。用不了多久,我就会出任CEO,当上董事长,迎娶白富美,走上人生巅峰,想想都有点小激动呢! …… 万万没想到,我被开除了,临走时老板对我说: “做人做事要兢兢业业、勤勤恳恳、本本分分,人要是行,干一行行一行。一行行行行行;要是不行,干一行不行一行,一行不行行行不行。” 我现在整个人红红火火恍恍惚惚的……

请听题:请实现大锤的自动校对程序

输入描述: 第一行包括一个数字N,表示本次用例包括多少个待校验的字符串。

后面跟随N行,每行为一个待校验的字符串。

输出描述: N行,每行包括一个被修复后的字符串。

输入例子1: 2 helloo wooooooow

输出例子1: hello woow

思路

第一想法是用正则实现,简单直接。

代码

const n = Number(readline());
let cur = ""
while(cur = readline()) {
    console.log(cur.replace(/([a-z])\1{1,}/g, "$1$1").replace(/([a-z])\1([a-z])\2/g, "$1$1$2"))
}

复杂度分析

  • 时间复杂度:取决于正则引擎的实现
  • 空间复杂度:取决于正则引擎的实现

2. 大锤特工

题目描述

我叫王大锤,是一名特工。我刚刚接到任务:在字节跳动大街进行埋伏,抓捕恐怖分子孔连顺。和我一起行动的还有另外两名特工,我提议

  1. 我们在字节跳动大街的N个建筑中选定3个埋伏地点。
  2. 为了相互照应,我们决定相距最远的两名特工间的距离不超过D。

我特喵是个天才! 经过精密的计算,我们从X种可行的埋伏方案中选择了一种。这个方案万无一失,颤抖吧,孔连顺! …… 万万没想到,计划还是失败了,孔连顺化妆成小龙女,混在cosplay的队伍中逃出了字节跳动大街。只怪他的伪装太成功了,就是杨过本人来了也发现不了的!

请听题:给定N(可选作为埋伏点的建筑物数)、D(相距最远的两名特工间的距离的最大值)以及可选建筑的坐标,计算在这次行动中,大锤的小队有多少种埋伏选择。 注意:

  1. 两个特工不能埋伏在同一地点
  2. 三个特工是等价的:即同样的位置组合(A, B, C) 只算一种埋伏方法,不能因“特工之间互换位置”而重复使用

输入描述: 第一行包含空格分隔的两个数字 N和D(1 ≤ N ≤ 1000000; 1 ≤ D ≤ 1000000)

第二行包含N个建筑物的的位置,每个位置用一个整数(取值区间为[0, 1000000])表示,从小到大排列(将字节跳动大街看做一条数轴)

输出描述: 一个数字,表示不同埋伏方案的数量。结果可能溢出,请对 99997867 取模

输入例子1: 4 3 1 2 3 4

输出例子1: 4

例子说明1: 可选方案 (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)

输入例子2: 5 19 1 10 20 30 50

输出例子2: 1

例子说明2: 可选方案 (1, 10, 20)

思路

思路是:

  • 固定两个端点,两个端点的距离是 X (X<=D)。
  • 然后将第二个和三个特工塞到两个端点内的 X 个 空位即可。
  • 在 X 个位置上塞两个人的组合数是 $C_X^(2)$, 即 $N*(N - 1) / 2$。

    代码

实际上可以利用 dict,单调栈等技巧加速寻找右边界的过程。

n, dist = map(int, input().split())
nums = list(map(int, input().split()))

ans = l = 0
r = 2 # ∵ D >= 1

while l < n - 2:
    while r < n and nums[r] - nums[l] <= dist:
        r += 1
    if r - 1 - l >= 2:
        cnt = r - l - 1
        ans += cnt * (cnt - 1) // 2
    l += 1

print(ans % 99997867)

复杂度分析

  • 时间复杂度:$O(N ^ 2)$,加速之后可以到 $O(N)$
  • 空间复杂度:$O(1)$

    3. 雀魂

4.猫的运动

题目描述

小明是一名算法工程师,同时也是一名铲屎官。某天,他突发奇想,想从猫咪的视频里挖掘一些猫咪的运动信息。为了提取运动信息,他需要从视频的每一帧提取“猫咪特征”。一个猫咪特征是一个两维的vector<x, y>。如果x_1=x_2 and y_1=y_2,那么这俩是同一个特征。

因此,如果喵咪特征连续一致,可以认为喵咪在运动。也就是说,如果特征<a, b>在持续帧里出现,那么它将构成特征运动。比如,特征<a, b>在第2/3/4/7/8帧出现,那么该特征将形成两个特征运动2-3-4 和7-8。 现在,给定每一帧的特征,特征的数量可能不一样。小明期望能找到最长的特征运动。

输入描述: 第一行包含一个正整数N,代表测试用例的个数。

每个测试用例的第一行包含一个正整数M,代表视频的帧数。

接下来的M行,每行代表一帧。其中,第一个数字是该帧的特征个数,接下来的数字是在特征的取值;比如样例输入第三行里,2代表该帧有两个猫咪特征,<1,1>和<2,2> 所有用例的输入特征总数和<100000

N满足1≤N≤100000,M满足1≤M≤10000,一帧的特征个数满足 ≤ 10000。 特征取值均为非负整数。

输出描述: 对每一个测试用例,输出特征运动的长度作为一行

输入例子1: 1 8 2 1 1 2 2 2 1 1 1 4 2 1 1 2 2 2 2 2 1 4 0 0 1 1 1 1 1 1

输出例子1: 3

例子说明1: 特征<1,1>在连续的帧中连续出现3次,相比其他特征连续出现的次数大,所以输出3

思路

用一个 dict 记录上一帧的最长特征运动,枚举这一帧的运动信息并更新 dict即可,在这个过程记录最大值,类似滚动数组。

代码

n = int(input())

while n > 0:
    n -= 1
    ans = 1
    pre = {}
    for _ in range(int(input())):
        l = list(map(int , input().split()))
        k = l[0]
        cur = {}
        for j in range(k):
            k = (l[2 * j + 1], l[2 * j + 2])
            if k in pre:
                cur[k] = pre[k] + 1
                ans = max(ans, cur[k])
            else:
                cur[k] = 1
        pre = cur
    print(ans)·

复杂度分析

  • 时间复杂度:$O(N * K)$,,其中 K 为所有帧的特征平均值
  • 空间复杂度:$O(M)$,其中 M 为所有帧的特征最大值。

5. 小明的毕业旅行

题目描述

小明目前在做一份毕业旅行的规划。打算从北京出发,分别去若干个城市,然后再回到北京,每个城市之间均乘坐高铁,且每个城市只去一次。由于经费有限,希望能够通过合理的路线安排尽可能的省一些路上的花销。给定一组城市和每对城市之间的火车票的价钱,找到每个城市只访问一次并返回起点的最小车费花销。

输入描述: 城市个数n(1<n≤20,包括北京)

城市间的车票价钱 n行n列的矩阵 m[n][n]

输出描述: 最小车费花销 s

输入例子1: 4 0 2 6 5 2 0 4 4 6 4 0 2 5 4 2 0

输出例子1: 13

例子说明1: 共 4 个城市,城市 1 和城市 1 的车费为0,城市 1 和城市 2 之间的车费为 2,城市 1 和城市 3 之间的车费为 6,城市 1 和城市 4 之间的车费为 5,依次类推。假设任意两个城市之间均有单程票可购买,且票价在1000元以内,无需考虑极端情况。

思路

典型的旅行商问题(TSP), DP即可解决。

copy 一个模板过来改改就行了。

代码

改成非递归的 bottom-up 性能更好

import functools
n = int(input())
graph = []
for i in range(n):
    graph.append(list(map(int, input().split())))
visited = 1 << (n - 1)
@functools.lru_cache(None)
def dp(fr, to):
    if to == 0: return graph[fr][0]
    ans = float('inf')
    for i in range(1, n):
        if ((to >> (i - 1)) & 1) == 1:
            to ^= 1 << (i - 1) # mark visited
            ans = min(ans, graph[fr][i] + dp(i, to))
            to ^= 1 << (i - 1) # unmark
    return ans

print(dp(0, visited - 1))

复杂度分析

  • 时间复杂度:$O(2^N*N^2)$
  • 空间复杂度:$O(2^N*N)$

    6. 硬币找零

    题目描述

Z国的货币系统包含面值1元、4元、16元、64元共计4种硬币,以及面值1024元的纸币。现在小Y使用1024元的纸币购买了一件价值为的商品,请问最少他会收到多少硬币?

输入描述: 一行,包含一个数N。

输出描述: 一行,包含一个数,表示最少收到的硬币数。

输入例子1: 200

输出例子1: 17

例子说明1: 花200,需要找零824块,找12个64元硬币,3个16元硬币,2个4元硬币即可。

思路

完全背包问题,力扣硬币找零的简化版。

代码

n = 1024 - int(input())
dp = [1024] * (n + 1)
dp[0] = 0

for i in range(n + 1):
    for coin in [1, 4, 16, 64]:
        if i >= coin:
            dp[i]= min(dp[i], dp[i - coin] + 1)
print(dp[-1])

复杂度分析

  • 时间复杂度:$O(N)$
  • 空间复杂度:$O(N)$

代码

7.机器人跳跃

see: #423

更多题解可以访问我的LeetCode题解仓库:https://github.com/azl397985856/leetcode 。 目前已经35K star啦。

关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。

回答