字节跳动2019春招研发部分编程题汇总(Python版本)

一、万万没想到之聪明的编辑

王大锤是一家出版社的编辑,负责校对投稿来的英文稿件,他发现一个发现拼写错误的捷径:

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

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

输入描述:

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

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

输出描述:

N行,每行包括一个被修复后的字符串。

输入例子1:

2
helloo
wooooooow

输出例子1:

hello
woow

题解:

每次取判断是否连续出现3个相同和是否出现"AABB"的形式即可。

n=int(input())
for i in range(n):
    s=list(input())
    k=0
    for j in range(len(s)):
        s[k]=s[j]
        k+=1
        if k>=3 and s[k-3]==s[k-2] and s[k-2]==s[k-1]:
            k-=1              
        if k>=4 and s[k-4]==s[k-3] and s[k-2]==s[k-1]:
            k-=1      
    print(''.join(s[:k]))

【注】
1、使用python想用input输入一个整数,但是input()函数返回值是str型。需要这样转换:a=int(input(“请输入一个整数”))(强制类型转换,其他同理)或者用a=eval(input(“请输入一个整数”))(自动类型转换)
2、range(5)等价于range(0,5),是[0, 1, 2, 3, 4]没有5
3、list() 方法用于将元组转换为列表。
4、join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。

二、万万没想到之抓捕孔连顺

王大锤是一名特工。刚刚接到任务抓捕恐怖分子孔连顺。和他一起行动的还有另外两名特工,他提议

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

给定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)

题解:
设置两个指针,i指针为第一个特工的下标,j指针为另外两个特工最远位置的下标,依次遍历;根据排列组合,每个i指针对应的方案数为C(j-i,2),将所有方案数相加。

n, dist = map(int, input().split()) #n是建筑物数目,dist是两个特工相距的最大距离
nums = list(map(int, input().split())) #列表nums存储所有建筑物的坐标(横轴)
res = 0 #res埋伏方案数目
i = 0 #i为第一个特工的下标
j = 2 #j为另外两个特工最远位置的下标,因为有三个特工,所以j的下标从2开始
while i < n-2:
    while j < n and nums[j] - nums[i] <= dist: #符合埋伏条件,继续搜寻
        j += 1 #最后一次时会使j多加一次
    if j - 1 - i >= 2:
        num = j - i - 1 #num为C的底数
        res += num * (num - 1) // 2 #排列组合C(num,2)=num!/(num-2)!*2!
    i += 1
res= res%99997867
print(res)

【注】
1、a, b,c= map(int, input().split(’,’)) #一行输入多个用逗号隔开的数字,这里是输入三个数字。
N = list(map(int, input().split())) #一行输入多个空格隔开的数字,并以列表的形式存储。
2、排列A(n,m)=n!/(n-m)!(n为下标,m为上标,以下同)
组合C(n,m)= n!/m!(n-m)!;

三、雀魂启动!

小包最近发明了一种新的麻将,具体的规则如下:

总共有36张牌,每张牌是1~9。每个数字4张牌。
你手里有其中的14张牌,如果这14张牌满足如下条件,即算作和牌
14张牌中有2张相同数字的牌,称为雀头。
除去上述2张牌,剩下12张牌可以组成4个顺子或刻子。顺子的意思是递增的连续3个数字牌(例如234,567等),刻子的意思是相同数字的3个数字牌(例如111,777)

例如:
1 1 1 2 2 2 6 6 6 7 7 7 9 9 可以组成1,2,6,7的4个刻子和9的雀头,可以和牌
1 1 1 1 2 2 3 3 5 6 7 7 8 9 用1做雀头,组123,123,567,789的四个顺子,可以和牌
1 1 1 2 2 2 3 3 3 5 6 7 7 9 无论用1 2 3 7哪个做雀头,都无法组成和牌的条件。

现在,小包从36张牌中抽取了13张牌,他想知道在剩下的23张牌中,再取一张牌,取到哪几种数字牌可以和牌。

输入描述:

输入只有一行,包含13个数字,用空格分隔,每个数字在1~9之间
数据保证同种数字最多出现4次。

输出描述:

