2020 年最全 Python 面试题汇总 (四)
@Author:Runsen
文章目錄
- 前言
- 61、01背包
- 62、完全背包
- 63、多重背包
- 64、多重背包的二進制
- 65、混合背包
- 66、Vivio面試真題
- 67、二維費用的背包問題
- 68、買賣股票的最佳時機(買一次)
- 69、買賣股票的最佳時機(買N次)
- 70、買賣股票的最佳時機(買2次)
- 71、買賣股票的最佳時機(買k次)
- 72、買賣股票的最佳時機(買N次加CD冷卻時間)
- 73、買賣股票的最佳時機(買N次加手續費)
- 74、冒泡排序
- 75、插入排序
- 76、選擇排序
- 77、希爾排序
- 78、歸并排序
- 79、快速排序
- 80、查找和為定值的兩個數
前言
求職季在即,技巧千萬條,硬實力才是關鍵,聽說今年疫情大環境不好,更要好好準備才行。于是 Runsen 在牛客網,Leetcode,九章算法,不斷地尋找面試真題,共計 100 題,包括 Python基礎、算法、SQL。
此次寫作的一個明確目標是能夠讓 90% 以上的 Python 技術面試題都能覆蓋到。更重要的目的是讓我提升硬實力,在畢業之際,拿下offer。
本次 GitChat,分享辛苦總結了100 道 Python 基本算法面試題超強匯總,基本全部來自??途W和最近的 2020 大廠的校招題目。
61、01背包
動態規劃需要搞定三個系列:分別是背包,打劫問題和股票問題。
對應的題目:https://www.acwing.com/problem/content/2/
01背包問題就是物品只有一件。
輸入格式 : 第一行兩個整數,N,V,用空格隔開,分別表示物品數量和背包容積。接下來有 N 行,每行兩個整數 vi,wi,用空格隔開,分別表示第 i 件物品的體積和價值。
輸出格式 : 輸出一個整數,表示最大價值。
數據范圍 : 0<N,V≤1000 ;0<vi,wi≤1000
輸入樣例
4 5 1 2 2 4 3 4 4 6輸出樣例:
8 # 4+4 2+6在解決這類問題先,dp怎么定義和狀態轉移方程怎么搞就是重要,搞定了就是半分鐘的事情。搞不定了可能半小時的事情。
很多人和Runsen一樣,都會把狀態定義二維數組:dp[i][v]dp[i][v]dp[i][v] 為前 iii 「個」 物品中,體積恰好為vvv 時的最大價值。
狀態轉移方程也是順便搞定:dp[i][j]=max(dp[i?1][j],dp[i?1][j?weight[i]]+value[i])dp[i][j] = max(dp[i-1][j],dp[i - 1][j - weight[i]] + value[i])dp[i][j]=max(dp[i?1][j],dp[i?1][j?weight[i]]+value[i])
如果 「不選第 i 個物品」,那么前 i 個背包的最大價值就是前 i-1 個物品的價值,即 dp[i][j] = dp[i-1][j];
如果 「選擇了第 i 個物品」,前 i-1 個物品的體積就是j - weight[i],狀態方程為 dp[i - 1][j - weight[i]] + value[i],注意這時的價值是前i-1個物品的價值,因此少了 weight[i]]的空間,所以 dp[i - 1][j - weight[i]] + value[i]。
''' @Author: Runsen @WeChat:RunsenLiu @微信公眾號: Python之王 @CSDN: https://blog.csdn.net/weixin_44510615 @Github: https://github.com/MaoliRUNsen @Date: 2020/9/10 ''' # n是個數 v是體積 # 4 5 n, v = map(int, input().split()) goods = [] for i in range(n):goods.append([int(i) for i in input().split()])# 初始化,先全部賦值為0,這樣至少體積為0或者不選任何物品的時候是滿足要求 # 因為for 循環先遍歷個數,所以將體積寫在里面 dp = [[0 for i in range(v+1)] for j in range(n+1)] print(goods) # [[1, 2], [2, 3], [3, 4], [4, 5]] # 0 可以無視掉 for i in range(1, n+1):for j in range(1,v+1):# 判斷背包容量是不是大于第i件物品的體積if j>=goods[i-1][0]:# 在選和不選的情況中選出最大值dp[i][j] = max(dp[i-1][j], dp[i - 1][j - goods[i - 1][0]] + goods[i - 1][1])else:# 第i個物品不選dp[i][j] = dp[i-1][j] print(dp[-1][-1])# 測試數據 5 10 1 2 2 3 3 4 4 5 5 614 # 2+3+4+5上面的代碼是狀態定義二維數組,可以把狀態定義一維數組,這樣空間就節省了。
一維數組就是去掉了狀態iii,且jjj的遍歷方式改為 「倒序」 遍歷到 c[i]。
因此,Runsen們可以將求解空間進行優化,將二維數組壓縮成一維數組,此時,轉移方程變為:
dp(j)=max(dp(j),dp(i?wi)+vi)dp(j) = max(dp(j),dp(i - wi) + vi)dp(j)=max(dp(j),dp(i?wi)+vi)
''' @Author: Runsen @WeChat:RunsenLiu @微信公眾號: Python之王 @CSDN: https://blog.csdn.net/weixin_44510615 @Github: https://github.com/MaoliRUNsen @Date: 2020/9/10 ''' n, v = map(int, input().split()) goods = [] for i in range(n):goods.append([int(i) for i in input().split()]) print(goods) # [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6]] dp = [0 for i in range(v + 1)] for i in range(n):# 由于要放入物品,所以從空間v開始遍歷到0for j in range(v, -1, -1):# 判斷背包容量是不是大于第i件物品的體積if j >= goods[i][0]:# 更新j的狀態,即當前容量放入物品之后的狀態dp[j] = max(dp[j], dp[j - goods[i][0]] + goods[i][1]) print(dp) print(dp[-1])62、完全背包
題目來源:https://www.acwing.com/problem/content/3
先上代碼,和01背包問題的解法有略微的改動,區別在于遍歷體積jjj時從逆序改為順序,在上一篇博客中有Runsen關于01背包問題的理解。
# 代碼基本一樣 n, v = map(int, input().split()) goods = [] for i in range(n):goods.append([int(i) for i in input().split()]) dp = [0 for i in range(v+1)] for i in range(n):for j in range(v+1): # 從前往后if j >= goods[i][0]:dp[j] = max(dp[j], dp[j-goods[i][0]]+goods[i][1]) print(dp[-1])# 測試代碼 5 10 1 2 2 3 3 4 4 5 5 6 2063、多重背包
題目來源:https://www.acwing.com/problem/content/4/
多重背包問題每件物品件數都有上限。
下面是多重背包問題的輸入樣例和輸出樣例
輸入樣例 4 5 1 2 3 # 體積、價值和數量 2 4 1 3 4 3 4 5 2 輸出樣例: 10多重背包問題的思路跟完全背包的思路非常類似,只是取值是有限制的,因為每件物品的數量是有限制的,狀態轉移方程為:dp [j] = max(dp [j], dp [j - k*b] + k*w) 這里的b和w指的是當前遍歷的體積和價值。
這里一維動態規劃和01背包基一樣,就是多了一個k的循環,具體的查看下面代碼。
n, v = map(int, input().split())dp = [0 for _ in range(v+1)]for i in range(n):b, w, s = map(int, input().split())for j in range(v, -1, -1):k = 1while k <= s and j >= k * b:dp [j] = max(dp [j], dp [j - k*b] + k*w)k += 1 print(dp[v])除了上面的方法,還有用最原始的方法,將多個同一物品轉化成不同物品,再用01背包求解
n,v = map(int, input().split()) goods = [] for i in range(n):goods.append([int(i) for i in input().split()])new_goods = []for i in range(n):for j in range(goods[i][2]):new_goods.append(goods[i][0:2])goods = new_goods n = len(goods)dp = [0 for i in range(v+1)]for i in range(n):# 01背包倒序for j in range(v,-1,-1):if j>= goods[i][0]:dp[j] = max(dp[j], dp[j - goods[i][0]] + goods[i][1]) print(dp[-1])64、多重背包的二進制
多重背包有三層循環,如果數據非常的大,那么程序就會運行很慢。有一種優化方式叫做二進制優化
二進制是一個非常神奇的進制,譬如說7這個數,分開就是1+2+4(20+21+22)1+2+4(2^0+2^1+2^2)1+2+4(20+21+22)。
進行完二進制拆分之后,這個問題就轉化成了零一背包。
下面就是一個二進制解決多重背包的示例,其中items 表示次數,體積 價值。
''' @Author: Runsen @WeChat:RunsenLiu @微信公眾號: Python之王 @CSDN: https://blog.csdn.net/weixin_44510615 @Github: https://github.com/MaoliRUNsen @Date: 2020/9/21 ''' def binary_divide(volume,price,count):divides = []for i in range(32):# 從0位開始枚舉cur = 1 << i# 如果小于枚舉值,說明已經拆分完畢了if count < cur:# 把剩下的部分打包divides.append((count, count * volume, count * price))breakelse:# 否則繼續拆分,打包1 << i個物品count -= curdivides.append((cur, cur * volume, cur * price))return divides n,v = map(int, input().split()) goods = [] for i in range(n):goods.append([int(i) for i in input().split()]) new_good = [] for i in goods:# 二進制拆分 extend 這里我用append卡了幾天。new_good.extend(binary_divide(*i)) dp = [0 for _ in range(v+1)] # 現在就是01背包 for item in new_good:i, j = item[1], item[2]for k in range(v - i, -1, -1):dp[k + i] = max(dp[k + i], dp[k] + j) print(dp[-1])4 5 1 2 3 2 4 1 3 4 3 4 5 2 1065、混合背包
混合背包問題混合了這三者。
題目來源:https://www.acwing.com/problem/content/7/
# -1 表示01背包 0表示完全背包 大于0的表示多重背包 輸入樣例 4 5 1 2 -1 2 4 1 3 4 0 4 5 2 輸出樣例: 8最簡單的方法就是直接轉化為多重背包。-1變成1,0變成V,這樣就是最簡單最高效的方法。對于多重背包問題,可以同樣采用二進制的方法。
''' @Author: Runsen @WeChat:RunsenLiu @微信公眾號: Python之王 @CSDN: https://blog.csdn.net/weixin_44510615 @Github: https://github.com/MaoliRUNsen @Date: 2020/9/27# -1 表示01背包 0表示完全背包 大于0的表示多重背包 輸入樣例 4 5 1 2 -1 2 4 1 3 4 0 4 5 2 輸出樣例: 8 ''' n, v = map(int, input().split()) dp = [0 for _ in range(v+1)] for i in range(n):b, w, s = map(int, input().split())# 這里需要判斷下sif s == -1 : s = 1if s == 0 : s = vfor j in range(v, -1, -1):k = 1while k <= s and j >= k * b:dp [j] = max(dp [j], dp [j - k*b] + k*w)k += 1 print(dp[v])66、Vivio面試真題
二維費用的背包問題。直接讓我想起了Vivo的面試題,具體鏈接
輸入:15 10 5,1,1000#2,3,3000#5,2,15000#10,4,16000
輸出:31000
說明組合部署服務5,2,15000、10,4,16000 ,可以讓單臺服務器承載最大用戶數31000
其實就是二維費用的背包問題,變湯不變藥的。
''' @Author: Runsen @WeChat:RunsenLiu @微信公眾號: Python之王 @CSDN: https://blog.csdn.net/weixin_44510615 @Github: https://github.com/MaoliRUNsen @Date: 2020/9/27輸入:15 10 5,1,1000#2,3,3000#5,2,15000#10,4,16000 輸出:31000 考點:動態規劃 '''''' Welcome to vivo ! ''' def solution(total_disk, total_memory, app_list):# 背包的二維費用問題 三維dp解決disk_sum = []memory_sum = []apps = []for i in app_list:disk_sum.append(i[0])memory_sum.append(i[1])apps.append(i[2])n = len(apps)# 狀態 三維dp dp[i][j][k] 表示第i個服務器,磁盤空間為j,內存為k的最大APP部署應用的個數# dp[i][j][k] 要么就是第i-1個服務器,磁盤空間為j,內存為k的最大APP部署應用的個數,# 要么就是第i-1個服務器,磁盤空間為j-(i-1)的空間,內存為k-(i-1)的空間的最大APP部署應用的個數(需要判斷當前j和k能不能大于i-1的狀態# 這里需要注意:為什么dp定義成n+1?dp = [[[0] * (total_memory + 1) for _ in range(total_disk + 1)] for _ in range(n + 1)]# 因為最后的一個n+1,需要取到nfor i in range(1, n + 1):for j in range(1, 1 + total_disk):for k in range(1, 1 + total_memory):# 需要判斷當前j和k能不能大于i-1的狀態if j - disk_sum[i - 1] >= 0 and k - memory_sum[i - 1] >= 0:dp[i][j][k] = max(dp[i - 1][j][k], dp[i - 1][j - disk_sum[i - 1]][k - memory_sum[i - 1]] + apps[i - 1])else:# 判罰失敗,只有一種來源dp[i][j][k] = dp[i-1][j][k]return dp[-1][-1][-1]if __name__ == "__main__":# 15 10 5,1,1000#2,3,3000#5,2,15000#10,4,16000input1 = input()disk = int(input1.split()[0])memory = int(input1.split()[1])input2 = input1.split()[2]app_list = [[int(j) for j in i.split(',')] for i in input2.split('#')]print(solution(disk, memory, app_list))# 順便更新將三維空間壓縮成二維空間的超級簡單的做法 input1 = input() A = int(input1.split()[0]) B = int(input1.split()[1]) input2 = input1.split()[2] app_list = [[int(j) for j in i.split(',')] for i in input2.split('#')] dp = [[0 for _ in range(B+1)] for _ in range(A+1)] for a,b,c in app_list:for j in range(A, a - 1, -1):for k in range(B, b - 1, -1):dp[j][k] = max(dp[j][k], dp[j - a][k - b] + c) print(dp[-1][-1])15 10 5,1,1000#2,3,3000#5,2,15000#10,4,16000 3100067、二維費用的背包問題
題目來源:https://www.acwing.com/problem/content/8/
只要知道了三維的dp的狀態轉移方程:dp[i][j][k] = max(dp[i-1][j][k],dp[i-1][j-V[i-1]][k-M[i-1]]+W[i-1])。就是一道在算法中送分題。
''' @Author: Runsen @WeChat:RunsenLiu @微信公眾號: Python之王 @CSDN: https://blog.csdn.net/weixin_44510615 @Github: https://github.com/MaoliRUNsen @Date: 2020/9/27 '''n,v,m = map(int,input().split()) dp = [[[0] * (m+1) for _ in range(v+1)] for _ in range(n+1)] V = [] M = [] W = [] for i in range(n):# 體積、重量和價值a,b,c = map(int,input().split())V.append(a)M.append(b)W.append(c) for i in range(1,n+1):# j是容量for j in range(1,v+1):# k是重量for k in range(1,m+1):if j-V[i-1] >= 0 and k-M[i-1] >= 0:dp[i][j][k] = max(dp[i-1][j][k],dp[i-1][j-V[i-1]][k-M[i-1]]+W[i-1])else:dp[i][j][k] = dp[i-1][j][k] print(dp[-1][-1][-1])下面是將三維dp直接進行空間優化成二維dp,其原理就是斐波那契數列的從底向頂的做法,逆向思維。
''' @Author: Runsen @WeChat:RunsenLiu @微信公眾號: Python之王 @CSDN: https://blog.csdn.net/weixin_44510615 @Github: https://github.com/MaoliRUNsen @Date: 2020/9/27 '''n,v,m = map(int,input().split()) dp = [[0 for _ in range(m+1)] for _ in range(v+1)] for i in range(n):# 體積、重量和價值a, b, c = map(int, input().split())for j in range(v, a - 1, -1):for k in range(m, b - 1, -1):dp[j][k] = max(dp[j][k], dp[j - a][k - b] + c) print(dp[-1][-1])68、買賣股票的最佳時機(買一次)
這是Leetcode的第121題: 買賣股票的最佳時機(買一次)
題目不說了,就是只能買一次,
class Solution:def maxProfit(self, prices: List[int]) -> int:# dp的狀態轉移方程:dp[i] = max(dp[i-1],prices[i]-minprice)n = len(prices)if n == 0: return 0dp = [0] * nminprice = prices[0]for i in range(1,n):minprice = min(minprice,prices[i])dp[i] = max(dp[i-1],prices[i]-minprice)return dp[-1]69、買賣股票的最佳時機(買N次)
這是Leetcode的第122題: 買賣股票的最佳時機(買N次)
那么dp就需要開一個維度來表示當天是買還是賣。
class Solution:def maxProfit(self, prices: List[int]) -> int:'''可以買賣多次 dp[i][j]dp[i][0] 表示前 i天的最大利潤,第i天不買,那么dp轉移方程取決于i-1天是有股票還是沒有股票dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i])dp[i][1] 表示前 i天的最大利潤,第i天必須買, 那么dp轉移方程取決于i-1天是有股票還是沒有股票dp[i][1] = max(dp[i-1][0]-prices[i],dp[i-1][1])'''n = len(prices)if n == 0: return 0dp = [[0]*2 for _ in range(n)]dp[0][0] = 0dp[0][1] = -prices[0]for i in range(1,n):dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i])dp[i][1] = max(dp[i-1][0]-prices[i],dp[i-1][1])return dp[-1][0]# 找到所有的上升區間,計算每個上升區間的價格差,直接節約了空間復雜度 為O(1)# 貪心做法n = len(prices)profit = 0if n == 0 : return 0for i in range(1,n):if prices[i] > prices[i-1]:profit += prices[i] - prices[i-1]return profit# 最好的做法就是有一個變量儲存沒有股票的最大利潤和有股票的最大利潤,然后不斷地維護# cash表示第i天結束,沒有股票的最大利潤# hold表示第i天結束,有股票的最大利潤cash, hold = 0, -prices[0]for i in range(1,len(prices)):cash = max(cash,hold+prices[i])hold = max(hold,cash-prices[i])return cash70、買賣股票的最佳時機(買2次)
這是Leetcode的第123題: 買賣股票的最佳時機(買2次)
class Solution:def maxProfit(self, prices: List[int]) -> int:'''dp[i][k][XX] i 表示第i的最大利潤,k表示第i天之前你買了多少次,X表示第i天是否有股票 0 ,1 p[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1]+prices[i])dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0]-prices[i])'''if not prices:return 0n = len(prices)# 初始化狀態dp = [[[0]*2 for _ in range(3)] for _ in range(n)]for k in range(3):# 第一天買入股票dp[0][k][1] = -prices[0]# 從 i=1 處開始迭代for i in range(1, n):for k in range(1, 3):dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1]+prices[i])dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0]-prices[i])return dp[-1][2][0]71、買賣股票的最佳時機(買k次)
這是Leetcode的第188題: 買賣股票的最佳時機(買k次)
注釋寫得很詳細了。
class Solution:def maxProfit(self, k: int, prices: List[int]) -> int:# @Author:Runsen#dp[i][j][0] 今天是第i天 進行 j次 交易 手上沒有股票#dp[i][j][1] 今天是第i天 進行 j次 交易 手上有股票if k == 0 or len(prices) < 2:return 0n = len(prices)res = []# 如果k的次數大于n//2,那么就是直接計算利潤,第一天買,第二天就賣,然后第二天在買。if k > n // 2: max_profit = 0for i in range(1,n):profit = prices[i] - prices[i - 1]# 如果第二天比第一天高,那就直接加入if profit > 0:max_profit += profitreturn max_profit# 下面就是Leetcode第123的代碼 dp[i][j][0]dp = [[[0] * 2 for _ in range(k + 1)] for _ in range(n)]for i in range(k + 1):# 第一天買入股票dp[0][i][1] = - prices[0]for i in range(1, n):for k in range(1, k+1):dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1]+prices[i])dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0]-prices[i])# 求dp[i][k][0] 的最大,這里我直接開數組for m in range(k + 1):res.append(dp[-1][m][0])return max(res)72、買賣股票的最佳時機(買N次加CD冷卻時間)
這是Leetcode的第309題: 買賣股票的最佳時機(買N次加CD冷卻時間)
注釋寫得很詳細了。
class Solution:def maxProfit(self, prices: List[int]) -> int:# 如果設置dp的狀態? 就是關鍵。冷凍期其實就是CD技能的時間。# dp[i][0]表示第i天結束之后,我有股票的最大收益。那么有可能i-1天我本來就有股票,今天的價不好,我不賣了,或者昨天我沒有股票,但我今天可以買了股票,說明今天不是冷凍期。# dp[i][0] = max(dp[i-1][0], dp[i-1][2] - prices[i])# dp[i][1]表示第i天結束之后,我沒有股票,明天就是冷凍期,也就是昨天有股票,今天運氣好,價格高,我剛剛賣了股票這一種可能。# dp[i][1] = dp[i-1][0] + prices[i]# dp[i][2]表示第i天結束之后,我沒有股票,但是明天不在冷凍期,也就是今天我不買股票,有可能因為我昨天剛剛賣了,今天就是冷凍期,我買不了。也有可能,昨天的我可能沒打算買,今天又不買。# dp[i][2] = max(dp[i-1][1] ,dp[i-1][2])if not prices: return 0n = len(prices)# 第0天dp[0][0]要買是第一個股dp = [[-prices[0], 0, 0]] + [[0] * 3 for _ in range(n - 1)]for i in range(1, n):dp[i][0] = max(dp[i-1][0], dp[i-1][2] - prices[i])dp[i][1] = dp[i-1][0] + prices[i]dp[i][2] = max(dp[i-1][1] ,dp[i-1][2])return max(dp[-1][1], dp[-1][2])73、買賣股票的最佳時機(買N次加手續費)
這是Leetcode的第714題: 買賣股票的最佳時機(買N次加手續費)
注釋寫得很詳細了。
# 就是在dp[i][0]減去手續費而已 class Solution:def maxProfit(self, prices: List[int], fee: int) -> int:n = len(prices)if n == 0: return 0dp = [[0]*2 for _ in range(n)]dp[0][0] = 0dp[0][1] = -prices[0]for i in range(1,n):dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i]-fee)dp[i][1] = max(dp[i-1][0]-prices[i] ,dp[i-1][1])return dp[-1][0]class Solution:def maxProfit(self, prices: List[int], fee: int) -> int:# cash表示第i天結束,沒有股票的最大利潤# hold表示第i天結束,有股票的最大利潤cash, hold = 0, -prices[0]for i in range(1,len(prices)):cash = max(cash,hold+prices[i]-fee)hold = max(hold,.cash-prices[i])return cash74、冒泡排序
冒泡排序(英語:Bubble Sort)是一種簡單的排序算法。它重復地遍歷要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。遍歷數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。具體的查看代碼
def bubble_sort(nums):for i in range(len(nums) - 1):for j in range(len(nums) - i - 1):if nums[j] > nums[j + 1]:nums[j], nums[j + 1] = nums[j + 1], nums[j]return numsif __name__ == '__main__':nums = [54, 26, 93, 17, 77, 31, 44, 55, 20]bubble_sort(nums)print(nums) # [17, 20, 26, 31, 44, 54, 55, 77, 93]75、插入排序
插入排序的實現思路顧名思義,就是不斷地在一個已經是有序的數組中,尋找合適位置并插入新元素。
從后往前依次進行比較,如果待插入元素大于當前元素,則將待插入元素插入到當前元素的后一位,如果待插入元素小于當前元素,則將當前元素后移一位。不斷重復該過程直至到數組的最后一位
def insert_sort(a):length = len(a)if length <= 1:return a# 從數組的第二個數開始for i in range(1, length):# 從后向前掃描j = i - 1# value指的是插入元素value = a[i]while j >= 0:if a[j] < value:# 插入元素大于當前元素,則將待插入元素插入到當前元素的后一位a[j + 1] = valuebreakelse:# 插入元素小于當前元素,則將當前元素后移一位a[j + 1] = a[j]if j == 0:a[j] = valuej -= 1return aif __name__ == '__main__':nums = [54, 26, 93, 17, 77, 31, 44, 55, 20]print(insert_sort(nums))# [17, 20, 26, 31, 44, 54, 55, 77, 93]76、選擇排序
選擇排序:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再從剩余未排序元素中繼續尋找最小(大)元素,然后放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。
def selection_sort(arr):"""選擇排序"""# 第一層for表示循環選擇的遍數for i in range(len(arr) - 1):# 將起始元素設為最小元素min_index = i# 第二層for表示最小元素和后面的元素逐個比較for j in range(i + 1, len(arr)-1):if arr[j] < arr[min_index]:# 如果當前元素比最小元素小,則把當前元素角標記為最小元素角標min_index = j# 查找一遍后將最小元素與起始元素互換arr[min_index], arr[i] = arr[i], arr[min_index]return arrif __name__ == '__main__':nums = [54, 26, 93, 17, 77, 31, 44, 55, 20]print(selection_sort(nums))# [17, 20, 26, 31, 44, 54, 55, 77, 93]77、希爾排序
希爾排序的基本思想是:把記錄按步長 gap 分組,對每組記錄采用直接插入排序方法進行排序。
def shell_sort(list):n = len(list)# 步長一般為gap = n // 2while gap >= 1:for j in range(gap, n):i = jwhile( i - gap ) >= 0:if list[i] < list[ i - gap ]:list[i], list[ i - gap ] = list[ i - gap ], list[i]i -= gapelse:breakgap //= 2if __name__ == '__main__':alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]shell_sort(alist)print(alist)# [17, 20, 26, 31, 44, 54, 55, 77, 93]78、歸并排序
歸并排序基本思想:將數組array[0,...,n-1]中的元素分成兩個子數組:array1[0,...,n/2]和array2[n/2+1,...,n-1]。分別對這兩個數組單獨排序,然后將已排序的 兩個子數組歸并成一個含有n個元素的有序數組
def merge(left, right):i = 0j = 0temp = []while i <= len(left) - 1 and j <= len(right) - 1:if left[i] <= right[j]:temp.append(left[i])i += 1else:temp.append(right[j])j += 1temp += left[i:] + right[j:]return tempdef merge_sort(nums):if len(nums) <= 1:return numsnum = len(nums) >> 1left = merge_sort(nums[:num])right = merge_sort(nums[num:])return merge(left, right)if __name__ == '__main__':nums = [54, 26, 93, 17, 77, 31, 44, 55, 20]print(merge_sort(nums))79、快速排序
快速排序的基本思想是:通過一趟排序將要排序的數據分割成獨立的兩部分:分割點左邊都是比它小的數,右邊都是比它大的數。
快速排序用遞歸來寫,代碼非常簡單。
def quicksort(array):if len(array) < 2:# 基本情況下,具有0或1個元素的數組是已經“排序”的return arrayelse:# 遞歸情況pivot = array[len(array)//2]# 小于基準值的所有元素的子數組less = [i for i in array[1:] if i <= pivot]# 大于基準值的所有元素的子數組greater = [i for i in array[1:] if i > pivot]return quicksort(less) + [pivot] + quicksort(greater)if __name__ == '__main__':nums = [54, 26, 93, 17, 77, 31, 44, 55, 20]print(quicksort(nums))80、查找和為定值的兩個數
查找和為定值的兩個數,這道題可以說是Leetcode第一題的變體。比如array = [0, 1, 2, 3, 4, 5, 6],求所有等于7的兩個數的列表總和。
def two_sum2(array, s):# 時間復雜度是O(N),空間復雜度是O(N)d= dict()for a in array:d[a] = Noneresult = []for a in array:if s - a in d and s - a != a:result.append([a, s - a])del d[a]return resultif __name__ == '__main__':array = [0, 1, 2, 3, 4, 5, 6]print(two_sum2(array, 7)) # [[1, 6], [2, 5], [3, 4]]總結
以上是生活随笔為你收集整理的2020 年最全 Python 面试题汇总 (四)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 鲲伍游泳馆去清场万达运吗?
- 下一篇: 坦克歼击车的鼻祖——一号自行反坦克炮?