先從簡單的題型開始刷起,一起加油啊!!
點個關注和收藏唄,一起刷題鴨!!
第一批題目
1.設備編號
給定一個設備編號區間[start, end],包含4
或18
的編號都不能使用,如:418、148、718不能使用,108可用。請問有多少可用設備編號。
class Solution:def get_normal_device_number(self, start, end):count = 0for i in range(start, end+1):if ('4' in str(i) or '18' in str(i)):continueelse:count += 1return countif __name__ == "__main__":start, end = tuple(map(int, input().strip().split()))function = Solution()result = function.get_normal_device_number(start, end)print(result)
2.服務器集群網絡延時
給定一個正整數數組表示某服務器集群內服務器的機位編號,請選擇一臺服務器作為主服務器,使得集群網絡延遲最小,并返回該最小值。
- 每臺服務器有唯一的機位編號。
- 兩服務器之間的網絡延遲,可以簡單用所在機位編號之差的絕對值表示;服務器到自身的延遲為0。
- 集群網絡延遲是指主服務器與所有服務器的網絡延遲之和。
class Solution:def cluster_latency(self, arr):res = 0mid = len(arr) // 2arr.sort()for num in arr:res += abs(num - arr[mid])return resif __name__ == "__main__":num = input().strip()arr = list(map(int, input().strip().split()))function = Solution()results = function.cluster_latency(arr)print(results)
3.給定差值的組合
給定一個數組,每個元素的值是唯一的,找出其中兩個元素相減等于給定差值 diff 的所有不同組合的個數。
輸入三行:
第一行為一個整數,表示給定差值diff;范圍[-50000, 50000]
第二行也為一個數字,表示數組的長度;范圍[2, 102400]
第三行為該數組,由單個空格分割的一組數字組成;其中元素的值范圍[-20, 102400]
用例保證第三行數字和空格組成的字符串長度不超過 649999
輸出
1個整數,表示滿足要求的不同組合的個數
樣例
輸入樣例 1?
3 5 1 3 2 5 4
輸出樣例 1
2
提示樣例 1
數組為[1 3 2 5 4], 差值 diff 為 3,其中 4 - 1 = 3,5 - 2 = 3,共 2 個組合滿足條件,因此輸出 2
class Solution:def proc(self, arr, diff):# 在此添加你的代碼if diff == 0:return 0arr_set = set(arr)diff_set = set(ele + diff for ele in arr_set)cross_set = arr_set & diff_setreturn len(cross_set)
if __name__ == "__main__":diff = int(input().strip())count = int(input().strip())arr = list(map(int, input().strip().split(' ')))function = Solution()result = function.proc(arr, diff)print(result)
左右指針算法:
class Solution:def __init__(self):self.count, self.left, self.right = 0, 0, 0# 左右指針算法def proc(self, nums, d):# 差值為0,直接返回0if d == 0:return self.count# 升序排序nums.sort()while self.right < len(nums) and self.left < len(nums):# 當右值左值差大于diff時,左指針加一if nums[self.right] - nums[self.left] > d:self.left += 1continue# 當右值左值差等于diff時,左指針加一,右指針加一,結果加一elif nums[self.right] - nums[self.left] == d:self.left += 1self.right += 1self.count += 1# 當右值左值差小于diff時,右指針加一else:self.right += 1return self.count
集合交集算法:
class Solution:def __init__(self):self.count = 0def proc_set(self, nums, d):if d == 0:return self.countnums_set = set(nums)diff_set = set(i - d for i in nums_set)return len(nums_set & diff_set)
好厲害的算法啊!執行時間也很短
第七批題目
1.IP報文頭解析
一個IP報文頭及所包含的各信息的關系如圖所示:
- 圖中從上到下、從左到右依次表示各信息在IP報文頭中的順序。
- 各信息括號內的數字表示所占位數,如:標識(16),表示標識部分占16個bit位即2個字節長度。
現給定一個十六進制格式的IP報文頭數據,請解析輸出其中的總長度、標志、目的IP地址:
- 總長度、標志為十進制整數
- 目的IP地址為點分十進制格式,如:192.168.20.184
輸入樣例 1?
45 00 10 3c 7c 48 20 03 80 06 00 00 c0 a8 01 02 c0 a8 14 b8
輸出樣例 1
4156,1,192.168.20.184
對照圖示的各信息所在位置:
總長度 :0x103c,十進制值為 4156
標 志 :0x20的二進制為 00100000,其中的高 3 位為標志,二進制為 001,10進制值為 1
目的IP地址:0xc0a814b8,點分十進制為 192.168.20.184
(內心:簡單題的題目怎么這么復雜?????看都看不懂)
前置知識:每個十六進制(0x)數字對應4位二進制數。
from typing import List
class Solution:def get_ip_info(self, datas: str) -> str:# 1.先按空格切割data_lst = datas.split()# 2.提取長度字段,16進制轉為10進制,最終轉為字符串length_str = str(int("0x" + "".join(data_lst[2:4]), 16))# 3.提取標志字段,16進制轉10進制,再轉2進制(注意zfill補齊前置0),再轉10進制,最終轉為字符串flag_str = str(int(bin(int("0x" + "".join(data_lst[6]), 16))[2:].zfill(8)[:3], 2))# 4.最后四位轉為點分10進制,最終轉為字符串ip_str = ".".join([str(int("0x" + x, 16)) for x in data_lst[-4:]])return length_str + "," + flag_str + "," + ip_str
if __name__ == "__main__":data = input().strip()function = Solution()results = function.get_ip_info(data)print(results)
length_str = str(int("0x" + "".join(data_lst[2:4]), 16)) ,將十六進制表示的一段數據轉換為十進制表示的字符串。我們可以一步步地解讀它:
1. `data_lst[2:4]`:這是一個列表切片操作,從列表 `data_lst` 中提取索引2和3的兩個元素。這些元素應該是以字符串形式表示的十六進制數。
2. `"".join(data_lst[2:4])`:這個操作將步驟1中提取的元素連接成一個字符串。例如,如果 `data_lst[2]` 是 `'10'`,`data_lst[3]` 是 `'3c'`,那么結果將是 `'103c'`。
3. `"0x" + "".join(data_lst[2:4])`:在連接好的字符串前面加上 `'0x'`,使其成為一個合法的十六進制字符串表示。例如,如果結果是 `'103c'`,那么現在它變成 `'0x103c'`。
4. `int("0x" + "".join(data_lst[2:4]), 16)`:將這個十六進制字符串轉換為一個十進制的整數。`int` 函數的第一個參數是要轉換的字符串,第二個參數 `16` 表示輸入是一個十六進制數。例如,`'0x103c'` 會被轉換成十進制的 `4156`。
5. `str(int("0x" + "".join(data_lst[2:4]), 16))`:將上述得到的十進制整數轉換為字符串。例如,`4156` 會被轉換成 `'4156'`。
舉例說明:
假設 `data_lst = ["45", "00", "10", "3c", "7c", "48", "20", "03", "80", "06", "00", "00", "c0", "a8", "01", "02", "c0", "a8", "14", "b8"]`,那么:
- `data_lst[2:4]` 提取的子列表是 `["10", "3c"]`。
- `"".join(data_lst[2:4])` 結果是 `'103c'`。
- `"0x" + "".join(data_lst[2:4])` 結果是 `'0x103c'`。
- `int("0x103c", 16)` 結果是 `4156`。
- `str(4156)` 結果是 `'4156'`。
flag_str = str(int(bin(int("0x" + "".join(data_lst[6]), 16))[2:].zfill(8)[:3], 2))? 代碼詳細解讀
進制轉化:16→10→2→10
1.int("0x" + "".join(data_lst[6]), 16),16進制轉化成十進制,int("0x20", 16)
結果是 32?
2.使用 bin
函數將十進制整數轉換為二進制字符串,結果是"0b100000"
3.[2:]?去掉前綴 "0b"
4.zfill(8)
方法將二進制字符串填充到 8 位長度
5.[:3]? 使用切片操作提取二進制字符串的高 3 位?對于 "00100000"
,結果是 "001"
6.
使用 int
函數將二進制字符串 "001"
轉換為十進制整數
ip_str = ".".join([str(int("0x" + x, 16)) for x in data_lst[-4:]]) 解讀
- 對于每個元素
x
,首先使用"0x" + x
將其轉換為十六進制字符串,例如"c0"
變為"0xC0"
。 - 使用
int("0x" + x, 16)
將十六進制字符串轉換為十進制整數,例如int("0xC0", 16)
結果是192
。
注意A.join(B)? ?A 和 B 都是字符串類型
int(A,B)? ?A是字符串類型,返回的是整數類型
2.可漫游服務區
漫游(roaming)是一種移動電話業務,指移動終端離開自己注冊登記的服務區,移動到另一服務區(地區或國家)后,移動通信系統仍可向其提供服務的功能。
用戶可簽約漫游限制服務,設定一些限制區域,在限制區域內將關閉漫游服務。
現給出漫游限制區域的前綴范圍,以及一批服務區(每個服務區由一個數字字符串標識),請判斷用戶可以漫游的服務區,并以字典序降序輸出;如果沒有可以漫游的服務區,則輸出字符串empty
。
輸入
首行輸入兩個整數m n
,取值范圍均為 [1, 1000]。
隨后 m 行是用戶簽約的漫游限制區域的前綴范圍,每行格式為start end
(含start和end),start和end是長度相同的數字字符串,長度范圍為[1, 6],且 start <= end。
接下來 n 行是服務區列表,每行一個數字字符串表示一個服務區,長度范圍為[6,15]。
輸出
字典序降序排列的可漫游服務區列表,或字符串empty
輸入樣例 1?
2 4 755 769 398 399 3970001 756000000000002 600032 755100
輸出樣例 1
600032 3970001
提示樣例 1
服務區 755100 和 756000000000002 的前綴在漫游限制 [755,769] 范圍內,不能漫游。 3970001 和 600032,不在任何漫游限制范圍內,因此可以漫游,按字典序降序先輸出 600032。
方法一:
prex_len = len(restricts[0][0])ranges = []for i in restricts:start = int(i[0])end = int(i[-1])for j in range(start, end+1):ranges.append(j)res = []for j in areas:if int(j[:prex_len]) not in ranges:res.append(j)res.sort(reverse=True)if not res:print("empty") return res
方法二:
def get_roaming_area(self, restricts: List[List[str]], areas: List[str]) -> List[str]:un_limit = []# 備份for j in areas:un_limit.append(j)# 在范圍內就刪除for k in areas:for i, j in restricts:if int(i) <= int(k[0:len(i)]) <= int(j):un_limit.remove(k)# 輸出結果if not un_limit:un_limit = ['empty']else:un_limit = sorted(un_limit, reverse=True)return un_limit
# 定義測試樣例
restricts_num, areas_num = 2, 4
restricts = [["755", "769"], ["398", "399"]]
areas = ["3970001", "756000000000002", "600032", "755100"]
-
for k in areas:
- 這個循環遍歷
areas
列表中的每一個元素,k
代表areas
中的一個區域。
- 這個循環遍歷
-
for i, j in restricts:
- 這個內層循環遍歷
restricts
列表中的每一個限制條件,i
和j
分別代表每個限制條件中的兩個值。 restricts
是一個包含成對限制條件的列表,每對由兩個字符串(i
和j
)組成,表示一個范圍。
- 這個內層循環遍歷
-
if int(i) <= int(k[0:len(i)]) <= int(j):
- 這一行檢查當前區域
k
是否在當前限制條件i
和j
之間。 int(i)
和int(j)
將限制條件i
和j
轉換為整數。k[0:len(i)]
提取區域k
的前len(i)
個字符并轉換為整數。這是因為i
和j
的長度可能不同,代碼需要根據i
的長度來提取并比較k
的相應部分。- 如果提取的部分在
i
和j
之間(包括邊界),條件為真。
- 這一行檢查當前區域
-
如果條件為真,從un_limit.remove(k)
un_limit
列表中移除區域k
,表示該區域k
符合當前的限制條件,不再屬于不受限制的區域。
3.信號解碼
無線基站接收到手機上報的某種信息(例如11@2$3@14
)后,需要先進行解碼操作,再計算結果。假定每條信息中都至少包含特殊運算符?@
?和?$
?的一種,解碼規則如下:
x@y = 2*x+y+3
x$y = 3*x+2*y+1
- x、y 都是非負整數 ;
- @ 的優先級高于 $ ;
- 相同的特殊運算符,按從左到右的順序計算。
11@2$3@14
= (2*11+2+3)$3@14
= 27$3@14
= 27$(2*3+14+3)
= 27$23
= 3*27+2*23+1
= 128
現給定一個字符串,代表一個手機上報的待解碼信息,請按照解碼規則進行解碼和計算,并返回計算結果。
import re
class Solution:def get_calc_result(self, information: str) -> int:# 這一步把輸入拆成數字和符號存入字符串,如11@2$3@14 -> ['11', '@', '2', '$', '3', '@', '14']ex = re.split(r"(\D)", information) pos = 0 #用于保存符號的位置sign = '' #用于記錄符號#核心邏輯:邊計算,便刪除ex表達式中元素,直到只剩一個值即為結果while len(ex)!=1:#如果還存在@則sign記錄為@,pos記錄為@在ex中的位置;否則記錄$信息(實現@優先于$)(sign, pos) = ('@', ex.index('@')) if '@' in ex else ('$', ex.index('$'))ex[pos-1] = self.cal(sign, int(ex[pos-1]), int(ex[pos+1]))del ex[pos:pos+2]return ex[0]def cal(self, sign, x, y):if sign == '@': return 2*x+y+3else: return 3*x+2*y+1
if __name__ == "__main__":information = str(input().strip())function = Solution()results = function.get_calc_result(information)print(results)
1. `re.split(r"(\D)", information)`
- 使用正則表達式 `(\D)` 將 `information` 按非數字字符拆分成一個列表。括號 `()` 表示捕獲分組,因而分隔符本身也會包含在結果列表中。例如,字符串 `11@2$3@14` 將被拆分成 `['11', '@', '2', '$', '3', '@', '14']`。
import restring = "a1b2c3d4"
# 使用捕獲組 (\D) 來分割字符串
result = re.split(r"(\D)", string)
print(result)#輸出
['', 'a', '1', 'b', '2', 'c', '3', 'd', '4', '']
import restring = "a1b2c3d4"
# 使用正則表達式 \D 來分割字符串,\D 表示非數字字符
result = re.split(r"\D", string)
print(result)#輸出
['', '1', '2', '3', '4']
2. `pos = 0` 和 `sign = ''`
- 初始化變量 `pos` 和 `sign`,分別用于保存符號的位置和記錄當前符號。
3. **`while len(ex) != 1:`**
- 這個循環會持續運行,直到 `ex` 列表中只剩下一個元素,即最終計算結果。
4. `(sign, pos) = ('@', ex.index('@')) if '@' in ex else ('$', ex.index('$'))`
- 這行代碼檢查 `ex` 列表中是否包含 `@` 符號。如果包含,則 `sign` 設為 `@`,`pos` 設為 `@` 在 `ex` 中的位置。如果不包含 `@`,則檢查并設置 `$` 符號的信息。這樣確保 `@` 的優先級高于 `$`。
A if condition else B
condition
是條件,如果條件為真,表達式返回A
;否則返回B
。如果條件為真,返回一個元組
('@', ex.index('@'))
。
sign
被賦值為'@'
pos
被賦值為ex.index('@')
,即'@'
在ex
列表中的索引位置。如果條件為假(即
ex
列表中不包含字符'@'
),返回一個元組('$', ex.index('$'))
。這里:
sign
被賦值為'$'
pos
被賦值為ex.index('$')
,即'$'
在ex
列表中的索引位置。
5.ex[pos-1] = self.cal(sign, int(ex[pos-1]), int(ex[pos+1]))
- 調用 `cal` 方法,傳入符號 `sign` 以及符號前后的數字,進行計算,并將計算結果賦值給符號前面的數字位置。
6. **`del ex[pos:pos+2]`**
- 刪除符號和符號后面的數字,使得 `ex` 列表長度減少。舉例來說,`['11', '@', '2', '$', '3', '@', '14']` 將變為 `['結果', '$', '3', '@', '14']`。
7. **`return ex[0]`**
- 當 `while` 循環結束時,`ex` 列表中只剩下一個元素,即最終計算結果,將其返回。
假設輸入 `information = "11@2$3@14"`:
1. 初始分割為 `['11', '@', '2', '$', '3', '@', '14']`。
2. 首先處理 `@` 操作符:
- `11@2` 計算結果為 `2*11 + 2 + 3 = 27`,列表變為 `['27', '$', '3', '@', '14']`。
3. 繼續處理 `@` 操作符:
- `3@14` 計算結果為 `2*3 + 14 + 3 = 23`,列表變為 `['27', '$', '23']`。
4. 最后處理 `$` 操作符:
- `27$23` 計算結果為 `3*27 + 2*23 + 1 = 154`,列表變為 `['154']`。
5. 返回 `154` 作為最終結果。
?
方法二:
#$的優先級低,直接分割,先把@計算完后,再單獨計算$lst_info = information.split("$")#判斷list中每個元素,沒有@則跳過,有@計算for i in range(len(lst_info)):#每個再按@拆if '@' in lst_info[i]:lst1 = lst_info[i].split("@")lst2 = [int(j) for j in lst1]#按棧的方式計算lst2.append(lst2[0])for j in range(1,len(lst2)-1):lst2.append(lst2.pop(-1)*2 +lst2[j]+3)#最后只保留算出來的結果lst_info[i] =lst2[-1]lst_fianl = [int(i) for i in lst_info]#計算$,原理和上面相同lst_fianl.append(lst_fianl[0])for j in range(1, len(lst_fianl) - 1):lst_fianl.append(lst_fianl.pop(-1) * 3 + lst_fianl[j]*2 + 1)return lst_fianl[-1]
4.比特翻轉
工程師小A在對二進制碼流 bits 進行驗證,驗證方法為:給定目標值 target(0 或 1),最多可以反轉二進制碼流 bits 中的一位,來獲取最大連續 target的個數,請返回該個數。
解答要求時間限制:1000ms, 內存限制:256MB
輸入
第一行為 target,取值僅為 0 或 1;
第二行為 bits 的長度 length,取值范圍 [1, 10000];
第三行為 bits 數組的元素,只包含 0 或 1 。
輸出
一個整數,表示最大連續 target 的個數
樣例
輸入樣例 1?
1 9 0 1 1 0 1 0 1 0 0
輸出樣例 1
4
提示樣例 1
0 1 1?0
?1 0 1 0 0
目標值為1,表示需要獲取最大連續1的個數。
將第二個出現的0反轉為1,得到0 1 1 1 1 0 1 0 0 ,獲得 4 個連續的1;
其它反轉獲得連續1的個數最大為3,如 1 1 1 0 1 0 1 0 0 或 0 1 1 0 1 1 1 0 0 。
輸入樣例 2?
0 8 0 0 0 0 0 0 0 0
輸出樣例 2
8
提示樣例 2
不需要反轉即可獲得最大連續0,個數為8
滑動窗口的解法:
def find_max_consecutive_bits(self, target: int, bits: List[int]) -> int:left, right = 0, 1res = 0while right <= len(bits):if bits[left:right].count(1 - target) <= 1:res = max(res, right - left)right += 1else:left += 1return res
if bits[left:right].count(1 - target) <= 1:
計算當前子數組 bits[left:right]
中不同于 target
的位數(即 1 - target
的位數)。如果不同于 target
的位數不超過 1,則當前子數組符合條件。
更新 res
為當前子數組的長度與之前最大長度中的較大者。
將 right
指針右移一位,擴展子數組范圍。
def main():target, length, bits = int(input().strip()), int(input().strip()), [*map(int, input().strip().split())]count1 = count2 = max_length = 0 # count2計算前一段連續target的個數 + 1, count1計算當前連續target的個數for i in range(length):if bits[i] == target:count1 += 1continuemax_length = max(max_length, count2 + count1)count2 = count1 + 1count1 = 0max_length = max(max_length, count2 + count1)print(max_length)
if __name__ == "__main__":main()
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,第一批和第七批的題目比起來還真的不是同一個難度啊
加油啊!!祝我好運
引用的代碼就不一一注釋原處了,作者介意的請聯系我加上