输出同样是一行,包含1个或以上的数字。代表他再取到哪些牌可以和牌。
若满足条件的有多种牌,请按从小到大的顺序输出。若没有满足条件的牌,请输出一个数字0

输入例子1:

1 1 1 2 2 2 5 5 5 6 6 6 9

输出例子1:

9

例子说明1:

可以组成1,2,5,6的4个刻子和9的雀头

输入例子2:

1 1 1 1 2 2 3 3 5 6 7 8 9

输出例子2:

4 7

例子说明2:

用1做雀头,组123,123,567或456,789的四个顺子

输入例子3:

1 1 1 2 2 2 3 3 3 5 7 7 9

输出例子3:

0

例子说明3:

来任何牌都无法和牌

题解:
原理:如果该手牌胡牌,那么每个数字必然是,雀头、刻子、顺子的成员,
递归算法 : 从最小的数字开始尝试,如果把其当成雀头成员,该数字划掉两个,并看余下的数字能否划空
如果是刻子成员,该数字划掉三个,并查看余下数字能否划空
如果是顺子成员,划掉该值a, a + 1, a + 2,并查看余下数字能否划空
如果上述三种尝试都无法划空数组,说明存在数字无法是雀头、刻子、顺子的成员,
将一个数字牌补入13个牌之中,判断是否和牌,是则输出,不是则下一个数字牌

def IShepai(str):
    lenth=len(str)
    #能否划空
    if lenth == 0:
        return True
    count1=str.count(str[0])
 	# 没出现过雀头,且第一个数字出现的次数 >= 2,去掉雀头剩下的能不能和牌
    if lenth%3!=0 and count1>=2 and IShepai(str[2:])==True:
        return True
    # 如果第一个数字出现次数 >= 3,去掉这个刻子后看剩下的能和牌
    if  count1 >= 3 and IShepai(str[3:])==True:
            return True
    # 如果存在顺子,移除顺子后剩下的能和牌
    if str[0] + 1 in str and str[0] + 2 in str:
        str1 = str[1:]
        str1.remove(str[0]+1)
        str1.remove(str[0]+2)
        if IShepai(str1) == True:
            return True
    # 以上条件都不满足,则不能和牌
    return False
    
if __name__ == '__main__':
    a=list(map(int, input().split()))
    flag=0
    #遍历所有可以抓到的牌看能不能胡牌
    for i in range(1,10):
        al=sorted(a + [i])
        #每个数字最多4张牌
        if al.count(i)>4:
            continue
        else:
            if IShepai(al) == True:
                flag=1
                print(i,end=" ")
    if flag==0:
        print(0)

四、特征提取

小明是一名算法工程师,同时也是一名铲屎官。某天,他突发奇想,想从猫咪的视频里挖掘一些猫咪的运动信息。为了提取运动信息,他需要从视频的每一帧提取“猫咪特征”。一个猫咪特征是一个两维的vector。如果x_1=x_2 and y_1=y_2,那么这俩是同一个特征。
因此,如果喵咪特征连续一致,可以认为喵咪在运动。也就是说,如果特征在持续帧里出现,那么它将构成特征运动。比如,特征在第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
n = int(input()) # n代表测试用例的个数
while n > 0: 
    m = int(input()) # m代表视频的帧数
    res = 1 #res代表最长特征运动的长度
    d = {} # 字典d记录{猫咪的特征值(key),特征运动长度(特征值连续出现的次数)}
    for i in range(m):
        l = list(map(int , input().split())) # 每行代表一帧
        k = l[0] # 第一个数字是该帧的特征个数
        tmp_d = {}
        for j in range(k):
            index = l[2 * j + 1]* 10 + l[2 * j + 2] #两个数字形成的特征值归一化为index
            if index in d: # 此特征值出现在了上一帧中
                tmp_d[index] = d[index] + 1
                res = max(res, tmp_d[index]) # 更新res即最长特征运动的长度
            else:
                tmp_d[index] = 1
        d = tmp_d #及时更新字典d的内容
    print(res)
    n -= 1

五、毕业旅行问题

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

输入描述:

