一趟結(jié)束后能夠確定一個(gè)元素的最終位置的排序方法有: 簡(jiǎn)單選擇排序、快速排序、冒泡排序、堆排序
穩(wěn)定性定義:排序前后兩個(gè)相等的數(shù)相對(duì)位置不變,則算法穩(wěn)定。
數(shù)據(jù)結(jié)構(gòu) search insert delete
數(shù)組 O(n),有序數(shù)組折半查找是O(lgn) O(n) O(n)
雙向鏈表 O(n) O(1) O(1)
排序二叉樹 O(lgn) O(lgn) O(lgn)
哈希表(n與槽數(shù)m成正比)O(1) O(1) O(1)-
快速排序算法:
public static int[] qsort(int arr[],int start,int end) { int pivot = arr[start]; int i = start; int j = end; while (i<j) { while ((i<j)&&(arr[j]>pivot)) { j--; } while ((i<j)&&(arr[i]<pivot)) { i++; } if ((arr[i]==arr[j])&&(i<j)) { i++; } else { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } if (i-1>start) arr=qsort(arr,start,i-1); if (j+1<end) arr=qsort(arr,j+1,end); return arr; }
-
歸并排序(左右分治):
/** * 歸并排序 * * @param arr */ public static void mergeSort(int[] arr) { process(arr, 0, arr.length - 1); } /** * 對(duì)lr范圍內(nèi)進(jìn)行左右分別排序,使中點(diǎn)左右兩邊都有序 * * @param arr * @param l * @param r */ public static void process(int[] arr, int l, int r) { if (l == r) return; int mid = (l + r) / 2; process(arr, l, mid); process(arr, mid + 1, r); merge(arr, l, r); } /** * 使用輔助數(shù)組對(duì)已經(jīng)左右拍好序的數(shù)組進(jìn)行整體排序 * * @param arr * @param l * @param r */ public static void merge(int[] arr, int l, int r) { int[] helpArr = new int[r - l + 1]; int mid = (r + l) / 2; int p = l; int q = mid + 1; int index = 0; while (p <= mid && q <= r) { helpArr[index++] = arr[p] < arr[q] ? arr[p++] : arr[q++]; } //左右一定有一個(gè)越界 while (p <= mid) { helpArr[index++] = arr[p++]; } while (q <= r) { helpArr[index++] = arr[q++]; } if (helpArr.length >= 0) System.arraycopy(helpArr, 0, arr, l, helpArr.length); }
歸并排序的*Master公式=T(N)=a*T(N/b)+O(N^d)==T(N)=2T(N/2)+O(N) **
大頂堆:(根節(jié)點(diǎn)的關(guān)鍵字既大于等于左子樹的關(guān)鍵字值,同時(shí)也大于等于右子樹的關(guān)鍵字值)
小頂堆:(根結(jié)點(diǎn)的鍵值是所有堆結(jié)點(diǎn)鍵值中最小者)
典例
-
4的冪:
這個(gè)題和“2的冪”“3的冪”一樣,有不用循環(huán)和遞歸就能直接判斷的方法,同樣十分巧妙,屬于二進(jìn)制/位運(yùn)算的應(yīng)用。 4的冪的數(shù),都是這樣的數(shù):100、10000、1000000……(4、16、64) 觀察規(guī)律,可以發(fā)現(xiàn) 4的冪 需要滿足以下條件: 最高位是 1,其余都為 0; 最高位的 1 應(yīng)該在奇數(shù)位上,比如:100 的 1 在 第三位上; 那么對(duì)應(yīng)的判斷方法為: 用 num & (num-1) 可以判斷條件1,比如:100(4) & 011(3) == 0,結(jié)果為 0 說明符合條件1; 是否在奇數(shù)位可以用 0xaaaaaaaa 判斷,16 進(jìn)制的 a 是 1010,比如:0100(4) & 1010(a) == 0,結(jié)果為 0 說明最高位 1 在奇數(shù)位上; public boolean isPowerOfFour(int n) { return n > 0 && (n & (n - 1)) == 0 && ((n & 0x55555555) == n); // if (n<0) return false; // if ((n&(n-1))!=0) return false; 判斷是否位2的冪次方 // return (n & 0x55555555) == n; 判斷1是否在奇數(shù)位上 }
-
兩個(gè)數(shù)相乘:
public static String multiply2(String num1, String num2) { int len1 = num1.length(); int len2 = num2.length(); int[] res = new int[len1 + len2]; for (int i = len1 - 1; i >= 0; i--) { for (int j = len2 - 1; j >= 0; j--) { int LowPos = i + j + 1; int highPos = i + j; int temp = (num1.charAt(i) - '0') * (num2.charAt(j) - '0') + res[LowPos]; res[LowPos] = (temp) % 10; res[highPos] += temp / 10; //這里高位不要取mod } } StringBuilder sb = new StringBuilder(); for (int i : res) { if (!(sb.length() == 0) && i == 0) sb.append(i); } return sb.length() == 0 ? "0" : sb.toString(); }
-
二叉樹的公共祖先:
-
最近公共祖先的定義為:“對(duì)于有根樹 T 的兩個(gè)結(jié)點(diǎn) p、q,最近公共祖先表示為一個(gè)結(jié)點(diǎn) x,滿足 x 是 p、q 的祖先且 x 的深度盡可能大(一個(gè)節(jié)點(diǎn)也可以是它自己的祖先)。”
例如,給定如下二叉樹: root = [3,5,1,6,2,0,8,null,null,7,4]
[圖片上傳失敗...(image-2faa57-1585194160478)]
-
class Solution { /* 算法思想,當(dāng)遞歸到的節(jié)點(diǎn)為p1或p2時(shí)候,則將該節(jié)點(diǎn)向上傳遞, 使其父節(jié)點(diǎn)變成其本身,如果一個(gè)節(jié)點(diǎn)下方?jīng)]有p1/p2,則向上傳遞null,使父節(jié)點(diǎn)為null, 當(dāng)左右節(jié)點(diǎn)分別是p1,p2時(shí)則說明該節(jié)點(diǎn)是目標(biāo)節(jié)點(diǎn),向上傳遞, 該目標(biāo)節(jié)點(diǎn)對(duì)應(yīng)的兄弟節(jié)點(diǎn)經(jīng)過遞歸后一定為null(因?yàn)樾值芄?jié)點(diǎn)的子節(jié)點(diǎn)中不存在p1/p2只能向上傳遞null), 最終目標(biāo)頂點(diǎn)傳遞至根節(jié)點(diǎn)。 */ public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p1, TreeNode p2) { if (root == null || root == p1 || root == p2) return root; TreeNode left = lowestCommonAncestor(root.left, p1, p2); TreeNode right = lowestCommonAncestor(root.right, p1, p2); if (left == null && right == null) return null; if (left == null || right == null) return left == null ? right : left; return root; } }
-
括號(hào)生成
-
給出 n 代表生成括號(hào)的對(duì)數(shù),請(qǐng)你寫出一個(gè)函數(shù),使其能夠生成所有可能的并且有效的括號(hào)組合。
例如,給出 n = 3,生成結(jié)果為:
[ "((()))",
"(()())",
"(())()",
"()(())",
"()()()"] public List<String> generateParenthesis(int n) { List<String> res = new ArrayList<>(); generate(res, "", 0, 0, n); return res; } //count1統(tǒng)計(jì)“(”的個(gè)數(shù),count2統(tǒng)計(jì)“)”的個(gè)數(shù) public void generate(List<String> res, String ans, int count1, int count2, int n) { if (count1 > n || count2 > n) return; if (count1 == n && count2 == n) res.add(ans); /*核心點(diǎn): count1>=count2 , 從左往右添加,只有滿足左邊括號(hào)數(shù)量>=右邊括號(hào)時(shí)候, 才能夠滿足題意,否則會(huì)出現(xiàn)括號(hào)不匹配的情況 */ if (count1 >= count2) { generate(res, ans + "(", count1 + 1, count2, n); generate(res, ans + ")", count1, count2 + 1, n); } }
-
-
BFS:
- [圖片上傳失敗...(image-26fb97-1585194160478)]
# 廣度遍歷 graph = { "A": ["B", "C"], "B": ["A", "C", "D"], "C": ["A", "B", "D", "E"], "D": ["B", "C", "E", "F"], "E": ["C", "D"], "F": ["D"] } def BFS(graph, s): queue = [] # 使用動(dòng)態(tài)數(shù)組作隊(duì)列 queue.append(s) seen = set() while (len(queue) > 0): vertex = queue.pop(0) # 每次取隊(duì)列中的第一個(gè)再進(jìn)行添加 seen.add(s) nodes = graph[vertex] for w in nodes: if w not in seen: queue.append(w) seen.add(w) print(vertex) BFS(graph, "A")
-
DFS
# 深度遍歷 graph = { "A": ["B", "C"], "B": ["A", "C", "D"], "C": ["A", "B", "D", "E"], "D": ["B", "C", "E", "F"], "E": ["C", "D"], "F": ["D"] } def DFS(graph, s): queue = [] # 使用動(dòng)態(tài)數(shù)組作棧 queue.append(s) seen = set() seen.add(s) parent = {s: None} # <子節(jié)點(diǎn):父節(jié)點(diǎn)> while (len(queue) > 0): vertex = queue.pop() nodes = graph[vertex] for w in nodes: if w not in seen: parent[w] = vertex queue.append(w) seen.add(w) print(vertex) return parent if __name__ == "__main__": print (DFS(graph,"A"))
-
使用BFS求最短路徑(Dijkstra):
[圖片上傳失敗...(image-a1078d-1585194160478)]
import heapq # 權(quán)限比隊(duì)列 import math graph = { "A": {"B": 5, "C": 1}, "B": {"A": 5, "C": 2}, "C": {"A": 1, "B": 2, "D": 4}, "D": {"B": 1, "C": 4, "E": 3, "F": 6}, "E": {"C": 8, "D": 3}, "F": {"D": 6} } def init_distance(graph, s): distance = {s: 0} for vertex in graph.keys(): if vertex != s: distance[vertex] = math.inf return distance def dijkstra(graph, s): pqueue = [] # prorityqueue 具有權(quán)重比的隊(duì)列,權(quán)重高的排前面 heapq.heappush(pqueue, (0, s)) seen = set() parent = {s: None} distance = init_distance(graph, s) while(len(pqueue) > 0): pair = heapq.heappop(pqueue) dist = pair[0] # 取出來的點(diǎn)到s的距離 vertex = pair[1] seen.add(vertex) nodes = graph[vertex].keys() for w in nodes: if w not in seen: if dist+graph[vertex][w] < distance[w]: distance[w] = dist+graph[vertex][w] heapq.heappush(pqueue, (dist+graph[vertex][w], w)) parent[w] = vertex return parent, distance parent, distance = dijkstra(graph, "A") print(parent) print(distance)
-
兩個(gè)數(shù)之間的所有數(shù)相與:
public static int rangeBitwiseAnd(int m, int n) { int count = 0; while (n != m) { n >>= 1; m >>= 1; count++; } return n << count; }
-
最大正方形
-
在一個(gè)由 0 和 1 組成的二維矩陣內(nèi),找到只包含 1 的最大正方形,并返回其面積。
示例:輸入:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0輸出: 4
//dp[i][j]為以[i][j]為右下角坐標(biāo)的最長(zhǎng)正方形邊長(zhǎng) class Solution { public int maximalSquare(char[][] matrix) { if (matrix==null||matrix.length==0) return 0; int m = matrix.length; int n = matrix[0].length; int[][] dp = new int[m][n]; int res = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (matrix[i][j] == '1' && (i == 0 || j == 0)) { dp[i][j] = 1; }else if (matrix[i][j] == '1') { dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])); } res = Math.max(dp[i][j] * dp[i][j], res); } } return res; } }
-
LeetCode 395題:至少有K個(gè)重復(fù)字符的最長(zhǎng)子串
找到給定字符串(由小寫字符組成)中的最長(zhǎng)子串 T , 要求 T 中的每一字符出現(xiàn)次數(shù)都不少于 k 。輸出 T 的長(zhǎng)度。 示例 1: 輸入: s = "aaabb", k = 3 輸出: 3 最長(zhǎng)子串為 "aaa" ,其中 'a' 重復(fù)了 3 次。 示例 2: 輸入: s = "ababbc", k = 2 輸出: 5 最長(zhǎng)子串為 "ababb" ,其中 'a' 重復(fù)了 2 次, 'b' 重復(fù)了 3 次。
題解(遞歸+分治):
class Solution {
public int longestSubstring(String s, int k) {
if (s.length() < k) return 0;
return countLongestSubstring(s.toCharArray(), 0, s.length() - 1, k);
}
private int countLongestSubstring(char[] chars, int l, int r, int k) {
int[] count = new int[26];
for (int i = l; i <= r; i++) {
count[chars[i] - 'a']++;
}
//使得左右指針?biāo)谖恢玫淖址麧M足條件(兩指針之間仍然可能存在不滿足條件的字符)
while (r - l + 1 >= k && count[chars[l] - 'a'] < k) l++;
while (r - l + 1 >= k && count[chars[r] - 'a'] < k) r--;
//當(dāng)篩選完畢后如果長(zhǎng)度不滿足K則返回0
if (r - l + 1 < k) return 0;
//對(duì)初篩滿足條件的子串進(jìn)行遍歷,出現(xiàn)不滿足條件的字符,以字符為分割,左右繼續(xù)遞歸查詢,直到滿足所有的count[chars[i] - 'a']都>=K則 返回 r - l + 1
for (int i = l; i < r; i++) {
if (count[chars[i] - 'a'] < k) {
return Math.max(countLongestSubstring(chars, l, i - 1, k), countLongestSubstring(chars, i + 1, r, k));
}
}
return r - l + 1;
}
}
?
計(jì)算完全二叉樹的節(jié)點(diǎn)個(gè)數(shù)并且且時(shí)間復(fù)雜度小于O(N)
[圖片上傳失敗...(image-86a6b8-1585194160478)]
-
lcs 最長(zhǎng)公共子串:
[圖片上傳失敗...(image-9fb531-1585194160478)]
-
//lrc 最長(zhǎng)公共子串 public int longestCommonSubsequence(String text1, String text2) { int[][] dp = new int[text1.length()][text2.length()]; for (int i = 0; i < text1.length(); i++) { for (int j = 0; j < text2.length(); j++) { boolean b = text1.charAt(i) == text2.charAt(j); if (i != 0 && j != 0) { if (b) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } else { if (b) dp[i][j] = 1; else { if (i == 0 && j == 0) continue; if (i == 0) dp[i][j] = dp[i][j - 1]; else dp[i][j] = dp[i - 1][j]; } } } } return dp[text1.length() - 1][text2.length() - 1]; }
更優(yōu)解法:
public int longestCommonSubsequence(String text1, String text2) { int n1 = text1.length(), n2 = text2.length(); int[][] dp = new int[n1 + 1][n2 + 1]; for (int i = 1; i <= n1; i++) { for (int j = 1; j <= n2; j++) { if (text1.charAt(i - 1) == text2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } } } return dp[n1][n2]; }
LIS 最長(zhǎng)上升子序列:
//給定一個(gè)無序的整數(shù)數(shù)組,找到其中最長(zhǎng)上升子序列的長(zhǎng)度。 class Solution { public int lengthOfLIS(int[] nums) { if (nums.length == 0) return 0; int[] dp = new int[nums.length]; dp[0] = 1; for (int i = 1; i < nums.length; i++) { int tempMax = 0; for (int j = i - 1; j >= 0; j--) { if (nums[i] > nums[j]) { tempMax = Math.max(tempMax, dp[j]); } } dp[i] = tempMax + 1; } int res = 0; for (int i : dp) { if (i > res) res = i; } return res; } }
lcs 712 兩個(gè)字符串的最小ascll刪除和:
//最大公共子串 且 要求這些公共子串的 ascii 值最大。 public int minimumDeleteSum(String s1, String s2) { int sum = 0; for (int i = 0; i < s1.length(); i++) sum += s1.charAt(i); for (int i = 0; i < s2.length(); i++) sum += s2.charAt(i); if (s1.length() == 0 || s2.length() == 0) return sum; int[][] dp = new int[s1.length() + 1][s2.length() + 1]; int max_lcs_sum = 0; for (int i = 1; i <= s1.length(); i++) { for (int j = 1; j <= s2.length(); j++) { if (s1.charAt(i - 1) == s2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1] + s1.charAt(i - 1); } else { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } max_lcs_sum = Math.max(dp[i][j], max_lcs_sum); } } return sum - 2 * max_lcs_sum; }
-
279 完全平方數(shù):
給定正整數(shù) n,找到若干個(gè)完全平方數(shù)(比如 1, 4, 9, 16, ...)使得它們的和等于 n。你需要讓組成和的完全平方數(shù)的個(gè)數(shù)最少。 示例 1: 輸入: n = 12 輸出: 3 解釋: 12 = 4 + 4 + 4.
//最小值公式f(n)=常數(shù)i+j*j (需要滿足條件i-j*j>=0,不能越界) //而f(j*j)=1 //所以f(n)=f(i)+f(j*j)=f(i)+1 //bfs遍歷所有可能的i j組合 //取每次遍歷的最小值情況 //dp[i]=Math.min(dp[i],dp[i-j*j]+dp[j*j]); public int numSquares(int n) { int[] dp = new int[n + 1]; for (int i = 0; i <= n; i++) { //默認(rèn)的每個(gè)數(shù)都是由全部1組成 dp[i] = i; //bfs操作 for (int j = 0; i - j * j >= 0; j++) { dp[i] = Math.min(dp[i], dp[i - j * j] + 1); } } return dp[n]; }
-
376,擺動(dòng)序列(線性DP)
public int wiggleMaxLength(int[] nums) { if(nums.length<2) return nums.length; int low = 1; int high = 1; for (int i = 1; i < nums.length; i++) { //起始位高低位都為1. //保證了在連續(xù)上升/下降的情況下 high/low 不會(huì)重復(fù)遞增, //在上升情況中,只要沒有發(fā)生坡度中斷,則high對(duì)應(yīng)的low不會(huì)發(fā)生改變。那么high位就不會(huì)發(fā)生改變。 if (nums[i] > nums[i - 1]) high = low+1; if (nums[i] < nums[i - 1]) low = high+1; } return Math.max(low, high); }
-
漢諾塔問題(每次移動(dòng)頂部的,并且不能大壓小)
public void hanoti(int N,String from,String to,String help){ if(N==1) System.out.println("Move 1 from" + from + "to" +to ); else{ hanoti(N-1,from,help,to); System.out.println("Move"+N+"from" + from + "to" +to ); hanoti(N-1,help,to,from); } }
-
502題IPO
public int findMaximizedCapital(int k, int W, int[] Profits, int[] Capital) { IpoNode[] ipoNodes = new IpoNode[Profits.length]; PriorityQueue<IpoNode> MinCostHeap = new PriorityQueue<>(comparingInt(o -> o.cost)); PriorityQueue<IpoNode> MaxProfitHeap = new PriorityQueue<>(comparingInt(o -> -o.profit)); for (int i = 0; i < ipoNodes.length; i++) { ipoNodes[i] = new IpoNode(Capital[i], Profits[i]); MinCostHeap.add(ipoNodes[i]); } for (int i = 0; i < k; i++) { while (MinCostHeap.size() > 0 && MinCostHeap.peek().cost <= W) MaxProfitHeap.add(MinCostHeap.poll()); if (MaxProfitHeap.size() > 0) W += MaxProfitHeap.poll().profit; } return W; } class IpoNode { public int cost; public int profit; public IpoNode(int cost, int profit) { this.cost = cost; this.profit = profit; } }
-
1277 統(tǒng)計(jì)全為1的正方形子矩陣:
-
核心在于加上每次的邊長(zhǎng) 因?yàn)楫?dāng)出現(xiàn)長(zhǎng)的邊長(zhǎng),說明以該右下角為正方形幾個(gè)新的小正方形也同時(shí)出現(xiàn)了, 比如3, res+3意味著加了邊長(zhǎng)為3和邊長(zhǎng)為2和邊長(zhǎng)為1這三個(gè)正方形。
class Solution { public int countSquares(int[][] matrix) { if (matrix == null || matrix.length == 0) return 0; int m = matrix.length; int n = matrix[0].length; int[][] dp = new int[m][n]; int res = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (matrix[i][j] == 1 && (i == 0 || j == 0)) { dp[i][j] = 1; } else if (matrix[i][j] == 1) { dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])); } //直接將每一個(gè)正方形的邊長(zhǎng)加上來 res += dp[i][j]; } } return res; } }
-
-
894,所有可能的滿二叉樹
public List<TreeNode> allPossibleFBT(int N) { List<TreeNode> res = new ArrayList<TreeNode>(); if(N % 2 == 0){ return res; } if(N == 1){ res.add(new TreeNode(0)); return res; } //對(duì)每個(gè)奇數(shù) //一個(gè)奇數(shù)拆成兩個(gè)奇數(shù)+1 for(int i = 1; i < N; i += 2){ List<TreeNode> lt = allPossibleFBT(i); List<TreeNode> rt = allPossibleFBT(N - 1 - i); //每種可能性都加進(jìn)來 for(TreeNode l : lt){ for(TreeNode r : rt){ TreeNode root = new TreeNode(0); root.left = l; root.right = r; res.add(root); } } } return res; }
-
1079 活字印刷:
你有一套活字字模 tiles,其中每個(gè)字模上都刻有一個(gè)字母 tiles[i]。返回你可以印出的非空字母序列的數(shù)目。 示例 1: 輸入:"AAB" 輸出:8 解釋:可能的序列為 "A", "B", "AA", "AB", "BA", "AAB", "ABA", "BAA"。
分而治之
-
23 合并K個(gè)排序鏈表
合并 k 個(gè)排序鏈表,返回合并后的排序鏈表。請(qǐng)分析和描述算法的復(fù)雜度。 示例: 輸入: [ 1->4->5, 1->3->4, 2->6 ] 輸出: 1->1->2->3->4->4->5->6
public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) return null; if (lists.length == 1) return lists[0]; if (lists.length == 2) return mergeTwoListNode(lists[0], lists[1]); int mid = lists.length / 2; ListNode[] leftArr = new ListNode[mid]; ListNode[] rightArr = new ListNode[lists.length - mid]; for (int i = 0; i < lists.length; i++) { if (i < mid) { leftArr[i] = lists[i]; } else { rightArr[i - mid] = lists[i]; } } //左右分治,最終變成兩個(gè)listNode合并 return mergeTwoListNode(mergeKLists(leftArr), mergeKLists(rightArr)); } //遞歸合并兩個(gè)ListNode public ListNode mergeTwoListNode(ListNode l1, ListNode l2) { if (l1 == null) return l2; if (l2 == null) return l1; ListNode cur; if (l1.val < l2.val) { cur = l1; cur.next = mergeTwoListNode(l1.next, l2); } else { cur = l2; cur.next = mergeTwoListNode(l1, l2.next); } return cur; }
-
不用加減乘除做加法:
a+b==> (a&b)<<1+a^b
(異或就相當(dāng)于沒有進(jìn)位的加法,而&就是尋找進(jìn)位,<<1左移動(dòng)1是表明與的值為進(jìn)位在二進(jìn)制加法中向前一位)
//當(dāng)a==0的時(shí)候說明沒有進(jìn)位 public int add(int a, int b) { if(a==0) return b; return add((a&b)<<1,b^a); }
動(dòng)態(tài)規(guī)劃
-
lc 264 丑數(shù) 三指針:
public int nthUglyNumber(int n) { if (n == 0) return 1; int[] dp = new int[n]; dp[0] = 1; int l_2 = 0, l_3 = 0, l_5 = 0; for (int i = 1; i < n; i++) { dp[i] = Math.min(dp[l_2] * 2, Math.min(dp[l_3] * 3, dp[l_5] * 5)); if (dp[i] == dp[l_2] * 2) l_2++; if (dp[i] == dp[l_3] * 3) l_3++; if (dp[i] == dp[l_5] * 5) l_5++; } return dp[n - 1]; }
-
lc 309 最佳買賣股票世紀(jì)含冷凍期:
# sold rest hold 分別表示在該price 所持有的收益 class Solution: def maxProfit(self, prices: List[int]) -> int: sold=0 rest=0 hold=-2147383648 for price in prices: pre_sold=sold # 今天賣出的的收益 sold=hold+price # 當(dāng)天是否買入,前一天的持有與之前的冷凍期收益減掉price hold = max(hold, rest - price); #當(dāng)天冷凍,取之前的冷凍的那天值和前一天pre_sold的比較值,保證了冷凍一定是在上次銷售之后 rest = max(rest, pre_sold); return max(sold,rest)
-
lc123 最佳買賣股票,次數(shù)限制:
public int maxProfit(int[] prices) { if (prices == null || prices.length < 2) return 0; int[][][] dp = new int[prices.length+1][3][2]; //base case for (int i = 0; i < 3; i++) { dp[0][i][0] = 0; dp[0][i][1] = Integer.MIN_VALUE; } for (int i = 1; i <= prices.length; i++) { for (int j = 1; j < 3; j++) { dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i-1]); dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j-1][0] - prices[i-1]); } } return dp[prices.length][2][0]; }
-
lc309 股票買賣,含冷凍期:
public int maxProfit(int[] prices) { if(prices==null||prices.length==0) return 0; int[][] dp = new int[prices.length][2]; dp[0][0] = 0; dp[0][1] = -prices[0]; for (int i = 1; i < prices.length; i++) { if (i == 1) dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); //-2表示相鄰那天不能交易 else dp[i][1] = Math.max(dp[i - 1][1], dp[i - 2][0] - prices[i]); dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); } return dp[prices.length - 1][0]; }
-
迭代實(shí)現(xiàn)中序遍歷:
public List<Integer> inorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<>(); Stack<TreeNode> stack = new Stack<>(); while (root != null || !stack.isEmpty()) { if (root != null) { stack.push(root); root = root.left; } else { root = stack.pop(); res.add(root.val); root = root.right; } } return res; }