天天看點

華為2021屆軟體測試筆試題,華為2021屆軟體類校園招聘筆試題題解

第一題很簡單,忘了是什麼題了。

第二題:驗證封包

難點在于進制的轉換和輸入輸出,python對于十六進制的存儲是0x__,比如5就是0x5,而C和C++就是5,這裡稍有不同,當時我摸不清python版本的輸入格式到底是什麼,因為python隻能用readline()的形式直接從指令行得到整條輸入,再進行解析,這裡就糾結到底是0x5還是5,想的腦子疼,(筆試結束後朋友提醒牛客網好像可以輸出樣例輸入),就沒寫這道題。

題目:封包流T由封包組成,每個封包以十六進制存儲,開始符是5a,結束符也是5a,在結束符之前,用一個位元組來存儲封包長度域(不包含開始、結束以及長度域本身),封包内如果遇到5a,5b兩種字元,轉義成5b ba和5b bb,但長度不變。兩個封包合并時,可以将中間的5a省去一個,用一個5a同時作為上一個封包的結束符和目前封包的開始符。

例如5a 06 5b ba 37 5b bb 44 05 5a 12 34 5b ba 03 5a封包流由兩個封包組成

1:5a 06 5a 37 5b 44 05 5a

2:5a 12 34 5b 03 5a

問題:現在有一個封包流,裡面有部分封包是錯誤的,(可能是沒轉義,可能是長度域錯誤等),需要剔除錯誤的封包,并傳回剩餘正确的封包流。

思路:

一:一個十六進制占1個位元組,先将輸入的十六進制資料流轉為整數存在數組裡(考察輸入)

二:周遊,将兩個5a之間的數組放進子函數,子函數計算這個數組的長度(注意将轉義字元看做一個位元組),跟長度域比較,不相等就不管,相等就放入結果數組裡,

三:将結果數組按照十六進制輸出即可。(這裡注意結果要補0,5要輸出成05,用print('02x'%input)即可)

挺可惜,我當時被輸入輸出整的有點煩,也是因為LeetCode并不需要處理輸入輸出,是以平時練得實在不多。

第三題:最優子序列

題目:現有一個序列長度為m,我們要将其分解成k個子序列,1<=k<=m<=500,序列由整數組成,整數小于10^7。要求這k個子序列和的最小值盡可能大,在有多解的情況下,優先s(1)序列最大,如果s(1)相同,則s(i+1)依次往下排。

例如:

100 200 300 400 500 600 700 800 900

k=3的情況

我們需要輸出: 100 200 300 400 500 / 600 700 / 800 900

這樣的劃分是最優的,最小值600+700=1300是能劃分的最大值

思路:

這裡很重要的是我們需要找出那個最優的最小值來劃分序列。查找自然就要用二分查找法啦,令X為我們要找的劃分值,那麼我們需要用二分來找X。二分查找自然需要low和high,這裡low=0無疑問,數組和最大值為500*10^7,是以high就是5e9。

那麼如何判定一次二分之後mid該往哪邊去呢?

試想,我們建構一個函數f,使得x能劃分時,f(x)=1,不能劃分時f(x)=0,那麼我們需要找的X正好就是這個函數定義域的分界點,任何xX使得f(x)=0,是以mid往哪邊走,由函數f傳回值來确定。

接下來建構函數f。首先,我們根據x來劃分序列,每個子序列必須要大于x。f(x)=0時,也就是x太大,最後劃出來區域數量小于k。f(x)=1,則x存在,可以劃分出k個區域(并不保證最優,但保證存在)

上代碼

def make_parts(a,k,x):

parts=[]

num_part=0

i=len(a)-1

#從後往前周遊,目的是保證前面的子序列和能更大

while i>=0:

tmp_sum=0

part=[]

j=i

#劃分子區域

while j>=0 and tmp_sum=0:

part.append(a[i])

i-=1

parts.append(part)

#x偏大,不能劃分k個區域

if num_part

子函數建構完成,外面套個二分查找即可,查找到最優值X後,再用子函數分一次X就是答案。