獻芹奏曝-Python面試題-演算法-動態規劃篇 獻芹奏曝-Python面試題
阿新 • • 發佈:2022-03-20
上一篇:獻芹奏曝-Python面試題
開篇的話:本文目的是收集和歸納力扣上的演算法題,希望用python語言,竭我所能做到思路最清奇、程式碼最簡潔、方法最廣泛、效能最高效,瞭解常見題目,找到最利於記憶的答案,更加從容的應對面試。希望廣思集益,共同進步。
動態規劃篇
-
70. 爬樓梯(難度係數✯)
class Solution: def climbStairs(self, n: int) -> int: if n == 1: return 1 elif n == 2:
方法一執行結果:1:超時
知識點/技巧: 遞迴呼叫,會有大量重複計算
class Solution: dict_result = {} def climbStairs(self, n: int) -> int: if self.dict_result.get(n): return self.dict_result.get(n)
方法二執行結果:1:耗時超過54%。2:記憶體超過79%
知識點/技巧:通過字典,將計算過的值儲存,減少重複計算
class Solution: def climbStairs(self, n: int) -> int: if n == 1: return 1 a = [1] * (n + 1) a[1] = 1 a[2] = 2 for i in range(3, n+1): a[i] = a[i - 1] + a[i - 2] return a[n]
方法三執行結果:1:耗時超過79%。2:記憶體超過89%
知識點/技巧:通過陣列,求和的速度更快,根據索引取值,比字典查詢更快
class Solution: def climbStairs(self, n: int) -> int: if n == 1: return 1 first = 1 second = 2 for i in range(3, n + 1): first, second = second, first + second return second
方法四執行結果:1:耗時超過79%。2:記憶體超過75%
知識點/技巧:通過數字滾動的方式,但是疑惑的是,並沒發現記憶體空間提升多少
當然還有一些其他方法,矩陣法、通項公式法,這裡不一一介紹 -
53. 最大子陣列和(難度係數✯)
class Solution: def maxSubArray(self, nums: List[int]) -> int: # 構造和目標陣列一樣長度的陣列 r = nums.copy() for i in range(1, len(nums)): if r[i - 1] > 0: r[i] += r[i - 1] return max(r)
方法一執行結果:1:耗時超過78%。2:記憶體超過15% 。
知識點/技巧:
為了便於理解記憶:可以想象成一個賭徒賭博,什麼時候,手中籌碼最多,
我們記錄每一把賭牌後的手中籌碼數,當然有一點不同的是,
如果上一步贏了,或者還有剩餘,我們財富積累,
如果上一步錢輸光了,往事隨風,另起爐灶,重新開始,從當前記錄class Solution: def maxSubArray(self, nums: List[int]) -> int: if len(nums) == 1: return nums[0] top_one = nums[0] for i in range(1, len(nums)): if nums[i - 1] > 0: nums[i] += nums[i - 1] if nums[i] > top_one: top_one = nums[i] return top_one
方法二執行結果:1:耗時超過70%。2:記憶體超過36%
知識點/技巧:通過數字滾動的方式,節省記憶體
-
416. 分割等和子集(難度係數✯)
""" 1:要想使得分割成後的兩個子集和相等,那麼:和必須為偶數 2:我們馬上可以轉換成0-1揹包問題:即每個物品可以出現0次或1次 3: 0 1 2 3 4 5 6 7 8 9 10 11 第一個物品放或者不放 √ √ 第二個物品放或者不放 √ √ √ √ 如果第二個物品5沒放,那就是原來的值,如果5放了,那就是在原來的基礎上向後移動5個單位 第三個物品放或者不放 √ √ √ √ √ √ 但是需要注意的是放與不放這個動作一氣呵成, """ from typing import List class Solution: def canPartition(self, nums: List[int]) -> bool: s = sum(nums) if s % 2: # 1:要想使得分割成後的兩個子集和相等,那麼:和必須為偶數 return False target = s // 2 a = [False] * (target + 1) a[0] = True for index_n, n in enumerate(nums): if n > target: # 2:如果遍歷的元素比目標值大,說明沒有找到結果,返回False return False change_index = [] for index, item in enumerate(a): if item: if index + n > target: for c_index in change_index: a[c_index] = True break if index + n == target: return True else: change_index.append(index + n) else: # 為什麼只有在退出的時候才統一賦值,[1,2,5] 此時會出錯 for c_index in change_index: a[c_index] = True return False
方法一執行結果:1:耗時超過95%。2:記憶體超過83%
知識點/技巧: 轉換成01揹包問題,詳情看程式碼中註釋
class Solution: def canPartition(self, nums: List[int]) -> bool: s = sum(nums) if s % 2: # 1:要想使得分割成後的兩個子集和相等,那麼:和必須為偶數 return False target = s // 2 a = [False] * (target + 1) a[0] = True for index_n, n in enumerate(nums): if n > target: # 2:如果遍歷的元素比目標值大,說明沒有找到結果,返回False return False for i in reversed(range(0, target - n + 1)): if a[i]: if i + n == target: return True a[i + n] = True return False
方法二執行結果:1:耗時超過96%。2:記憶體超過99%
知識點/技巧: 倒敘遍歷,是列表變化(長度、內容)的剋星
class Solution: def canPartition(self, nums: List[int]) -> bool: s = sum(nums) if s % 2: # 1:要想使得分割成後的兩個子集和相等,那麼:和必須為偶數 return False target = s // 2 a = [False] * (target + 1) dir_list = {0: True} for n in nums: if n > target: # 2:如果遍歷的元素比目標值大,說明沒有找到結果,返回False return False list_keys=[] for key in reversed(list(dir_list.keys())): if dir_list.get(target - n): return True list_keys.append(key + n) else: for l_key in list_keys: dir_list[l_key] = True return False
方法三執行結果:1:耗時超過96%。2:記憶體超過43%
知識點/技巧:利用雜湊表實現,實現快速查詢
-
217. 存在重複元素(難度係數✯)
方法一執行結果:1:耗時超過40%。2:記憶體超過33%。3:程式碼簡潔
知識點/技巧: 利用set去重,比較長度
方法二執行結果:1:耗時超過76%。2:記憶體超過30%。
知識點/技巧: 利用字典記錄字母出現次數
-