贪心算法+回溯算法+动态规划
一.貪心算法
1.分餅干問題
#思路:排序加貪心 先讓胃口小的孩子滿足 class Solution:def findContentChildren(self, g, s):print('==g:', g)print('==s:', s)g = sorted(g)#孩子s = sorted(s)#餅干res = 0for j in range(len(s)):#遍歷餅干 先給胃口小的分配if res<len(g):if g[res]<=s[j]:res+=1print('==res:', res)return resg = [1,2] s = [1,2,3] # g = [1, 2, 3] # s = [1, 1] sol = Solution() sol.findContentChildren(g, s)2.錢幣找零問題
用最少的紙幣來支付同等的金錢。
class Solution:def coinChange_2(self, coins, amount):coins=sorted(coins,reverse=True)print(coins)five_number=0two_number=0one_number=0while amount>=coins[0]:five_number+=1amount-=coins[0]# print('five_number:',five_number)# print(amount)while amount>=coins[1]:two_number+=1amount-=coins[1]# print('two__number:',two_number)# print(amount)while amount>=coins[-1]:one_number+=1amount-=coins[-1]# print('one__number:',one_number)# print(amount)return five_number,two_number,one_number coins = [1, 2, 5] amount = 11 sol = Solution() five_number,two_number,one_number = sol.coinChange_2(coins, amount) print('five_number:',five_number) print('two_number:',two_number) print('one_number:',one_number)3.區間覆蓋
假設我們有 n 個區間,區間的起始端點和結束端點分別是 [l1, r1],[l2, r2],[l3, r3],……,[...
我們從這 n 個區間中選出一部分區間,這部分區間滿足兩兩不相交,端點相交不算,最多有多少區間;
這個問題主要在于右端點選小的,使右邊能夠有更大的區間覆蓋。
4,霍夫曼編碼(用于數據壓縮)
假設1000個字符,每個字符占一個1個byte,一個byte=8bits,那么存儲這1000個就要8000bits,怎么節省呢?
發現這1000個字符只有a,b,c,d,e,f六種不同的字符,所以可以用三個二進制來表示,這樣空間就壓縮到了3000bits,
根據貪心算法,出現字符頻率次數多的,用稍微短的編碼,而出現字符頻率次數少的,用稍微長的編碼,
例題1:
N = int(input()) line = [] for i in range(N):a, b = sorted(list(map(int, input().split(' '))))line.append([a, b]) print(line)# line=[[3, 6], [1, 3], [2, 5]] line = sorted(line, key=lambda x: x[1]) print('line=', line)ret = [line[0]] print('ret=', ret) for item in line[1:]:print('item=', item)if ret[-1][1] > item[0]:passelse:ret.append(item) print(ret) print(len(ret))例題2:假設小偷有一個背包,最多能裝20公斤贓物,他闖入一戶人家,發現如下表所示的物品。很顯然,他不能把所有物品都裝進背包,所以必須確定拿走哪些物品,留下哪些物品。
| 電腦 | 200 | 20 |
| 收音機 | 20 | 4 |
| 鐘 | 175 | 10 |
| 花瓶 | 50 | 2 |
| 書 | 10 | 1 |
| 油畫 | 90 | 9 |
二.回溯算法
《蝴蝶效應》,講的就是主人公為了達到自己的目標,一直通過回溯的方法,回到童年,在關鍵的岔路口,重新做選擇。
背包總的承載重量是 Ckg。現在我們有 n 個物品,每個物品的重量不一樣,并且不能分割,選哪幾種才能讓背包的總重量最大,且背包不會壞。
bestV = 0 curW = 0 curV = 0 bestx = Nonedef backtrack(i):global bestV, curW, curV, x, bestxif i >= n:if bestV < curV:bestV = curVbestx = x[:]else:if curW + w[i] <= c:x[i] = TruecurW += w[i]curV += v[i]backtrack(i + 1)curW -= w[i]curV -= v[i]x[i] = Falsebacktrack(i + 1)if __name__ == '__main__':#實現選擇最大價值的物品,且背包不會壞n = 5 #5個物品c = 10 #背包最大承重w = [2, 2, 6, 5, 4] #每個物品重量v = [6, 3, 5, 4, 6] #每個物品價值x = [False for i in range(n)]backtrack(0)print(bestV)print(bestx)2.電話號碼的字母組合
https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-xiang-jie-by-labuladong-2/
class Solution:def backtrace(self, digits, track):if len(digits) == 0:#滿足終止條件self.res.append(track)returnfor letter in self.phone[digits[0]]:# for循環去遍歷選擇條件store = track#保存中間結果用于回溯track += letterself.backtrace(digits[1:], track)track = store#恢復中間結果回溯def letterCombinations(self, digits):self.res = []if len(digits) == 0:return self.resself.phone = {'2': ['a', 'b', 'c'],'3': ['d', 'e', 'f'],'4': ['g', 'h', 'i'],'5': ['j', 'k', 'l'],'6': ['m', 'n', 'o'],'7': ['p', 'q', 'r', 's'],'8': ['t', 'u', 'v'],'9': ['w', 'x', 'y', 'z']}self.backtrace(digits, track='')print('==self.res:', self.res)return self.resdigits = "23" sol = Solution() sol.letterCombinations(digits)3.遞歸實現全排列:
含有三種解法
def swap(a, p, i):a[p], a[i] = a[i], a[p]return a#取第一個數,剩下的做排序,邊界條件是開始索引p==終止索引q def main(a, p, q):res = []def permute(a, p, q):if p == q:res.append(a.copy())print('res:', res)else:for i in range(p, q, 1):swap(a, p, i)permute(a, p+1, q)print('a:', a.copy())swap(a, p, i)#a還原成原順序,比如2開頭的結束了是2 1 3 需要還原成1 2 3 在吧3放在開頭在排序print('==a:', a.copy())permute(a, p, q)print('==res:', res)# # a = [1] # a = [1, 2] a=[1, 2, 3] main(a, 0, len(a))class Solution:def permute(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""def backtrack(first=0):# 所有數都填完了if first == n:res.append(nums.copy())for i in range(first, n):# 動態維護數組nums[first], nums[i] = nums[i], nums[first]# 繼續遞歸填下一個數backtrack(first + 1)# 撤銷操作nums[first], nums[i] = nums[i], nums[first]n = len(nums)res = []backtrack()return resa = [1, 2, 3] sol = Solution() res = sol.permute(a) print('===res:', res) class Solution:def permute(self, nums):""":type nums: List[int]:rtype: List[List[int]]"""n = len(nums)res = []def backtrack(combination, nums):if len(combination) == n:#往前走的數與最早的數長度想等 就是要的結果之一res.append(combination)print('res', res)return# 遞歸的結束一定 要有returnfor i in range(len(nums)):#遞歸回溯print('===nums[i]:', nums[i])backtrack(combination+[nums[i]], nums[:i]+nums[i+1:])backtrack([], nums)return resa = [1, 2] # a = [1, 2, 3] sol = Solution() res = sol.permute(a) print('===res:', res)4.n皇后問題
#多皇后問題,同一列 同一行 對角都不能出現同一個皇后
#解法思路:采用回溯算法,可對行進行回溯遍歷, 用數組記錄列, 對角索引和,與對角索引差,都不在其中,那么就可以往下走
#終止條件:遍歷到的行是最后一行 且可以放置
class Solution:def could_place(self, row, col):return not (self.cols_index[col] + self.sub_indexs[row - col] + self.add_indexs[row + col])def place_queen(self, row, col):self.quenes.add((row, col))self.cols_index[col] = 1self.sub_indexs[row - col] = 1self.add_indexs[row + col] = 1def remove_queen(self, row, col):self.quenes.remove((row, col))self.cols_index[col] = 0self.sub_indexs[row - col] = 0self.add_indexs[row + col] = 0def add_res(self):for queue in self.quenes:self.res.append(queue)temp = []for row, col in sorted(self.quenes):temp.append('.'*col + 'Q' + '.' * (self.n - col - 1))self.out.append(temp)def backtrace(self, row):for col in range(self.n):if self.could_place(row, col):self.place_queen(row, col)if (row + 1) == self.n:self.add_res()else:self.backtrace(row + 1)self.remove_queen(row, col)def solveNQueens(self, n: int) -> List[List[str]]:self.n = nself.quenes = set()self.cols_index = [0] * nself.sub_indexs = [0]* (2 * n -1)self.add_indexs = [0]* (2 * n -1)self.res = []self.out = []self.backtrace(row = 0)return self.out?
三.動態規劃
其是一種空間換時間的算法。
1.遞歸與動態規劃解決最大不相鄰數之和
#不相鄰最大數 遞歸解法 def rect_opt(arr,i):if i==0:return arr[i]elif i==1:return max(arr[i-1],arr[i])else:#選自身A=rect_opt(arr,i-2)+arr[i]#不選自身B=rect_opt(arr,i-1)return max(A,B) arr=[4,1,1,9,1] arr=[1,2,3,4,5] res=rect_opt(arr,len(arr)-1) print('res:',res)#不相鄰最大數 DP解法 def dp_opt(arr):opt=[0]*len(arr)opt[0]=arr[0]opt[1]=max(arr[0],arr[1])for i in range(2,len(arr)):opt[i]=max(opt[i-2]+arr[i],opt[i-1])return optarr=[4,1,1,9,1] arr=[1,2,3,4,5] opt=dp_opt(arr) print('opt:',opt) print('res:',opt[-1])2.動態規劃解決最大公共子串問題
?
# # 動態規劃解決最大公共子串問題 def find_lcsubstr(s1, s2):m = [[0 for i in range(len(s2) + 1)] for j in range(len(s1) + 1)] # 生成0矩陣,為方便后續計算,比字符串長度多了一列print(m)mmax = 0 # 最長匹配的長度p = 0 # 最長匹配對應在si中的最后一位for i in range(len(s1)):for j in range(len(s2)):if s1[i] == s2[j]:m[i + 1][j + 1] = m[i][j] + 1if m[i + 1][j + 1] > mmax:mmax = m[i + 1][j + 1]p = i + 1print(p)return s1[(p - mmax):p], mmax # 返回最長子串及其長度3.?動態規劃解決最大公共子序列問題
方法1:
import numpy as np def find_lcseque(s1, s2):# 生成字符串長度加1的0矩陣,m用來保存對應位置匹配的結果m = [[0 for x in range(len(s2) + 1)] for y in range(len(s1) + 1)]print(m)# d用來記錄轉移方向d = [[None for x in range(len(s2) + 1)] for y in range(len(s1) + 1)]print(d)for i in range(len(s1)):for j in range(len(s2)):if s1[i] == s2[j]: # 字符匹配成功,則該位置的值為左上方的值加1m[i + 1][j + 1] = m[i][j] + 1d[i + 1][j + 1] = 'ok'elif m[i + 1][j] > m[i][j + 1]: # 左值大于上值,則該位置的值為左值,并標記回溯時的方向m[i + 1][j + 1] = m[i + 1][j]d[i + 1][j + 1] = 'left'else: # 上值大于左值,則該位置的值為上值,并標記方向upm[i + 1][j + 1] = m[i][j + 1]d[i + 1][j + 1] = 'up'print(m)print(d)(i, j) = (len(s1), len(s2))print(np.array(d))s = []while m[i][j]: # m[i][j]不為0 說明是存在公共子序列c = d[i][j]if c == 'ok': # 匹配成功,插入該字符,并向左上角找下一個s.append(s1[i - 1])i -= 1j -= 1if c == 'left': # 根據標記,向左找下一個j -= 1if c == 'up': # 根據標記,向上找下一個i -= 1s.reverse()return ''.join(s)res=find_lcseque('vesista', 'vsiss')print(res)
方法2:
import numpy as npclass Solution(object):def longestCommonSubsequence(self, text1, text2):""":type text1: str:type text2: str:rtype: int"""matrix = [[0 for i in range(len(text2) + 1)] for j in range(len(text1) + 1)]# print('==matrix:', matrix)ok_matrix = [[0 for i in range(len(text2) + 1)] for j in range(len(text1) + 1)]res = ''value = 0record_i_j = []for i in range(len(text1)):for j in range(len(text2)):if text1[i] == text2[j]: # 找到相等的字符matrix[i + 1][j + 1] = matrix[i][j] + 1if matrix[i+1][j+1] > value:#遞增的地方 才記錄value = matrix[i+1][j+1]ok_matrix[i][j] = 1else:matrix[i + 1][j + 1] = max(matrix[i + 1][j], matrix[i][j + 1])print('==matrix:', np.array(matrix))print(np.array(ok_matrix))for i in range(len(ok_matrix)):for j in range(len(ok_matrix[0])):if ok_matrix[i][j] == 1:print('===i,j', i, j)res += text1[i]print('===res:', res)return len(res)sol = Solution() # text1 = "abcde" # text2 = "ace" text1 = "ezupkr" text2 = "ubmrapg" # text1 = "bsbininm" # text2 ="jmjkbkjkv" # text1 = "abcba" # text2 = "abcbcba" # text1 = "oxcpqrsvwf" # text2 = "shmtulqrypy" res = sol.longestCommonSubsequence(text1, text2)只要求長度:
class Solution:def longestCommonSubsequence(self, text1: str, text2: str) -> int:n = len(text1)m = len(text2)dp = [[0 for _ in range(m + 1)] for _ in range(n + 1)]for i in range(n):for j in range(m):if text1[i] == text2[j]:dp[i + 1][j + 1] = dp[i][j] + 1else:dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1])return dp[-1][-1]c++實現:
class Solution { public:int longestCommonSubsequence(string text1, string text2) {int n = text1.size();int m = text2.size();vector<vector<int> > dp(n + 1, vector<int>(m + 1, 0));for(int i = 0; i < n; i++){for(int j = 0; j < m; j++){if(text1[i] == text2[j]){dp[i+1][j+1] = dp[i][j] + 1;}else{dp[i+1][j+1] = max(dp[i+1][j], dp[i][j+1]);}}}return dp[n][m];} };4.求解矩陣最短路徑
原始矩陣:
狀態轉移矩陣:
代碼:
import numpy as np class Solution(object):def minPathSum(self, grid):""":type grid: List[List[int]]:rtype: int"""rows=len(grid)cols=len(grid[0])opt=[[0 for i in range(cols)] for i in range(rows)]# print(np.array(opt))opt[0][0] = grid[0][0]for j in range(1,cols):opt[0][j]=opt[0][j-1]+grid[0][j]# print(np.array(opt))for i in range(1,rows):opt[i][0]=opt[i-1][0]+grid[i][0]# print(np.array(opt))for i in range(1,rows):for j in range(1,cols):opt[i][j]=min(opt[i-1][j]+grid[i][j],opt[i][j-1]+grid[i][j])# print(np.array(opt))return np.array(opt) grid=[[1,3,1],[1,5,1],[4,2,1]] sol=Solution() res=sol.minPathSum(grid) print('res:') print(res) print(res[-1][-1])結果:
5.子列表元素之和的最大值
解法1.
class Solution(object):def maxSubArray(self, arr):""":type nums: List[int]:rtype: int"""temp = len(arr) * [0]temp[0] = max(arr[0], 0)opt = len(arr)*[0]opt[0]=max(arr[0],0)for i in range(1,len(arr)):temp[i] = max(temp[i - 1]+arr[i], arr[i])opt[i] = max(temp[i],opt[i-1])print('temp:',temp)return optarr=[1, -2, 3, 5, -3, 2] sol=Solution() res=sol.maxSubArray(arr) print('res:',res)解法2.
class Solution(object):def maxSubArray(self, nums):""":type nums: List[int]:rtype: int"""for i in range(1,len(nums)):nums[i]+=max(nums[i-1],0)return numsa=[1, -2, 3, 5, -3, 2] sol=Solution() res=sol.maxSubArray(a) print('res:',res)6-1. 01背包問題
(1).復雜解法,空間復雜度為O(N*W)
dp[i][j]:表示第i件物品,重量為j的價值
不選i:? dp[i][j] = dp[i-1][j]
選i: dp[i][j] = dp[i-1][j-w[i]]+v[i]
""" 物品的數量, N = 6 書包能承受的重量, W = 10 每個物品的重量, things_w = [2, 2, 3, 1, 5, 2] 每個物品的價值 things_v = [2, 3, 1, 5, 4, 3] """ N = 6 W = 10 things_w = [2, 2, 3, 1, 5, 2] things_v = [2, 3, 1, 5, 4, 3]# import numpy as np # def bag_complicate(N, W, things_w, things_v):dp = [[0 for j in range(W + 1)] for i in range(N)]print('==np.array(dp):', np.array(dp))for j in range(W + 1):if j >= things_w[0]:dp[0][j] = things_v[0]print('==np.array(dp):', np.array(dp))for i in range(1, N):for j in range(W + 1):dp[i][j] = dp[i - 1][j] # 不選if j >= things_w[i]:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - things_w[i]] + things_v[i])print('==np.array(dp):\n', np.array(dp))return dpdef show(N, W, things_w, value):print('最大價值為:', value[N - 1][W])x = [False for i in range(N)]j = Wfor i in range(N - 1, 0, -1):if value[i][j] > value[i - 1][j]:x[i] = Truej -= things_w[i]print('x', x)# print('背包中所裝物品為:')# for i in range(numbers):print('==np.array(dp):', np.array(dp))# if x[i]:# print('第', i+1, '個,', end='')if __name__ == '__main__':dp = bag_complicate(N, W, things_w, things_v)show(N, W, things_w, dp)
(2). 簡單解法,空間復雜度為O(W)
思路:
不選i:? dp[j] = dp[j]
選i: dp[j] = dp[j-w[i]]+v[i]
要注意的是重量需要逆序遍歷,因為如果采用正序的話 dp[j -w[i]]會被之前的操作更新為新值
N = 6 W = 10 things_w = [2, 2, 3, 1, 5, 2] things_v = [2, 3, 1, 5, 4, 3]def bag_easy(N,W,things_w,things_v):dp = [0 for i in range(W+1)]print('==dp:', dp)for i in range(N):for j in range(W, 0, -1):#記得用一維空間要逆序 防止if j >= things_w[i]:dp[j] = max(dp[j-things_w[i]]+things_v[i], dp[j])print('==dp:', dp)return dpbag_easy(N,W,things_w,things_v)6-2.完全背包問題
(1)復雜解法
dp[i][j]:表示第i件物品,重量為j的價值
不選i:? dp[i][j] = dp[i-1][j]
選i: dp[i][j] = dp[i][j-w[i]]+v[i]
""" 物品的數量, N = 6 書包能承受的重量, W = 10 每個物品的重量, things_w = [2, 2, 3, 1, 5, 2] 每個物品的價值 things_v = [2, 3, 1, 5, 4, 3] """ N = 6 W = 10 things_w = [2, 2, 3, 1, 5, 2] things_v = [2, 3, 1, 5, 4, 3]# import numpy as np # def bag_complicate(N, W, things_w, things_v):dp = [[0 for j in range(W + 1)] for i in range(N)]print('==np.array(dp):', np.array(dp))for j in range(W + 1):if j >= things_w[0]:dp[0][j] = things_v[0]print('==np.array(dp):', np.array(dp))for i in range(1, N):for j in range(W + 1):dp[i][j] = dp[i - 1][j] # 不選if j >= things_w[i]:dp[i][j] = max(dp[i - 1][j], dp[i][j - things_w[i]] + things_v[i])print('==np.array(dp):\n', np.array(dp))print('最大價值為:', dp[N - 1][W])return dpif __name__ == '__main__':dp = bag_complicate(N, W, things_w, things_v)(2)優化解法
def bag_easy(N,W,things_w,things_v):dp = [i for i in range(W+1)]print('==np.array(dp):', np.array(dp))for i in range(N):for j in range(W+1):if j >= things_w[i]:dp[j] = max(dp[j], dp[j-things_w[i]]+things_v[i])else:dp[j] = dp[j]print('==np.array(dp):', np.array(dp)) if __name__ == '__main__':bag_easy(N, W, things_w, things_v)7.零錢兌換
https://leetcode-cn.com/problems/coin-change/submissions/
給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回?-1。假設我們取面額為 1 的硬幣,那么接下來需要湊齊的總金額變為?11 - 1 = 10,即?f(11) = f(10) + 1,這里的?+1?就是我們取出的面額為 1 的硬幣。
同理,如果取面額為 2 或面額為 5 的硬幣可以得到:
- f(11) = f(9) + 1
- f(11) = f(6) + 1
所以:
f(11) = min(f(10), f(9), f(6)) + 1
class Solution:def coinChange(self, coins,amount):f = [float("inf")] * (amount + 1)f[0] = 0for i in range(1, amount + 1):for coin in coins:if i - coin >= 0:f[i] = min(f[i], f[i - coin]+1)print(f)return f[-1] if f[-1] != float("inf") else -1coins = [1, 2, 5] amount = 11 sol=Solution() res=sol.coinChange(coins,amount) print('res:') print(res)8.乘積最大子序列
乘法與加法最大差別在于,當前元素的符號具有全局性的作用。如果當前元素為負,那么連乘到上個元素的最大乘積,再乘以當前元素,就變成負數,甚至可能成為最小乘積。同樣,連乘到上個元素的最小乘積如為負,再乘以當前元素,就變成正數,甚至可能成為最大乘積,所以用兩個列表存儲當前最大最小值。
class Solution(object):def maxProduct(self, nums):""":type nums: List[int]:rtype: int"""if len(nums)<=1:return Noneopt_min=[0]*len(nums)opt_max = [0] * len(nums)opt_min[0]=nums[0]opt_max[0] = nums[0]for i in range(1,len(nums)):opt_min[i] = min(min(opt_min[i-1]*nums[i],opt_max[i-1]*nums[i]),nums[i])opt_max[i] = max(max(opt_min[i-1]*nums[i],opt_max[i-1]*nums[i]),nums[i])print('opt_min',opt_min)print('opt_max',opt_max)return max(opt_max)nums = [2, 3, -4,4] # nums =[-2,0,-1] # nums=[0,2] # amount = 11 sol=Solution() res=sol.maxProduct(nums) print('res:') print(res)9.三角形最小路徑和
https://leetcode-cn.com/problems/triangle/submissions/
class Solution(object):def minimumTotal(self, triangle):""":type triangle: List[List[int]]:rtype: int"""# res=[]for i in range(1,len(triangle)):for j in range(len(triangle[i])):#邊界條件if j == 0:triangle[i][j]=triangle[i-1][j]+triangle[i][j]# 邊界條件elif j == i:triangle[i][j] = triangle[i - 1][j-1] + triangle[i][j]else:triangle[i][j] = min(triangle[i - 1][j - 1],triangle[i-1][j]) + triangle[i][j]return min(triangle[-1])triangle =[[2],[3,4],[6,5,7],[4,1,8,3] ] # nums =[-2,0,-1] # nums=[0,2] # amount = 11 sol=Solution() res=sol.minimumTotal(triangle) print('res:') print(res)10.收益最大--簡易
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/submissions/
前i天的最大收益 = max{前i-1天的最大收益,第i天的價格-前i-1天中的最小價格}
class Solution(object):def maxProfit(self, prices):""":type prices: List[int]:rtype: int"""if len(prices)<=1:return Noneopt=[0]*len(prices)min_p=9999for i in range(len(prices)):#記錄第i天之前的最小價min_p = min(min_p, prices[i])opt[i] = max(opt[i-1],prices[i]-min_p)#min(prices[:i]))print(opt)return opt[-1]prices =[1,2] # nums =[-2,0,-1] # nums=[0,2] # amount = 11 sol=Solution() res=sol.maxProfit(prices) print('res:') print(res)10.收益最大--中級
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
# sell[i]表示截至第i天,最后一個操作是賣時的最大收益; # buy[i]表示截至第i天,最后一個操作是買時的最大收益; # cool[i]表示截至第i天,最后一個操作是冷凍期時的最大收益; class Solution(object):def maxProfit(self, prices):""":type prices: List[int]:rtype: int"""if len(prices) == 0:return 0sell = [0]*len(prices)buy = [0] * len(prices)cool = [0] * len(prices)buy[0]-=prices[0]print(buy)for i in range(1,len(prices)):# 第i天賣 第i天不賣sell[i]=max(sell[i-1],buy[i-1]+prices[i])# 第i天不買 第i天買buy[i] = max(buy[i-1],cool[i-1]-prices[i])# 第i天冷 第i天不冷cool[i] = max(sell[i-1],cool[i - 1],buy[i-1])print(buy)print(cool)print(sell)return sell[-1]prices=[1,2,3,0,2] sol = Solution() res = sol.maxProfit(prices) print('res:') print(res)11.矩陣走法最多路徑
https://leetcode-cn.com/problems/unique-paths/
一個機器人位于一個 m x n 網格的左上角 (起始點在下圖中標記為“Start” )。
機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為“Finish”)。
問總共有多少條不同的路徑?
class Solution(object):def uniquePaths(self, m, n):""":type m: int:type n: int:rtype: int"""opt=[[0 for i in range(n)] for j in range(m)]print(opt)for i in range(m):for j in range(n):if i==0 or j==0:opt[i][j]=1else:opt[i][j]=opt[i-1][j]+opt[i][j-1]print(opt)print(opt[-1][-1])return opt[-1][-1]m = 3 n = 2 sol=Solution() sol.uniquePaths(m,n)12.一個機器人位于一個 m x n 網格的左上角 (起始點在下圖中標記為“Start” )。
機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為“Finish”)。
現在考慮網格中有障礙物。那么從左上角到右下角將會有多少條不同的路徑
https://leetcode-cn.com/problems/unique-paths-ii/
class Solution(object):def uniquePathsWithObstacles(self, obstacleGrid):""":type obstacleGrid: List[List[int]]:rtype: int"""opt=[[0 for i in range(len(obstacleGrid[0]))] for j in range(len(obstacleGrid))]# print(opt)for i in range(len(obstacleGrid)):for j in range(len(obstacleGrid[0])):#邊界條件if obstacleGrid[i][j]==1:opt[i][j]=0else:if i==0 and j==0:opt[i][j]=1elif i==0:opt[i][j]=opt[i][j-1]elif j==0:opt[i][j] = opt[i-1][j]else:opt[i][j]=opt[i-1][j]+opt[i][j-1]# print(opt)return opt[-1][-1]13.輸入: s = "leetcode", wordDict = ["leet", "code"] 輸出: true
https://leetcode-cn.com/problems/word-break/
class Solution(object):def wordBreak(self, s, wordDict):""":type s: str:type wordDict: List[str]:rtype: bool"""word_set = {word for word in wordDict}# print(word_set)dp = [False for _ in range(len(s))]dp[0] = s[0] in word_set#第一層循環最外層for i in range(1, len(s)):if s[:i+1] in wordDict:dp[i] = True#內層循環for j in range(i):if dp[j] and s[j+1:i+1] in wordDict:dp[i] = Truebreakprint(dp)return dp[-1]s = "leetcode" wordDict = ["leet", "code"] sol=Solution() res=sol.wordBreak(s,wordDict)14,最大正方形面積
在一個由 0 和 1 組成的二維矩陣內,找到只包含 1 的最大正方形,并返回其面積。
https://leetcode-cn.com/problems/maximal-square/
class Solution(object):def maximalSquare(self, matrix):""":type matrix: List[List[str]]:rtype: int"""if not matrix:return 0rows=len(matrix)columns=len(matrix[0])dp=[[0]*columns for i in range(rows)]#邊界條件dp[0]=list(map(int,matrix[0]))for i in range(rows):dp[i][0] = int(matrix[i][0])for i in range(1,rows):for j in range(1,columns):#遞歸條件if matrix[i][j]=="1":dp[i][j]=min(dp[i-1][j],dp[i-1][j-1],dp[i][j-1])+1res=0for i in range(rows):for j in range(columns):res = max(res,dp[i][j]**2)print('dp:',dp)print(res)return res# matrix=[[1, 0, 1, 0, 0], # [1, 0, 1, 1, 1], # [1, 1, 1, 1, 1], # [1, 0, 0, 1, 0]] matrix=[["1"]] sol=Solution() res=sol.maximalSquare(matrix) print('res:',res)15.將列表中相鄰的數聚類在一起(動態規劃)
1直接相鄰就聚,帶來的問題是如果值依次增加,會不準(動態規劃)
a=[1,2,3,4,56,34,46,100,110,123] a=sorted(a) print('a:',a) opt=[0]*len(a) for i in range(1,len(a)):if a[i]-a[i-1]<20:opt[i]=1 opt.append(0) print('opt:',opt) index=[j for j in range(len(opt)) if opt[j]==0] print('index:',index) for k in range(len(index)-1):print(a[index[k]:index[k+1]])2.優化版,雙指針
a = [1, 2, 3, 4, 56, 34, 46, 100, 110, 123] a = sorted(a) print('a:', a) res = [] left, right = 0, 0 while right <len(a):right= left+1while right < len(a) and a[right]-a[left]<20:right+=1res.append([left, right-1])left = rightprint('==res:', res)for i in res:print('==a[i[0]:i[1]]:', a[i[0]:i[1] + 1])16.打家劫舍簡單版?房屋一排
https://leetcode-cn.com/problems/house-robber/
class Solution(object):def rob(self, nums):""":type nums: List[int]:rtype: int"""if len(nums)==0:return 0if len(nums)<=2:return max(nums)opt = [0] * len(nums)opt[0] = nums[0]opt[1] = max(nums[:2])#注意邊界條件 從2開始 所以要對 0 1 賦值for i in range(2,len(nums)):opt[i]=max(opt[i-2]+nums[i],opt[i-1])print(opt)return opt[-1] nums=[1,2,3,1] sol = Solution() res = sol.rob(nums) print('res:') print(res)17.打家劫舍中等版 房屋圍成圈 所以分為不搶第一家和不搶最后一家兩種情況
https://leetcode-cn.com/problems/house-robber-ii/
class Solution(object):def rob(self, nums):""":type nums: List[int]:rtype: int"""if len(nums)==0:return 0if len(nums)<=2:return max(nums)opt1 = [0] * len(nums)opt2 = [0] * len(nums)#不搶第一家opt1[0] = 0opt1[1] = nums[1]#不搶最后一家opt2[0] = nums[0]opt2[1] = max(nums[:2])for i in range(2,len(nums)):opt1[i]=max(opt1[i-2]+nums[i], opt1[i-1])print(opt1)for i in range(2, len(nums)-1):opt2[i] = max(opt2[i - 2] + nums[i], opt2[i - 1])print(opt2)return max(opt1[-1],opt2[-2]) nums=[1,2,3,1] sol = Solution() res = sol.rob(nums) print('res:') print(res)18.最長上升子序列
給定一個無序的整數數組,找到其中最長上升子序列的長度。
利用opt列表來存儲在第i個元素之前小于i的最長長度。
class Solution(object):def lengthOfLIS(self, nums):""":type nums: List[int]:rtype: int"""if nums==[]:return 0opt=[0]*len(nums)opt[0]=1for i in range(len(nums)):max_value = 0for j in range(i):#在<i這段內 找出小于nums[i]的數字if nums[i]>nums[j]:max_value=max(max_value,opt[j])opt[i]=max_value+1# print(opt)# print(max_value)return max(opt)19.編輯距離計算字符之間相似度
編輯距離,又稱Levenshtein距離(萊文斯坦距離也叫做Edit Distance),是指兩個字串之間,由一個轉成另一個所需的最少編輯操作次數,如果它們的距離越大,說明它們越是不同。許可的編輯操作包括將一個字符替換成另一個字符,插入一個字符,刪除一個字符。
mat[i+1,j]+1表示增加操作
d[i,j+1]+1 表示刪除操作
d[i,j]+temp表示替換操作,其中temp取0或1
總結
以上是生活随笔為你收集整理的贪心算法+回溯算法+动态规划的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV与图像处理学习十——区域生长
- 下一篇: Python 学习编程 【for语句br