HW笔试真题
参考:
华为笔试4月6
2021 华为秋招笔试题
华为笔试题
详解2021华为笔试三道编程题
华为秋招机试三道编程题(2021-08-25)
华为秋招机试三道编程题(2021-08-18)
哔哩哔哩-万诺coding
城市旅游规划
算法分析:
该题整体属于数组中滑动窗口的问题
1)首先,根据城市的花费值大小,对城市进行排序
2)对排序后的城市,进行常规的滑动窗口处理,即:
3)当两个城市的花费差值小于k时,右指针++,加上对应的开心值;否则左指针++,减去对应的开心值
Python源码
# 输入处理
N, k = map(int, input().split(' '))
city_xy = dict()
for i in range(N):
x, y = map(int, input().split(' '))
city_xy[x] = y
# 对键进行排序
keys_sorted = sorted(city_xy.keys())
# 定义双指针
left = right = 0
happy_vals = 0
max_happy = 0
while right < len(keys_sorted):
happy_vals += city_xy[keys_sorted[right]]
# 两个城市之间的花费差值不小于k
# 左指针就要右移,同时要减去对应的开心值
if keys_sorted[right] - keys_sorted[left] >= k:
happy_vals -= city_xy[keys_sorted[left]]
left += 1
# 取当前较大的开心值
max_happy = max(max_happy, happy_vals)
right += 1
print(max_happy)
最大化养猪距离
算法分析:
该题整体属于数组中二分查找的问题,但隐藏得比较深,很难直接分析出来
Python源码
N, M = map(int, input().split(' '))
room = list(map(int, input().split(' ')))
room.sort()
# 判断在当前间隔下,是否满足放下M条猪的情况
def check(mid):
pre = room[0]
count = 1
for i in range(1, len(room)):
if pre + mid <= room[i]:
count += 1
pre = room[i]
return count >= M
# 二分查找间隔
maxGap = (room[-1] - room[0]) // (M - 1)
left, right = 0, maxGap
res = maxGap
while left <= right:
mid = (left + right) // 2
if check(mid):
res = mid
left = mid + 1
else:
right = mid - 1
print(res)
最小攻击防御差
算法分析:
该题整体属于前缀和的问题
1)从前往后遍历整个数组,统计每个下标对应的攻击力
2)从后往前遍历整个数组,统计每个下标对应的防御力
3)两个数据结果相减,得到绝对值差值最小的那个位置就是切割位置
Python源码
strInput = input()
# 为了避免初始化,attack和defender都扩充了一个元素
# attack扩充的是第一个元素
# defender扩充的是最后一个元素
attack = [0] * (len(strInput) + 1)
defender = [0] * (len(strInput) + 1)
# 从前往后遍历
for i in range(1, len(strInput)+1):
# 如果遇见0,则再前一个值的基础上加上当前下标
if strInput[i-1] == '0':
attack[i] = attack[i-1] + i
else:
attack[i] = attack[i-1]
# 从后往前遍历
for i in range(len(strInput)-1, -1, -1):
# 如果遇见1,则再前一个值得基础上加上前下标
if strInput[i] == '1':
defender[i] = defender[i+1] + i+1
else:
defender[i] = defender[i+1]
# 移除扩充元素
attack = attack[1:]
defender = defender[:-1]
res = float('inf')
for i in range(len(attack)):
res = min(res, abs(attack[i]-defender[i]))
print(res)
2021-Cheng
关键路径—有向无环图
【数据结构】关键路径 及 代码实现(附 c,java,python代码)
图之查找关键路径(python)实现
算法分析:
1)生成邻接矩阵
2)求Ve(v):最早发生时间,是指从始点开始到顶点Vk的最大路径长度
-a)从前向后,取大值:直接前驱结点的Ve(j)+到达边(指向顶点的边)的权值,有多个值的取较大者
-b)首结点Ve(j)已知,为0
3)求Vl(v):最迟发生时间,在不推迟整个工期的前提下,事件vk允许的最晚发生时间
-a)从后向前,取小值:直接后继结点的Vl(j) –发出边(从顶点发出的边)的权值,有多个值的取较小者
-b)终结点Vl(j)已知,等于它的Ve(j))
4)求d(v):活动时间余量,d(v) = l(v) - e(v),等于0的为关键点,即不能拖延
Python源码
def demo(matrix):
# 最迟发生时间
ve = [0] * len(matrix)
que = [0] # 定义一个先进先出的队列
while que:
index = que.pop(0) # 取出队列中第一个元素,即matrix中的第index行
for i in range(len(matrix)): # 遍历matrix中的第index行
if matrix[index][i]: # 如果当前matrix元素不为零
# 判断从index到i的距离是否大于之前的距离
ve[i] = max(ve[i], ve[index]+matrix[index][i])
# 将i节点添加到队列中
que.append(i)
print('ve={}'.format(ve))
# 最早发生时间
vl = [ve[-1]] * len(matrix)
for index in range(len(matrix)-1, -1, -1): # matrix从下往上遍历
# 再从左往右遍历
for i in range(len(matrix)):
if matrix[index][i]: # 如果当前matrix元素不为零
# 判断从i到index的距离是否小于之前的距离
vl[index] = min(vl[index], vl[i]-matrix[index][i])
print('vl={}'.format(vl))
res = []
for i in range(len(ve)):
if ve[i] == vl[i]:
res.append("V" + str(i+1))
return res
matrix = [[0, 6, 4, 5, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 2, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 9, 7, 0],
[0, 0, 0, 0, 0, 0, 0, 4, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 2],
[0, 0, 0, 0, 0, 0, 0, 0, 4],
[0, 0, 0, 0, 0, 0, 0, 0, 0]]
keyPoint = demo(matrix)
print('Key point: ' + ' '.join(keyPoint))
解法二:
def demo(matrix):
passed = [0]
nopass = [i for i in range(len(matrix)) if i != 0]
maxDis = matrix[0]
path = dict()
for i in range(len(maxDis)):
if maxDis[i] != 0:
path[i+1] = [1]
while nopass:
index = nopass[0]
for k in nopass:
if maxDis[k] > maxDis[index]: index = k
passed.append(index)
nopass.remove(index)
for k in nopass:
if matrix[index][k] != 0:
if maxDis[index] + matrix[index][k] > maxDis[k]:
maxDis[k] = maxDis[index] + matrix[index][k]
path[k+1] = path[index+1] + [index+1]
print('ve={}'.format(maxDis))
print('path(1->9): {}'.format(path[9]))
return maxDis
# ve=[0, 6, 4, 5, 7, 7, 16, 14, 18]
# path(1->9): [1, 2, 5, 7]
Dijstra算法(迪杰斯特拉)
Dijkstra算法python详细实现
找到从起始节点(1)到终止节点(6)的最短路径
Python源码
def demo(matrix):
passed = [0] # 默认从第0个节点开始,以邻接矩阵的第0行为准
nopass = [i for i in range(len(matrix)) if i != 0]
minDis = matrix[0]
# 初始化起始路径
path = dict()
for i in range(len(minDis)):
if minDis != float('inf'):
path[i+1] = [1]
while nopass:
# 取出nopass中在minDis中路径最小的节点
index = nopass[0]
for i in nopass:
if minDis[i] < minDis[index]: index = i
nopass.remove(index)
passed.append(index)
for i in nopass:
if matrix[index][i] != float('inf'):
if minDis[index] + matrix[index][i] < minDis[i]:
minDis[i] = minDis[index] + matrix[index][i]
path[i+1] = path[index+1] + [index+1]
print('minDis={}'.format(minDis))
print('path(1->6): {}'.format(path[6]))
return minDis
inf = float('inf')
matrix = [[0, 1, 12, inf, inf, inf],
[inf, 0, 9, 3, inf, inf],
[inf, inf, 0, inf, 5, inf],
[inf, inf, 4, 0, 13, 15],
[inf, inf, inf ,inf, 0, 4],
[inf, inf, inf, inf ,inf, 0]]
keyPoint = demo(matrix)
# minDis=[0, 1, 8, 4, 13, 17]
# path(1->6): [1, 2, 4, 3, 5]
2020-Tan
HJ82 将真分数分解为埃及分数
算法:
核心思想为贪心算法
输入为a/b,a为分子,b为分母
1)用b除以a,得到商q=b//a + 1,+1表示向上取整,得到余数mod=b%a。将得到的商q作为分解出来的埃及分数的分母,即第一个分解的埃及分数为1/q
2)在原始的分数a/b上减去分解出来的埃及分数1/q,来更新剩下的分数值a/b=(a-mod)/(b*q)
3)如果分子变为了1,或者b能整除a,这个时候就跳出循环,否者继续重复1、2步骤
4)跳出循环后,最后如果是分子变为了1,则添加上1/b;如果最后是b能整除a,则添加上1/(b//a)
为了加速,在第3步那里出了判断a是否等于1,或者b是否能整除a,还可以加一个判断,即判断a是否等于3同时b能被2整除,这时可直接分解为1/(b//2)+1/b
Python源码
while True:
try:
strInput = input()
a, b = map(int, strInput.split('/'))
res = []
while a != 1 and b % a != 0:
q = b // a + 1
mod = b % a
res.append('1/'+str(q))
a -= mod
b *= q
if a == 1:
res.append('1/'+str(b))
else:
res.append('1/'+str(b//a))
print('+'.join(res))
except:
break
快速代码
while True:
try:
strInput = input()
a, b = map(int, strInput.split('/'))
res = []
while True:
if a == 1:
res.append('1/'+str(b))
break
elif b % a == 0:
res.append('1/'+str(b//a))
break
elif a == 3 and b % 2 == 0:
res.append('1/'+str(b//2))
res.append('1/'+str(b))
break
else:
q = b // a + 1
a -= b % a
b *= q
res.append('1/'+str(q))
print('+'.join(res))
except:
break
也可以用递归实现
def convert(a, b):
if a == 1:
print('1/%d' % b)
elif b % a == 0:
print('1/%d' % (b//a))
elif a == 3 and b % 2== 0:
print('1/%d+1/%d' % (b//2, b))
else:
q = b // a + 1
print('1/%d' % q, end='+')
a -= b % a
b *= q
convert(a, b)
while True:
try:
strInput = input()
a, b = map(int, strInput.split('/'))
convert(a, b)
except:
break
款项统计
采购团队的负责人正在进行信息统计,数组arr中存放了该采购团队本月的支出款项。负责人需要找出每个数据(arr[])之前(不包含该数据)小于等于它的款项,计算出这些数据的和。
请你帮他设计一个高效算法统计出它们的总和。求和时需要取模1e9+7(1000000007),如:如果计算初
数组arr的长度大于等于1,不超过50000,每一笔款项都为大于等于1的整数,且不超过20000。始结果为:1000000008,请返回1。
输入:1 3 5 2 4 6,输出:27
算法分析:
感觉这题应该是优化算法的,但我的确还没想出来
目前想到的就是暴力求解了
1)遍历整个数组
2)再遍历当前元素的前面所有元素
3)找到前面所有小于等于当前元素的元素,并加到res里面去
4)取模
Python源码
nums = list(map(int, input().split(' ')))
res = 0
for i in range(len(nums)):
for j in range(i):
if nums[j] <= nums[i]:
res += nums[j]
out = res % 1000000007
print(out)
线性方程组求解
给出实数矩阵A,实数向量b,且矩阵A的列数与向量b的行数相等,求使得Ax-b的模最小的列向量x
输出结果仅保留整数部分,小数部分四舍五入
输入:[1,0;0,1] (换行) [2;3],输出:
算法分析:
常见迭代解法:
雅可比迭代法
高斯-赛德尔迭代法
SOR迭代法
这里有一点值得一提的是:
高斯-赛德尔迭代法与雅可比迭代法的区别在于:
1)雅可比迭代法是,根据x之前的值统一更新所有的值
2)高斯-赛德尔迭代法是,对于已经更新的元素,拿到下一个元素的更新等式中,而不是所有元素都用上一次的值。这样可以加速迭代过程
基于python实现的Jacobi迭代法和Gauss-Seidel迭代法
解线性方程组的迭代法 Python实现
Python 线性方程组求解的雅可比迭代法/高斯-赛德尔迭代法
python迭代法求解方程_Python求解线性方程组实例
Python源码
numpy linalg中solve的解法
import numpy as np
A = np.asarray(A)
B = np.asarray(B).T
x_cur = np.linalg.solve(A, B)
res = []
for x in x_cur:
res.append(str(round(x)))
print('['+';'.join(res)+']')
Jacobi迭代求解
strA = input()[1:-1].split(';')
A = []
for v in strA:
A.append(list(map(int, v.split(','))))
B = list(map(int, input()[1:-1].split(';')))
# Jacobi求解
x_pre = [0] * len(A[0])
x_cur = [0] * len(A[0])
error = 0.1
while True:
min_error = 0
for i in range(len(B)):
sum_row = 0
# 在当前x的值下,计算等号前面等式的结果
for j in range(len(A[0])):
sum_row += A[i][j] * x_pre[j]
# 核心公式!!!更新x的值
x_cur[i] = x_pre[i] + ((B[i] - sum_row)) / A[i][i]
# 计算误差
min_error = min(min_error, abs(x_cur[i] - x_pre[i]))
# 当最小的误差都满足条件时,就跳出循环
if min_error < error:
break
# 更新x_pre的值
x_pre = x_cur
res = []
for x in x_cur:
res.append(str(round(x)))
print('['+';'.join(res)+']')
超过当天温度
最近温度下降的有点厉害,大家都希望温度能有所回升,为了了解近段时间的天气情况,小明特地查看了下最近每天的温度,请帮小明算出基于某一天开始,一共需要几天气温才能超过当天的温度,如果温度一直都没有升高,说明那天后温度都低于当前温度。则需要0天温度才能超过当前温度。
输入描述:
1、输入一个整形数组,数组中每元素的值在[-10,40]之间
2、假设某几天的问题依次为1 3 4 6 1 4 2 8
3、两个整数之间用空格间隔
4、输入和输出格式参见样例
输出描述:
1、输出数组,数组中每个值当前索引日期需要多少天温度才能超过索引对应日期的温度
2、对应输出为1 1 1 4 1 2 1 0
3、第一天温度为1,第二天温度3,大于1,只需一天温度就可以超过第一天
4、第二天温度为3,第三天温度为4,大于3,只需一天温度就可以超过第二天
…
5、第四天温度为6,第五天温度为1,小于6,第六天温度为4,小于6,第七天温度为2,小于6,第八天温度为8,大于6,因此需要4天温度才能超过第四天
…
6、第八天温度为8,后面已经没有了,因此需要0天
测试例子:
输入:1 3 4 6 1 4 2 8,输出:1 1 1 4 1 2 1 0
算法分析
第一想法还是暴力求解。。
1)遍历所有元素
2)再遍历当前元素的后面元素
3)找到第一个大于当前元素的值,计算两者之间的距离,存放到res中;如果一直没找到就存放0
(华为的这道压轴题让我简单得不敢相信。。是我想多了还是我想少了?)
Python源码
temperature = list(map(int, input().split(' ')))
res = []
for i in range(len(temperature)-1):
for j in range(i+1, len(temperature)):
if temperature[j] > temperature[i]:
res.append(str(j-i))
break
if j == len(temperature) - 1:
res.append(str(0))
res.append(str(0))
print(' '.join(res))
2019-Long
8倍字符串
连续输入字符串(输入字符串个数为N,每个字符串长度不大于100, 输入字符串间按照空格键分隔),请按长度为8拆分每个字符串后输出到新的字符串数组,输出的字符串按照升序排列。
长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
输入内容:2 abc 123456789
输入说明:输入2个字符串(以空格分隔),其中一个为abc,另一个是123456789
输出结果: 12345678 90000000 abc00000
输出说明:字符串abc需要在后边补零,123456789拆分为12345678与90000000,所有的字符串升序输出(空格分隔)。
比较简单,不做分析
Python源码
inputList = input().split(' ')[1:]
res = []
for strT in inputList:
if len(strT) <= 8:
res.append(strT+'0'*(8-len(strT)))
else:
while len(strT) > 8:
res.append(strT[:8])
strT = strT[8:]
if len(strT) > 0:
res.append(strT+'0'*(8-len(strT)))
res.sort()
print(' '.join(res))
字符串展开
给定一个字符串,字符串包含数字、大小写字母以及括号(包括大括号、中括号和小括号),括号可以嵌套,即括号里面可以出现数字和括号。按照如下的规则对字符串进行展开,不需要考虑括号成对不匹配问题,用例保证括号匹配,同时用例保证每个数字后面都有括号,不用考虑数字后面没有括号的这种情况,即2a2(b)这种情况不用考虑。
1)数字表示括号里的字符串重复的次数,展开后的字符串不包含括号。
2)将字符串进行逆序展开。
输出最终展开的字符串。
输入内容:abc3(A),输出结果:AAAcba
算法分析参考:
各大厂面试算法真题之重复字符的速记方式
Python源码
strInput = input()
stack = []
repeat_times = []
pairs = {
')': '(', ']': '[', '}': '{'}
for i in range(len(strInput)):
# 如果是数字就将其记录到重复次数repeat_times栈中
if strInput[i].isdigit():
repeat_times.append(int(strInput[i]))
# 如果是右边括号,则需要展开括号里面的内容
elif strInput[i] in pairs:
val = stack.pop()
temp_stack = []
# 取出最近的一次重复内容temp_stack
while val != pairs[strInput[i]]:
temp_stack.append(val)
val = stack.pop()
# 取出最近的一次重复次数temp_times
temp_times = repeat_times.pop()
# 根据重复次数将重复的内容再次压入stack栈中
for t in range(temp_times):
for v in range(len(temp_stack)-1, -1, -1):
stack.append(temp_stack[v])
# 如果是其他字符,则依次压入stack栈中
else:
stack.append(strInput[i])
print(''.join(stack[::-1]))
破解加密密码
小王的保险箱密码是一个升序排列的数字串。但是小王总是记不住他的密码,于是小王将他的密码加密后保存在了一个文本文件里,加密的流程如下:
1、用数字的英文单词来代替数字本身。比如134699变成onethreefoursixninenine
2、将上诉字符串使用“小王加密算法”进行处理。该算法会按照某种规则来改变原字符串字符的排列顺序,同时还会改变某此字母的大小写。比如onethreefoursixninenine经过加密后就变成了 NeNohuiroNNiNeteefersix
由于“小王加密算法”是小王自己设计的,所以小王认为只有他自己能将加密后的字符串还原。
实际上小王的加密算法存在漏洞。即使不知道“小王加密算法”的具体实现细节,也是可以还原出原始的密码的。请你写一段程序来破解小王的密码。
输入:ONEthrEEfoursixNiNENiEN,输出:134699
算法分析
先看一眼数字0到9的英文字母
0: zero
1: one
2: two
3: three
4: four
5: five
6: six
7: seven
8: eight
9: nine
其实这道题就是一个找规律题
1)首先我们会发现有几个数字带有特殊的字母,换句话说,给你这个字母就一定是数字几,我们去找找满足这个条件的有哪几个数字。有0 (Zero), 2 (tWo), 4 (foUr), 6 (siX), 8 (eiGht)。可以发现:
有Z就一定有0
有W就一定有2
有U就一定有4
有X就一定有6
有G就一定有8
发现没有,全是偶数!我不知道这是不是英语数字中巧合。。
2)去掉0,2,4,6,8后,还剩数字1 (one), 3 (three), 5 (five), 7 (seven), 9 (nine)
全剩奇数
在奇数里面我们可以发现:
有O就一定有1
有T就一定有3
有F就一定有5
有S就一定有7
3)9比较惨,去掉上面全部字母后,如果最后还剩字母那就只能是9了
Python源码
strInput = input().lower()
# 记录下第一批拥有特殊字母的数字
special1 = {
'z': '0', 'w': '2', 'u': '4', 'x': '6', 'g': '8'}
# 记录下第二批拥有特殊字母的数字
special2 = {
'o': '1', 't':'3', 'f': '5', 's': '7'}
# 数字和英文字母之间的对应关系
number2alpha = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
'5': 'five',
'6': 'six',
'7': 'seven',
'8': 'eight',
'9': 'nine'}
# 遍历整个输入str,将其存入一个字典里面,记录每个字母出现的次数
strDict = dict()
for s in strInput:
if s in strDict: strDict[s] += 1
else: strDict[s] = 1
res = []
special = [special1, special2]
# 先遍历第一批特殊字母,然后第二批
for sp in special:
# 遍历特殊字母
for keyStr, keyNum in sp.items():
while True:
# 如果输入字符串strDict中存在特殊字母
if keyStr in strDict:
# 记录下对应的数字
res.append(keyNum)
# 移除对应数字的所有字母
numStr = list(number2alpha[keyNum])
for k in numStr:
strDict[k] -= 1
# 如果遇见次数为0的字母,则从strDict中移除
if strDict[k] == 0: del strDict[k]
# 如果不存在,则跳出循环
else: break
# 如果此时strDict还不为空,那剩的一定就是数字9了
if strDict:
# 统计一下会有几个9
times = strDict['e'] # 看字母i或者e都行,唯独不能看n,看的话记得除以2~~
for t in range(times):
res.append('9')
del strDict
# 升序的密码
res.sort()
print(''.join(res))