城市个数n(1

输出描述:

最小车费花销 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元以内,无需考虑极端情况。
import itertools
n = int(input()) #城市个数n(1
L = [] #城市间的车票价钱 n行n列的矩阵 [n][n]
for i in range(n):
    L.append(list(map(int, input().split(' '))))
 
def treaval(L, n):
    # 除起点之外的不同路线组合,假设起点为0号节点
    com = list(itertools.permutations(list(range(1, n)), n - 1))  #range函数返回的是一个可迭代对象,而不是列表类型, 所以打印的时候不会打印列表。
    spend = 9999  # 假设一开始花销很大
    for j in range(len(com)): #len(com)是可选择的路线种类数
        road = list(com.pop(0))# 获取其中一种路线组合road列表之后就释放,com是一个元组序列
        # 补全起点和终点(注意起点也是终点,形成闭环)此时road长度为n+1
        road.append(0)#在列表末尾添加新的对象
        road.insert(0, 0)#将对象插入列表
        x = 0 # 当前路线的花销
        for i in range(n):
            x = x + L[road[i]][road[i + 1]]
        if x < spend:
            spend = x #更新最小花销
    return spend
 
print(treaval(L, n))

【注】

若想遍历一个集合中元素的所有可能的排列或组合
itertools模块提供了函数来解决这类问题。其中一个是itertools.permutations(),它接受一个集合并产生一个元组序列,每个元组由集合中所有元素的一个可能排列组成,也就是说通过打乱集合中元素排列顺序生成一个元组。
items=[‘a’,‘b’,‘c’]
from itertools import permutations
for p in permutations(items):
print§

字节跳动2019春招研发部分编程题汇总(Python版本)_第1张图片

#若想得到指定长度的所有排列,你可以传递一个可选的长度参数
for p in permutations(items,2):
print§

字节跳动2019春招研发部分编程题汇总(Python版本)_第2张图片

六、找零

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

输入描述:

一行,包含一个数N。

输出描述:

一行,包含一个数,表示最少收到的硬币数。

输入例子1:

200

输出例子1:

17

例子说明1:

花200,需要找零824块,找12个64元硬币,3个16元硬币,2个4元硬币即可。
lyst = [64, 16, 4, 1] #硬币列表(从大到小排列)
cost = 1024 - int(input())
res = 0 #最少得到的硬币数量
for i in lyst:
    res += cost//i #取整除 - 返回商的整数部分(向下取整)
    cost %= i #取模 - 返回除法的余数
print(res)

七、机器人跳跃问题

机器人正在玩一个古老的基于DOS的游戏。游戏中有N+1座建筑——从0到N编号,从左到右排列。编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位。

起初, 机器人在编号为0的建筑处。每一步,它跳到下一个(右边)建筑。假设机器人在第k个建筑,且它现在的能量值是E, 下一步它将跳到第个k+1建筑。它将会得到或者失去正比于与H(k+1)与E之差的能量。如果 H(k+1) > E 那么机器人就失去 H(k+1) - E 的能量值,否则它将得到 E - H(k+1) 的能量值。

游戏目标是到达第个N建筑,在这个过程中,能量值不能为负数个单位。现在的问题是机器人以多少能量值开始游戏,才可以保证成功完成游戏?

输入描述:

第一行输入,表示一共有 N 组数据.

第二个是 N 个空格分隔的整数,H1, H2, H3, ..., Hn 代表建筑物的高度

输出描述:

输出一个单独的数表示完成游戏所需的最少单位的初始能量

输入例子1:

5
3 4 3 2 4

输出例子1:

4

输入例子2:

3
4 4 4

输出例子2:

4

输入例子3:

3
1 6 4

输出例子3:

3
import math
input()
arr = list(map(int, input().split('')))
# 假设跳跃前能力为E,要跳的高度为H,那么跳跃后的能量就是E-(H-E)=2E-H,
# 那么跳跃后的能量加上高度就是跳跃前的两倍,然后从后往前逆推。
E = 0    # 跳到最后一步的能力值设为0
arr.reverse()#翻转列表逆推
for H in arr:
    E = math.ceil((E + H ) / 2) #向上取整,以此保证剩余能量大于等于0
print(E)

你可能感兴趣的:(剑指Offer)