diff --git a/problems/0047.全排列II.md b/problems/0047.全排列II.md index 079ca834..b6c12919 100644 --- a/problems/0047.全排列II.md +++ b/problems/0047.全排列II.md @@ -5,6 +5,7 @@

欢迎大家参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ # 排列问题(二) ## 47.全排列 II @@ -222,6 +223,43 @@ class Solution: return res ``` +Go: + +```go +var res [][]int +func permute(nums []int) [][]int { + res = [][]int{} + sort.Ints(nums) + dfs(nums, make([]int, 0), make([]bool, len(nums))) + return res +} + +func dfs(nums, path []int, used []bool) { + if len(path) == len(nums) { + res = append(res, append([]int{}, path...)) + return + } + + m := make(map[int]bool) + for i := 0; i < len(nums); i++ { + // used 从剩余 nums 中选 + if used[i] { + continue + } + // m 集合间去重 + if _, ok := m[nums[i]]; ok { + continue + } + m[nums[i]] = true + path = append(path, nums[i]) + used[i] = true + dfs(nums, path, used) + used[i] = false + path = path[:len(path)-1] + } +} +``` + Javascript: ```javascript diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md index a04ebc0c..248d10f1 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -344,7 +344,7 @@ Python: # self.val = val # self.left = left # self.right = right -//递归法 +# 递归法 class Solution: def isValidBST(self, root: TreeNode) -> bool: res = [] //把二叉搜索树按中序遍历写成list @@ -356,6 +356,35 @@ class Solution: return res buildalist(root) return res == sorted(res) and len(set(res)) == len(res) //检查list里的数有没有重复元素,以及是否按从小到大排列 + +# 简单递归法 +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + def isBST(root, min_val, max_val): + if not root: return True + if root.val >= max_val or root.val <= min_val: + return False + return isBST(root.left, min_val, root.val) and isBST(root.right, root.val, max_val) + return isBST(root, float("-inf"), float("inf")) + +# 迭代-中序遍历 +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + stack = [] + cur = root + pre = None + while cur or stack: + if cur: # 指针来访问节点,访问到最底层 + stack.append(cur) + cur = cur.left + else: # 逐一处理节点 + cur = stack.pop() + if pre and cur.val <= pre.val: # 比较当前节点和前节点的值的大小 + return False + pre = cur + cur = cur.right + return True + ``` Go: ```Go diff --git a/problems/0123.买卖股票的最佳时机III.md b/problems/0123.买卖股票的最佳时机III.md index fccb187d..7ff1bfe2 100644 --- a/problems/0123.买卖股票的最佳时机III.md +++ b/problems/0123.买卖股票的最佳时机III.md @@ -193,35 +193,49 @@ dp[1] = max(dp[1], dp[0] - prices[i]); 如果dp[1]取dp[1],即保持买入股 Java: ```java -class Solution { // 动态规划 +// 版本一 +class Solution { public int maxProfit(int[] prices) { - // 可交易次数 - int k = 2; + int len = prices.length; + // 边界判断, 题目中 length >= 1, 所以可省去 + if (prices.length == 0) return 0; - // [天数][交易次数][是否持有股票] - int[][][] dp = new int[prices.length][k + 1][2]; + /* + * 定义 5 种状态: + * 0: 没有操作, 1: 第一次买入, 2: 第一次卖出, 3: 第二次买入, 4: 第二次卖出 + */ + int[][] dp = new int[len][5]; + dp[0][1] = -prices[0]; + // 初始化第二次买入的状态是确保 最后结果是最多两次买卖的最大利润 + dp[0][3] = -prices[0]; - // badcase - dp[0][0][0] = 0; - dp[0][0][1] = Integer.MIN_VALUE; - dp[0][1][0] = 0; - dp[0][1][1] = -prices[0]; - dp[0][2][0] = 0; - dp[0][2][1] = Integer.MIN_VALUE; - - for (int i = 1; i < prices.length; i++) { - for (int j = 2; j >= 1; j--) { - // dp公式 - dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]); - dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]); - } + for (int i = 1; i < len; i++) { + dp[i][1] = Math.max(dp[i - 1][1], -prices[i]); + dp[i][2] = Math.max(dp[i - 1][2], dp[i][1] + prices[i]); + dp[i][3] = Math.max(dp[i - 1][3], dp[i][2] - prices[i]); + dp[i][4] = Math.max(dp[i - 1][4], dp[i][3] + prices[i]); } - int res = 0; - for (int i = 1; i < 3; i++) { - res = Math.max(res, dp[prices.length - 1][i][0]); + return dp[len - 1][4]; + } +} + +// 版本二: 空间优化 +class Solution { + public int maxProfit(int[] prices) { + int len = prices.length; + int[] dp = new int[5]; + dp[1] = -prices[0]; + dp[3] = -prices[0]; + + for (int i = 1; i < len; i++) { + dp[1] = Math.max(dp[1], dp[0] - prices[i]); + dp[2] = Math.max(dp[2], dp[1] + prices[i]); + dp[3] = Math.max(dp[3], dp[2] - prices[i]); + dp[4] = Math.max(dp[4], dp[3] + prices[i]); } - return res; + + return dp[4]; } } ``` diff --git a/problems/0139.单词拆分.md b/problems/0139.单词拆分.md index b6a6242e..59892ef9 100644 --- a/problems/0139.单词拆分.md +++ b/problems/0139.单词拆分.md @@ -291,6 +291,27 @@ func wordBreak(s string,wordDict []string) bool { } ``` +Javascript: +```javascript +const wordBreak = (s, wordDict) => { + + let dp = Array(s.length + 1).fill(false); + dp[0] = true; + + for(let i = 0; i <= s.length; i++){ + for(let j = 0; j < wordDict.length; j++) { + if(i >= wordDict[j].length) { + if(s.slice(i - wordDict[j].length, i) === wordDict[j] && dp[i - wordDict[j].length]) { + dp[i] = true + } + } + } + } + + return dp[s.length]; +} +``` + ----------------------- diff --git a/problems/0188.买卖股票的最佳时机IV.md b/problems/0188.买卖股票的最佳时机IV.md index 431c292b..d1ca8a8d 100644 --- a/problems/0188.买卖股票的最佳时机IV.md +++ b/problems/0188.买卖股票的最佳时机IV.md @@ -170,41 +170,54 @@ public: Java: ```java -class Solution { //动态规划 +// 版本一: 三维 dp数组 +class Solution { public int maxProfit(int k, int[] prices) { - if (prices == null || prices.length < 2 || k == 0) { - return 0; + if (prices.length == 0) return 0; + + // [天数][交易次数][是否持有股票] + int len = prices.length; + int[][][] dp = new int[len][k + 1][2]; + + // dp数组初始化 + // 初始化所有的交易次数是为确保 最后结果是最多 k 次买卖的最大利润 + for (int i = 0; i <= k; i++) { + dp[0][i][1] = -prices[0]; } - // [天数][交易次数][是否持有股票] - int[][][] dp = new int[prices.length][k + 1][2]; - - // bad case - dp[0][0][0] = 0; - dp[0][0][1] = Integer.MIN_VALUE; - dp[0][1][0] = 0; - dp[0][1][1] = -prices[0]; - // dp[0][j][0] 都均为0 - // dp[0][j][1] 异常值都取Integer.MIN_VALUE; - for (int i = 2; i < k + 1; i++) { - dp[0][i][0] = 0; - dp[0][i][1] = Integer.MIN_VALUE; - } - - for (int i = 1; i < prices.length; i++) { - for (int j = k; j >= 1; j--) { - // dp公式 + for (int i = 1; i < len; i++) { + for (int j = 1; j <= k; j++) { + // dp方程, 0表示不持有/卖出, 1表示持有/买入 dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]); dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]); } } + return dp[len - 1][k][0]; + } +} - int res = 0; - for (int i = 1; i < k + 1; i++) { - res = Math.max(res, dp[prices.length - 1][i][0]); +// 版本二: 空间优化 +class Solution { + public int maxProfit(int k, int[] prices) { + if (prices.length == 0) return 0; + + // [天数][股票状态] + // 股票状态: 奇数表示第 k 次交易持有/买入, 偶数表示第 k 次交易不持有/卖出, 0 表示没有操作 + int len = prices.length; + int[][] dp = new int[len][k*2 + 1]; + + // dp数组的初始化, 与版本一同理 + for (int i = 1; i < k*2; i += 2) { + dp[0][i] = -prices[0]; } - return res; + for (int i = 1; i < len; i++) { + for (int j = 0; j < k*2 - 1; j += 2) { + dp[i][j + 1] = Math.max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]); + dp[i][j + 2] = Math.max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]); + } + } + return dp[len - 1][k*2]; } } ``` diff --git a/problems/0322.零钱兑换.md b/problems/0322.零钱兑换.md index cf537088..302ae789 100644 --- a/problems/0322.零钱兑换.md +++ b/problems/0322.零钱兑换.md @@ -304,6 +304,26 @@ func min(a, b int) int { ``` +Javascript: +```javascript +const coinChange = (coins, amount) => { + if(!amount) { + return 0; + } + + let dp = Array(amount + 1).fill(Infinity); + dp[0] = 0; + + for(let i =0; i < coins.length; i++) { + for(let j = coins[i]; j <= amount; j++) { + dp[j] = Math.min(dp[j - coins[i]] + 1, dp[j]); + } + } + + return dp[amount] === Infinity ? -1 : dp[amount]; +} +``` + ----------------------- diff --git a/problems/0377.组合总和Ⅳ.md b/problems/0377.组合总和Ⅳ.md index d0394706..2ee009b3 100644 --- a/problems/0377.组合总和Ⅳ.md +++ b/problems/0377.组合总和Ⅳ.md @@ -201,6 +201,25 @@ func combinationSum4(nums []int, target int) int { } ``` +Javascript: +```javascript +const combinationSum4 = (nums, target) => { + + let dp = Array(target + 1).fill(0); + dp[0] = 1; + + for(let i = 0; i <= target; i++) { + for(let j = 0; j < nums.length; j++) { + if (i >= nums[j]) { + dp[i] += dp[i - nums[j]]; + } + } + } + + return dp[target]; +}; +``` + ----------------------- diff --git a/problems/0474.一和零.md b/problems/0474.一和零.md index fd925f76..6b73c080 100644 --- a/problems/0474.一和零.md +++ b/problems/0474.一和零.md @@ -244,6 +244,35 @@ func max(a,b int) int { } ``` +Javascript: +```javascript +const findMaxForm = (strs, m, n) => { + const dp = Array.from(Array(m+1), () => Array(n+1).fill(0)); + let numOfZeros, numOfOnes; + + for(let str of strs) { + numOfZeros = 0; + numOfOnes = 0; + + for(let c of str) { + if (c === '0') { + numOfZeros++; + } else { + numOfOnes++; + } + } + + for(let i = m; i >= numOfZeros; i--) { + for(let j = n; j >= numOfOnes; j--) { + dp[i][j] = Math.max(dp[i][j], dp[i - numOfZeros][j - numOfOnes] + 1); + } + } + } + + return dp[m][n]; +}; +``` + ----------------------- diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md index 85c9d307..103b8b10 100644 --- a/problems/0491.递增子序列.md +++ b/problems/0491.递增子序列.md @@ -257,6 +257,34 @@ class Solution: Go: +```golang +func findSubsequences(nums []int) [][]int { + var subRes []int + var res [][]int + backTring(0,nums,subRes,&res) + return res +} +func backTring(startIndex int,nums,subRes []int,res *[][]int){ + if len(subRes)>1{ + tmp:=make([]int,len(subRes)) + copy(tmp,subRes) + *res=append(*res,tmp) + } + history:=[201]int{}//记录本层元素使用记录 + for i:=startIndex;i0&&nums[i] List[int]: + result = [-1]*len(nums1) + stack = [0] + for i in range(1,len(nums2)): + # 情况一情况二 + if nums2[i]<=nums2[stack[-1]]: + stack.append(i) + # 情况三 + else: + while len(stack)!=0 and nums2[i]>nums2[stack[-1]]: + if nums2[stack[-1]] in nums1: + index = nums1.index(nums2[stack[-1]]) + result[index]=nums2[i] + stack.pop() + stack.append(i) + return result +``` + diff --git a/problems/0518.零钱兑换II.md b/problems/0518.零钱兑换II.md index 08043ea3..3f907da9 100644 --- a/problems/0518.零钱兑换II.md +++ b/problems/0518.零钱兑换II.md @@ -243,6 +243,22 @@ func change(amount int, coins []int) int { } ``` +Javascript: +```javascript +const change = (amount, coins) => { + let dp = Array(amount + 1).fill(0); + dp[0] = 1; + + for(let i =0; i < coins.length; i++) { + for(let j = coins[i]; j <= amount; j++) { + dp[j] += dp[j - coins[i]]; + } + } + + return dp[amount]; +} +``` + ----------------------- diff --git a/problems/0530.二叉搜索树的最小绝对差.md b/problems/0530.二叉搜索树的最小绝对差.md index 47b2b434..bf646443 100644 --- a/problems/0530.二叉搜索树的最小绝对差.md +++ b/problems/0530.二叉搜索树的最小绝对差.md @@ -222,6 +222,26 @@ class Solution: for i in range(len(res)-1): // 统计有序数组的最小差值 r = min(abs(res[i]-res[i+1]),r) return r + +# 迭代法-中序遍历 +class Solution: + def getMinimumDifference(self, root: TreeNode) -> int: + stack = [] + cur = root + pre = None + result = float('inf') + while cur or stack: + if cur: # 指针来访问节点,访问到最底层 + stack.append(cur) + cur = cur.left + else: # 逐一处理节点 + cur = stack.pop() + if pre: # 当前节点和前节点的值的差值 + result = min(result, cur.val - pre.val) + pre = cur + cur = cur.right + return result + ``` Go: > 中序遍历,然后计算最小差值 diff --git a/problems/0739.每日温度.md b/problems/0739.每日温度.md index e72fd6a4..8ad79fe3 100644 --- a/problems/0739.每日温度.md +++ b/problems/0739.每日温度.md @@ -211,7 +211,24 @@ Java: } ``` Python: - +``` Python3 +class Solution: + def dailyTemperatures(self, temperatures: List[int]) -> List[int]: + answer = [0]*len(temperatures) + stack = [0] + for i in range(1,len(temperatures)): + # 情况一和情况二 + if temperatures[i]<=temperatures[stack[-1]]: + stack.append(i) + # 情况三 + else: + while len(stack) != 0 and temperatures[i]>temperatures[stack[-1]]: + answer[stack[-1]]=i-stack[-1] + stack.pop() + stack.append(i) + + return answer +``` Go: > 暴力法 diff --git a/problems/1143.最长公共子序列.md b/problems/1143.最长公共子序列.md index 2ddab584..8e245c20 100644 --- a/problems/1143.最长公共子序列.md +++ b/problems/1143.最长公共子序列.md @@ -8,6 +8,8 @@ ## 1143.最长公共子序列 +题目链接: https://leetcode-cn.com/problems/longest-common-subsequence/ + 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 diff --git a/problems/背包问题理论基础完全背包.md b/problems/背包问题理论基础完全背包.md index a5a708cf..1ad09c4b 100644 --- a/problems/背包问题理论基础完全背包.md +++ b/problems/背包问题理论基础完全背包.md @@ -176,9 +176,48 @@ int main() { ## 其他语言版本 - Java: +```java + //先遍历物品,再遍历背包 + private static void testCompletePack(){ + int[] weight = {1, 3, 4}; + int[] value = {15, 20, 30}; + int bagWeight = 4; + int[] dp = new int[bagWeight + 1]; + for (int i = 0; i < weight.length; i++){ + for (int j = 1; j <= bagWeight; j++){ + if (j - weight[i] >= 0){ + dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]); + } + } + } + for (int maxValue : dp){ + System.out.println(maxValue + " "); + } + } + + //先遍历背包,再遍历物品 + private static void testCompletePackAnotherWay(){ + int[] weight = {1, 3, 4}; + int[] value = {15, 20, 30}; + int bagWeight = 4; + int[] dp = new int[bagWeight + 1]; + for (int i = 1; i <= bagWeight; i++){ + for (int j = 0; j < weight.length; j++){ + if (i - weight[j] >= 0){ + dp[i] = Math.max(dp[i], dp[i - weight[j]] + value[j]); + } + } + } + for (int maxValue : dp){ + System.out.println(maxValue + " "); + } + } +``` + + + Python: ```python3