【笔试代码题记录】20190810贝壳/网易互娱
作者:互联网
文章目录
2019.8.10 贝壳
2. 丢失的卡片
3. 锯子斧头
面前有n颗树,你有两种工具锯子和斧头,它们砍第i颗树的时间分别为ai和bi,一开始你拿的是斧头,而砍第i颗树前交换工具需要花费ci的时间,请问,看完这些树的时间最短是多少?
输入:
第一行一个数n(1<=100)
接下来n行,每行3个数ai,bi,ci(<=30000)
输出:最短时间
样例输入:
3
20 40 20
10 4 25
90 100 5
样例输出:
139
解法(正确解法):双状态的动态规划。 可以参考下leetcode714 带手续费的买卖股票问题。
def GetResult(record, n):
dp = [[0] * 2 for _ in range(n)]
# 第一棵树,第二维0,1表示斧头和锯子
dp[0][0] = record[0][1] # 表示本轮用斧子,花费的最少时间
dp[0][1] = record[0][0] + record[0][2] # 表示本轮用锯子,花费的最少时间
for i in range(1, n):
dp[i][0] = min(dp[i - 1][0] + record[i][1], dp[i - 1][1] + record[i][1] + record[i][2])
dp[i][1] = min(dp[i - 1][1] + record[i][0], dp[i - 1][0] + record[i][0] + record[i][2])
print(dp)
return min(dp[-1][0], dp[-1][1])
反思:自己没有想到用双状态的dp,而是使用了一个flag变量来表示当前的工具,没通过。。
4. 图的存在性
给定过一个1到N的排列P1-PN,请判断是否存在一个由N个点,N-1条边组成的无向连通图,满足对于任意两个整数i和j(i不等于j),若第i个点和第j个点之间有边相连,则第Pi个点和第Pj个点之间同样有边相连。
输入:
第一行输入一个整数T表示T组数据,
每组数据格式为:
第一行包括一个整数N,
第二行包含N个整数P1到PN
输出:
每组输出一行,如果存在满足条件的图则输出Yes,否则输出No
样例输入:
2
4
4 3 2 1
3
3 1 2
样例输出:
Yes
No
2019.8.11网易互娱
1. 转二进制后有多少个1 ,个数相同归为一类,问一共几类?
本题AC,思路:遍历给出的数字,统计每个数字的二进制中1的个数,讲这个个数存入集合中,最后输出集合的大小即可。
T=int(input()) for i in range(0,T):
N=int(input())
nums=list(map(int,input().split()))
res={} for x in nums:
temp="{0:b}".format(x) print(temp)
t=temp.count('1') if t not in res:
res[t]=1 else:
res[t]+=1 print(len(res))
2. 注水排水问题(没做出来)
水池容量为m,有注水管和排水管,刚开始两个管子都是开的,水池里没有水。每隔t1分钟,注水管状态改变一次,开变关,关变开;每隔t2分钟排水管状态改变一次,注水管在打开时,一分钟注水m1,排水管一分钟出水m2,问,t分钟后,水池里的水有多少?(1<=T<=10, 1<=m<=100000, 1<= t <= 86400, 1 <= m1,m2 <=100, 1<= t1,t2 <= 10
)
测试样例(几个参数分别是m, t, m1, t1, m2, t2):
10,2,1,5,2,5 # 输出0
10,2,10,5,2,5 # 10
10 2 3 5 2 5 # 2
100 100 3 4 4 3 # 3
10000 1000 10 5 5 3 # 2495
本题的暴力解法是:按时间从0开始遍历,每分钟判断两个水管的开关状态,然后每分钟更新一次水量,直至t时刻。
本题的优化解法是:循环一个周期性,周期性就是t1和t2的最小公倍数,循环这么多次,就统计出了在一个周期内池里剩余的水量,每个周期剩余的水量都是相同的。最后在单独处理t%周期性求余最后部分单独求解,可以减小计算量。
由于本题的暴力解法可以通过,因此牛客上的AC代码大都是暴力解法,这里列出一个AC代码:
def _clip(v, v_min, v_max): # 保证水不超过泳池限额
if v > v_min and v < v_max:
return v
elif v < v_min:
return v_min
else:
return v_max
def _update_water(M, on, off, m, m1, m2): # 每分钟更新一次水量
if on and off:
return _clip(M + (m1 - m2), 0, m)
elif on:
return _clip(M + m1, 0, m)
elif off:
return _clip(M - m2, 0, m)
else:
return M
def f(nums): # 主函数,返回最终水量即可
m, t, m1, t1, m2, t2 = nums
M, T = 0, 0 # 刚开始的水量和时间都是0
while T < t:
on, off = T // t1 % 2 == 0, T // t2 % 2 == 0 # 这行代码是精髓,判断当前时刻两个水管分别是开还是关
M = _update_water(M, on, off, m, m1, m2)
T += 1
return M
3. 最长重复字符串(AC90%)
给定字符串,最多允许改变两个字符,使得连续“N”串最长,求最长的连续N串的长度。
我的解法(AC 90%,至今不知道剩下的10%是哪里错了):遍历字符串,统计所有非“N”字符的下标在一个列表res中,然后将0和字符串长度len(s)添加到res的首尾(这样可以一起处理边界问题,类似于链表里面的dummy_head思想),遍历res列表,统计res[i] - res[i - 3]的最大值(相当于将res[i - 2]和res[i - 1]替换掉),输出最终结果。
测试用例:
s = 'NGNNNNGNNNNNNNNSNNNN' # 18
s = 'NNNNGGNNNN' # 10
s = "NNTN" # 4
def func(s):
if not s or len(s) <= 2:
return len(s)
queue = [] if s[0] == 'N' else [0]
for i in range(1, len(s)):
if s[i] != 'N':
queue.append(i)
if len(queue) <= 2: return len(s)
if queue[-1] < len(s): queue.append(len(s))
if queue[0] > 0: queue.insert(0,0)
res = 0
for i in range(3, len(queue)):
res = max(res, queue[i] - queue[i- 3] - 1)
return res
import sys
if __name__ == "__main__":
while True:
try:
t = int(sys.stdin.readline().strip())
if t:
for i in range(t):
s = input()
print(func(s))
else:
break
except:
break
网上的AC代码(动态规划):维护数组dp以及v_dp,dp保存要用到的索引,v_dp保存以当前字符结尾的最长连续字串长度(可容错2),最后返回v_dp的最大值即可. 个人感觉不那么容易理解。
def f(S):
n = len(S)
dp = [[-1, 0, 0] for _ in range(n)]
v_dp = [0 for _ in range(n)]
cnt = 0 # 用来统计替换了几次
for i in range(n):
if S[i] != 'N' and cnt == 0:
dp[i][1] = i
cnt += 1
elif S[i] != 'N' and cnt == 1:
dp[i][1] = dp[i - 1][1]
dp[i][2] = i
cnt += 1
elif S[i] != 'N' and cnt == 2: # 如果两次机会都替换了,则将最前面替换的“挤掉”
dp[i] = dp[i - 1][1:] + [i]
else:
dp[i] = dp[i - 1]
v_dp[i] = i - dp[i][0]
return max(v_dp)
AC代码二(双指针+计数,思路很清晰,重要):双指针左右夹逼,夹逼区间的宽的最大值即为所求。计数器count记录非N字符的个数,当计数器超过2时,左指针后移,一直移到计数器不超过2为止。时间复杂度O(n) 【参考】
def f(s):
if not s or len(s) <= 2:
return len(s)
left, right = 0, 0
count, res = 0, 0 # count用来统计替换的次数
while right < len(s):
if s[right] != 'N':
count += 1
right += 1
while count > 2:
if s[left] != 'N':
count -= 1
left += 1
res = max(res, right - left)
return res
标签:10,return,互娱,res,笔试,record,range,20190810,dp 来源: https://blog.csdn.net/aaon22357/article/details/99090811