mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 00:43:04 +08:00
Merge branch 'master' of https://github.com/youngyangyang04/leetcode
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
|
||||
</p>
|
||||
<p align="center"><strong>欢迎大家<a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
|
||||
|
||||
# 排列问题(二)
|
||||
|
||||
## 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
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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];
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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];
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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];
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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;i<len(nums);i++{
|
||||
//分两种情况判断:一,当前取的元素小于子集的最后一个元素,则继续寻找下一个适合的元素
|
||||
// 或者二,当前取的元素在本层已经出现过了,所以跳过该元素,继续寻找
|
||||
if len(subRes)>0&&nums[i]<subRes[len(subRes)-1]||history[nums[i] + 100]==1{
|
||||
continue
|
||||
}
|
||||
history[nums[i] + 100]=1//表示本层该元素使用过了
|
||||
subRes=append(subRes,nums[i])
|
||||
backTring(i+1,nums,subRes,res)
|
||||
subRes=subRes[:len(subRes)-1]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Javascript:
|
||||
|
||||
```Javascript
|
||||
|
@ -185,3 +185,26 @@ public:
|
||||
|
||||
建议大家把情况一二三想清楚了,先写出版本一的代码,然后在其基础上在做精简!
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
Python:
|
||||
```python3
|
||||
class Solution:
|
||||
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> 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
|
||||
```
|
||||
|
||||
|
@ -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];
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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:
|
||||
> 中序遍历,然后计算最小差值
|
||||
|
@ -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:
|
||||
|
||||
> 暴力法
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
## 1143.最长公共子序列
|
||||
|
||||
题目链接: https://leetcode-cn.com/problems/longest-common-subsequence/
|
||||
|
||||
给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列的长度。
|
||||
|
||||
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user