mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-06 23:28:29 +08:00
Merge branch 'master' of github.com:youngyangyang04/leetcode-master
This commit is contained in:
@ -615,6 +615,68 @@ char * longestPalindrome(char * s){
|
||||
}
|
||||
```
|
||||
|
||||
C#:
|
||||
|
||||
動態規則:
|
||||
```c#
|
||||
public class Solution {
|
||||
|
||||
public string LongestPalindrome(string s) {
|
||||
bool[,] dp = new bool[s.Length, s.Length];
|
||||
int maxlenth = 0;
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
for(int i = s.Length-1 ; i>=0; i--){
|
||||
for(int j = i; j <s.Length;j++){
|
||||
if(s[i] == s[j]){
|
||||
if(j - i <= 1){ // 情况一和情况二
|
||||
dp[i, j] = true;
|
||||
}else if( dp[i+1, j-1] ){ // 情况三
|
||||
dp[i, j] = true;
|
||||
}
|
||||
}
|
||||
if(dp[i, j] && j-i+1 > maxlenth){
|
||||
maxlenth = j-i+1;
|
||||
left = i;
|
||||
right = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.Substring(left, maxlenth);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
雙指針:
|
||||
```C#
|
||||
public class Solution {
|
||||
int maxlenth = 0;
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
|
||||
public string LongestPalindrome(string s) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < s.Length; i++) {
|
||||
extend(s, i, i, s.Length); // 以i為中心
|
||||
extend(s, i, i + 1, s.Length); // 以i和i+1為中心
|
||||
}
|
||||
return s.Substring(left, maxlenth);
|
||||
}
|
||||
|
||||
private void extend(string s, int i, int j, int n) {
|
||||
while (i >= 0 && j < n && s[i] == s[j]) {
|
||||
if (j - i + 1 > maxlenth) {
|
||||
left = i;
|
||||
right = j;
|
||||
maxlenth = j - i + 1;
|
||||
}
|
||||
i--;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -207,24 +207,26 @@ class Solution:
|
||||
```
|
||||
|
||||
### Go
|
||||
```golang
|
||||
```go
|
||||
func merge(intervals [][]int) [][]int {
|
||||
//先从小到大排序
|
||||
sort.Slice(intervals,func(i,j int)bool{
|
||||
return intervals[i][0]<intervals[j][0]
|
||||
sort.Slice(intervals, func(i, j int) bool {
|
||||
return intervals[i][0] < intervals[j][0]
|
||||
})
|
||||
//再弄重复的
|
||||
for i:=0;i<len(intervals)-1;i++{
|
||||
if intervals[i][1]>=intervals[i+1][0]{
|
||||
intervals[i][1]=max(intervals[i][1],intervals[i+1][1])//赋值最大值
|
||||
intervals=append(intervals[:i+1],intervals[i+2:]...)
|
||||
i--
|
||||
res := make([][]int, 0, len(intervals))
|
||||
left, right := intervals[0][0], intervals[0][1]
|
||||
for i := 1; i < len(intervals); i++ {
|
||||
if right < intervals[i][0] {
|
||||
res = append(res, []int{left, right})
|
||||
left, right = intervals[i][0], intervals[i][1]
|
||||
} else {
|
||||
right = max(right, intervals[i][1])
|
||||
}
|
||||
}
|
||||
return intervals
|
||||
res = append(res, []int{left, right}) // 将最后一个区间放入
|
||||
return res
|
||||
}
|
||||
func max(a,b int)int{
|
||||
if a>b{
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
|
@ -69,7 +69,7 @@ dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索
|
||||
|
||||
**dp[i] : 1到i为节点组成的二叉搜索树的个数为dp[i]**。
|
||||
|
||||
也可以理解是i的不同元素节点组成的二叉搜索树的个数为dp[i] ,都是一样的。
|
||||
也可以理解是i个不同元素节点组成的二叉搜索树的个数为dp[i] ,都是一样的。
|
||||
|
||||
以下分析如果想不清楚,就来回想一下dp[i]的定义
|
||||
|
||||
@ -199,11 +199,11 @@ class Solution:
|
||||
### Go
|
||||
```Go
|
||||
func numTrees(n int)int{
|
||||
dp:=make([]int,n+1)
|
||||
dp[0]=1
|
||||
for i:=1;i<=n;i++{
|
||||
for j:=1;j<=i;j++{
|
||||
dp[i]+=dp[j-1]*dp[i-j]
|
||||
dp := make([]int, n+1)
|
||||
dp[0] = 1
|
||||
for i := 1; i <= n; i++ {
|
||||
for j := 1; j <= i; j++ {
|
||||
dp[i] += dp[j-1] * dp[i-j]
|
||||
}
|
||||
}
|
||||
return dp[n]
|
||||
|
@ -384,6 +384,34 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
## rust
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn lowest_common_ancestor(
|
||||
root: Option<Rc<RefCell<TreeNode>>>,
|
||||
p: Option<Rc<RefCell<TreeNode>>>,
|
||||
q: Option<Rc<RefCell<TreeNode>>>,
|
||||
) -> Option<Rc<RefCell<TreeNode>>> {
|
||||
if root == p || root == q || root.is_none() {
|
||||
return root;
|
||||
}
|
||||
let left = Self::lowest_common_ancestor(
|
||||
root.as_ref().unwrap().borrow().left.clone(),
|
||||
p.clone(),
|
||||
q.clone(),
|
||||
);
|
||||
let right =
|
||||
Self::lowest_common_ancestor(root.as_ref().unwrap().borrow().right.clone(), p, q);
|
||||
match (&left, &right) {
|
||||
(None, Some(_)) => right,
|
||||
(Some(_), Some(_)) => root,
|
||||
_ => left,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -235,43 +235,6 @@ class Solution:
|
||||
return dp[n]
|
||||
```
|
||||
|
||||
Python3:
|
||||
```python
|
||||
class Solution:
|
||||
'''版本一,先遍历背包, 再遍历物品'''
|
||||
def numSquares(self, n: int) -> int:
|
||||
dp = [n] * (n + 1)
|
||||
dp[0] = 0
|
||||
# 遍历背包
|
||||
for j in range(1, n+1):
|
||||
for i in range(1, n):
|
||||
num = i ** 2
|
||||
if num > j: break
|
||||
# 遍历物品
|
||||
if j - num >= 0:
|
||||
dp[j] = min(dp[j], dp[j - num] + 1)
|
||||
return dp[n]
|
||||
|
||||
class Solution:
|
||||
'''版本二, 先遍历物品, 再遍历背包'''
|
||||
def numSquares(self, n: int) -> int:
|
||||
# 初始化
|
||||
# 组成和的完全平方数的最多个数,就是只用1构成
|
||||
# 因此,dp[i] = i
|
||||
dp = [i for i in range(n + 1)]
|
||||
# dp[0] = 0 无意义,只是为了方便记录特殊情况:
|
||||
# n本身就是完全平方数,dp[n] = min(dp[n], dp[n - n] + 1) = 1
|
||||
|
||||
for i in range(1, n): # 遍历物品
|
||||
if i * i > n:
|
||||
break
|
||||
num = i * i
|
||||
for j in range(num, n + 1): # 遍历背包
|
||||
dp[j] = min(dp[j], dp[j - num] + 1)
|
||||
|
||||
return dp[n]
|
||||
```
|
||||
|
||||
Go:
|
||||
```go
|
||||
// 版本一,先遍历物品, 再遍历背包
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
## 思路
|
||||
|
||||
这道题目初步看,是如下两题几乎是一样的,大家可以用回溯法,解决如下两题
|
||||
这道题目初步看,和如下两题几乎是一样的,大家可以用回溯法,解决如下两题
|
||||
|
||||
* 698.划分为k个相等的子集
|
||||
* 473.火柴拼正方形
|
||||
@ -62,7 +62,7 @@
|
||||
|
||||
回归主题:首先,本题要求集合里能否出现总和为 sum / 2 的子集。
|
||||
|
||||
那么来一一对应一下本题,看看背包问题如果来解决。
|
||||
那么来一一对应一下本题,看看背包问题如何来解决。
|
||||
|
||||
**只有确定了如下四点,才能把01背包问题套到本题上来。**
|
||||
|
||||
@ -77,9 +77,9 @@
|
||||
|
||||
1. 确定dp数组以及下标的含义
|
||||
|
||||
01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值可以最大为dp[j]。
|
||||
01背包中,dp[j] 表示: 容量为j的背包,所背的物品价值最大可以为dp[j]。
|
||||
|
||||
本题中每一个元素的数值即是重量,也是价值。
|
||||
本题中每一个元素的数值既是重量,也是价值。
|
||||
|
||||
**套到本题,dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]**。
|
||||
|
||||
@ -106,9 +106,9 @@
|
||||
|
||||
从dp[j]的定义来看,首先dp[0]一定是0。
|
||||
|
||||
如果如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。
|
||||
如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。
|
||||
|
||||
**这样才能让dp数组在递归公式的过程中取的最大的价值,而不是被初始值覆盖了**。
|
||||
**这样才能让dp数组在递推的过程中取得最大的价值,而不是被初始值覆盖了**。
|
||||
|
||||
本题题目中 只包含正整数的非空数组,所以非0下标的元素初始化为0就可以了。
|
||||
|
||||
@ -202,15 +202,15 @@ class Solution {
|
||||
if(nums == null || nums.length == 0) return false;
|
||||
int n = nums.length;
|
||||
int sum = 0;
|
||||
for(int num : nums){
|
||||
for(int num : nums) {
|
||||
sum += num;
|
||||
}
|
||||
//总和为奇数,不能平分
|
||||
if(sum % 2 != 0) return false;
|
||||
int target = sum / 2;
|
||||
int[] dp = new int[target + 1];
|
||||
for(int i = 0; i < n; i++){
|
||||
for(int j = target; j >= nums[i]; j--){
|
||||
for(int i = 0; i < n; i++) {
|
||||
for(int j = target; j >= nums[i]; j--) {
|
||||
//物品 i 的重量是 nums[i],其价值也是 nums[i]
|
||||
dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);
|
||||
}
|
||||
@ -220,6 +220,7 @@ class Solution {
|
||||
}
|
||||
```
|
||||
|
||||
二维数组版本(易于理解):
|
||||
```java
|
||||
public class Solution {
|
||||
public static void main(String[] args) {
|
||||
@ -288,46 +289,6 @@ false true false false false true true false false false false true
|
||||
false true false false false true true false false false true true
|
||||
```
|
||||
|
||||
|
||||
二维数组版本(易于理解):
|
||||
```Java
|
||||
class Solution {
|
||||
public boolean canPartition(int[] nums) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
sum += nums[i];
|
||||
}
|
||||
|
||||
if (sum % 2 == 1)
|
||||
return false;
|
||||
int target = sum / 2;
|
||||
|
||||
//dp[i][j]代表可装物品为0-i,背包容量为j的情况下,背包内容量的最大价值
|
||||
int[][] dp = new int[nums.length][target + 1];
|
||||
|
||||
//初始化,dp[0][j]的最大价值nums[0](if j > weight[i])
|
||||
//dp[i][0]均为0,不用初始化
|
||||
for (int j = nums[0]; j <= target; j++) {
|
||||
dp[0][j] = nums[0];
|
||||
}
|
||||
|
||||
//遍历物品,遍历背包
|
||||
//递推公式:
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
for (int j = 0; j <= target; j++) {
|
||||
//背包容量可以容纳nums[i]
|
||||
if (j >= nums[i]) {
|
||||
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
|
||||
} else {
|
||||
dp[i][j] = dp[i - 1][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dp[nums.length - 1][target] == target;
|
||||
}
|
||||
}
|
||||
```
|
||||
### Python:
|
||||
```python
|
||||
class Solution:
|
||||
@ -341,6 +302,7 @@ class Solution:
|
||||
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
|
||||
return target == dp[target]
|
||||
```
|
||||
|
||||
### Go:
|
||||
```go
|
||||
// 分割等和子集 动态规划
|
||||
@ -369,46 +331,6 @@ func canPartition(nums []int) bool {
|
||||
}
|
||||
```
|
||||
|
||||
```go
|
||||
func canPartition(nums []int) bool {
|
||||
/**
|
||||
动态五部曲:
|
||||
1.确定dp数组和下标含义
|
||||
2.确定递推公式
|
||||
3.dp数组初始化
|
||||
4.dp遍历顺序
|
||||
5.打印
|
||||
**/
|
||||
//确定和
|
||||
var sum int
|
||||
for _,v:=range nums{
|
||||
sum+=v
|
||||
}
|
||||
if sum%2!=0{ //如果和为奇数,则不可能分成两个相等的数组
|
||||
return false
|
||||
}
|
||||
sum/=2
|
||||
//确定dp数组和下标含义
|
||||
var dp [][]bool //dp[i][j] 表示: 前i个石头是否总和不大于J
|
||||
//初始化数组
|
||||
dp=make([][]bool,len(nums)+1)
|
||||
for i,_:=range dp{
|
||||
dp[i]=make([]bool,sum+1)
|
||||
dp[i][0]=true
|
||||
}
|
||||
for i:=1;i<=len(nums);i++{
|
||||
for j:=1;j<=sum;j++{//j是固定总量
|
||||
if j>=nums[i-1]{//如果容量够用则可放入背包
|
||||
dp[i][j]=dp[i-1][j]||dp[i-1][j-nums[i-1]]
|
||||
}else{//如果容量不够用则不拿,维持前一个状态
|
||||
dp[i][j]=dp[i-1][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[len(nums)][sum]
|
||||
}
|
||||
```
|
||||
|
||||
### javaScript:
|
||||
|
||||
```js
|
||||
|
@ -62,9 +62,9 @@
|
||||
|
||||
每次取非交叉区间的时候,都是可右边界最小的来做分割点(这样留给下一个区间的空间就越大),所以第一条分割线就是区间1结束的位置。
|
||||
|
||||
接下来就是找大于区间1结束位置的区间,是从区间4开始。**那有同学问了为什么不从区间5开始?别忘已经是按照右边界排序的了**。
|
||||
接下来就是找大于区间1结束位置的区间,是从区间4开始。**那有同学问了为什么不从区间5开始?别忘了已经是按照右边界排序的了**。
|
||||
|
||||
区间4结束之后,在找到区间6,所以一共记录非交叉区间的个数是三个。
|
||||
区间4结束之后,再找到区间6,所以一共记录非交叉区间的个数是三个。
|
||||
|
||||
总共区间个数为6,减去非交叉区间的个数3。移除区间的最小数量就是3。
|
||||
|
||||
@ -183,23 +183,19 @@ public:
|
||||
```java
|
||||
class Solution {
|
||||
public int eraseOverlapIntervals(int[][] intervals) {
|
||||
Arrays.sort(intervals, (a, b) -> {
|
||||
// 按照区间右边界升序排序
|
||||
return a[1] - b[1];
|
||||
Arrays.sort(intervals, (a,b)-> {
|
||||
return Integer.compare(a[0],b[0]);
|
||||
});
|
||||
|
||||
int count = 0;
|
||||
int edge = Integer.MIN_VALUE;
|
||||
for (int i = 0; i < intervals.length; i++) {
|
||||
// 若上一个区间的右边界小于当前区间的左边界,说明无交集
|
||||
if (edge <= intervals[i][0]) {
|
||||
edge = intervals[i][1];
|
||||
} else {
|
||||
int count = 1;
|
||||
for(int i = 1;i < intervals.length;i++){
|
||||
if(intervals[i][0] < intervals[i-1][1]){
|
||||
intervals[i][1] = Math.min(intervals[i - 1][1], intervals[i][1]);
|
||||
continue;
|
||||
}else{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return intervals.length - count;
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -208,16 +204,15 @@ class Solution {
|
||||
```java
|
||||
class Solution {
|
||||
public int eraseOverlapIntervals(int[][] intervals) {
|
||||
|
||||
Arrays.sort(intervals,(a,b)->{
|
||||
Arrays.sort(intervals, (a,b)-> {
|
||||
return Integer.compare(a[0],b[0]);
|
||||
});
|
||||
int remove = 0;
|
||||
int pre = intervals[0][1];
|
||||
for(int i=1;i<intervals.length;i++){
|
||||
if(pre>intervals[i][0]) {
|
||||
for(int i = 1; i < intervals.length; i++) {
|
||||
if(pre > intervals[i][0]) {
|
||||
remove++;
|
||||
pre = Math.min(pre,intervals[i][1]);
|
||||
pre = Math.min(pre, intervals[i][1]);
|
||||
}
|
||||
else pre = intervals[i][1];
|
||||
}
|
||||
@ -242,27 +237,26 @@ class Solution:
|
||||
```
|
||||
|
||||
### Go
|
||||
```golang
|
||||
```go
|
||||
func eraseOverlapIntervals(intervals [][]int) int {
|
||||
var flag int
|
||||
//先排序
|
||||
sort.Slice(intervals,func(i,j int)bool{
|
||||
return intervals[i][0]<intervals[j][0]
|
||||
sort.Slice(intervals, func(i, j int) bool {
|
||||
return intervals[i][1] < intervals[j][1]
|
||||
})
|
||||
fmt.Println(intervals)
|
||||
for i:=1;i<len(intervals);i++{
|
||||
if intervals[i-1][1]>intervals[i][0]{
|
||||
flag++
|
||||
intervals[i][1]=min(intervals[i-1][1],intervals[i][1])//由于是先排序的,所以,第一位是递增顺序,故只需要将临近两个元素的第二个值最小值更新到该元素的第二个值即可作之后的判断
|
||||
res := 1
|
||||
for i := 1; i < len(intervals); i++ {
|
||||
if intervals[i][0] >= intervals[i-1][1] {
|
||||
res++
|
||||
} else {
|
||||
intervals[i][1] = min(intervals[i - 1][1], intervals[i][1])
|
||||
}
|
||||
}
|
||||
return flag
|
||||
return len(intervals) - res
|
||||
}
|
||||
func min(a,b int)int{
|
||||
if a>b{
|
||||
return b
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return a
|
||||
return b
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
||||
|
||||
但本题其实是01背包问题!
|
||||
|
||||
这不过这个背包有两个维度,一个是m 一个是n,而不同长度的字符串就是不同大小的待装物品。
|
||||
只不过这个背包有两个维度,一个是m 一个是n,而不同长度的字符串就是不同大小的待装物品。
|
||||
|
||||
开始动规五部曲:
|
||||
|
||||
@ -114,7 +114,7 @@ for (string str : strs) { // 遍历物品
|
||||
|
||||
有同学可能想,那个遍历背包容量的两层for循环先后循序有没有什么讲究?
|
||||
|
||||
没讲究,都是物品重量的一个维度,先遍历那个都行!
|
||||
没讲究,都是物品重量的一个维度,先遍历哪个都行!
|
||||
|
||||
5. 举例推导dp数组
|
||||
|
||||
@ -152,7 +152,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
不少同学刷过这道提,可能没有总结这究竟是什么背包。
|
||||
不少同学刷过这道题,可能没有总结这究竟是什么背包。
|
||||
|
||||
此时我们讲解了0-1背包的多种应用,
|
||||
|
||||
@ -252,53 +252,6 @@ func max(a,b int) int {
|
||||
return b
|
||||
}
|
||||
```
|
||||
> 传统背包,三维数组法
|
||||
```golang
|
||||
func findMaxForm(strs []string, m int, n int) int {
|
||||
//dp的第一个index代表项目的多少,第二个代表的是背包的容量
|
||||
//所以本处项目的多少是len(strs),容量为m和n
|
||||
dp:=make([][][]int,len(strs)+1)
|
||||
for i:=0;i<=len(strs);i++{
|
||||
//初始化背包容量
|
||||
strDp:=make([][]int,m+1)
|
||||
for j:=0;j<m+1;j++{
|
||||
tmp:=make([]int,n+1)
|
||||
strDp[j]=tmp
|
||||
}
|
||||
dp[i]=strDp
|
||||
}
|
||||
for k,value:=range strs{
|
||||
//统计每个字符串0和1的个数
|
||||
var zero,one int
|
||||
for _,v:=range value{
|
||||
if v=='0'{
|
||||
zero++
|
||||
}else{
|
||||
one++
|
||||
}
|
||||
}
|
||||
k+=1
|
||||
//计算dp
|
||||
for i:=0;i<=m;i++{
|
||||
for j:=0;j<=n;j++{
|
||||
//如果装不下
|
||||
dp[k][i][j]=dp[k-1][i][j]
|
||||
//如果装的下
|
||||
if i>=zero&&j>=one{
|
||||
dp[k][i][j]=getMax(dp[k-1][i][j],dp[k-1][i-zero][j-one]+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[len(strs)][m][n]
|
||||
}
|
||||
func getMax(a,b int)int{
|
||||
if a>b{
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
```
|
||||
|
||||
### Javascript
|
||||
```javascript
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
|
||||
x = (target + sum) / 2
|
||||
|
||||
**此时问题就转化为,装满容量为x背包,有几种方法**。
|
||||
**此时问题就转化为,装满容量为x的背包,有几种方法**。
|
||||
|
||||
这里的x,就是bagSize,也就是我们后面要求的背包容量。
|
||||
|
||||
@ -184,11 +184,11 @@ dp[j] += dp[j - nums[i]]
|
||||
|
||||
3. dp数组如何初始化
|
||||
|
||||
从递归公式可以看出,在初始化的时候dp[0] 一定要初始化为1,因为dp[0]是在公式中一切递推结果的起源,如果dp[0]是0的话,递归结果将都是0。
|
||||
从递推公式可以看出,在初始化的时候dp[0] 一定要初始化为1,因为dp[0]是在公式中一切递推结果的起源,如果dp[0]是0的话,递推结果将都是0。
|
||||
|
||||
这里有录友可能认为从dp数组定义来说 dp[0] 应该是0,也有录友认为dp[0]应该是1。
|
||||
|
||||
其实不要硬去解释它的含义,咱就把 dp[0]的情况带入本题看看就是应该等于多少。
|
||||
其实不要硬去解释它的含义,咱就把 dp[0]的情况带入本题看看应该等于多少。
|
||||
|
||||
如果数组[0] ,target = 0,那么 bagSize = (target + sum) / 2 = 0。 dp[0]也应该是1, 也就是说给数组里的元素 0 前面无论放加法还是减法,都是 1 种方法。
|
||||
|
||||
@ -198,7 +198,7 @@ dp[j] += dp[j - nums[i]]
|
||||
|
||||
其实 此时最终的dp[0] = 32,也就是这五个零 子集的所有组合情况,但此dp[0]非彼dp[0],dp[0]能算出32,其基础是因为dp[0] = 1 累加起来的。
|
||||
|
||||
dp[j]其他下标对应的数值也应该初始化为0,从递归公式也可以看出,dp[j]要保证是0的初始值,才能正确的由dp[j - nums[i]]推导出来。
|
||||
dp[j]其他下标对应的数值也应该初始化为0,从递推公式也可以看出,dp[j]要保证是0的初始值,才能正确的由dp[j - nums[i]]推导出来。
|
||||
|
||||
|
||||
4. 确定遍历顺序
|
||||
@ -245,7 +245,7 @@ public:
|
||||
|
||||
## 总结
|
||||
|
||||
此时 大家应该不仅想起,我们之前讲过的[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)是不是应该也可以用dp来做啊?
|
||||
此时 大家应该不禁想起,我们之前讲过的[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)是不是应该也可以用dp来做啊?
|
||||
|
||||
是的,如果仅仅是求个数的话,就可以用dp,但[回溯算法:39. 组合总和](https://programmercarl.com/0039.组合总和.html)要求的是把所有组合列出来,还是要使用回溯法爆搜的。
|
||||
|
||||
|
@ -837,6 +837,93 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
## rust
|
||||
|
||||
递归:
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn find_mode(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let mut count = 0;
|
||||
let mut max_count = 0;
|
||||
let mut res = vec![];
|
||||
let mut pre = i32::MIN;
|
||||
Self::search_bst(&root, &mut pre, &mut res, &mut count, &mut max_count);
|
||||
res
|
||||
}
|
||||
pub fn search_bst(
|
||||
cur: &Option<Rc<RefCell<TreeNode>>>,
|
||||
mut pre: &mut i32,
|
||||
res: &mut Vec<i32>,
|
||||
count: &mut i32,
|
||||
max_count: &mut i32,
|
||||
) {
|
||||
if cur.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let cur_node = cur.as_ref().unwrap().borrow();
|
||||
Self::search_bst(&cur_node.left, pre, res, count, max_count);
|
||||
if *pre == i32::MIN {
|
||||
*count = 1;
|
||||
} else if *pre == cur_node.val {
|
||||
*count += 1;
|
||||
} else {
|
||||
*count = 1;
|
||||
};
|
||||
match count.cmp(&max_count) {
|
||||
std::cmp::Ordering::Equal => res.push(cur_node.val),
|
||||
std::cmp::Ordering::Greater => {
|
||||
*max_count = *count;
|
||||
res.clear();
|
||||
res.push(cur_node.val);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
*pre = cur_node.val;
|
||||
Self::search_bst(&cur_node.right, pre, res, count, max_count);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
迭代:
|
||||
|
||||
```rust
|
||||
pub fn find_mode(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {
|
||||
let (mut cur, mut pre) = (root, i32::MIN);
|
||||
let mut res = vec![];
|
||||
let mut stack = vec![];
|
||||
let (mut count, mut max_count) = (0, 0);
|
||||
while !stack.is_empty() || cur.is_some() {
|
||||
while let Some(node) = cur {
|
||||
cur = node.borrow().left.clone();
|
||||
stack.push(node);
|
||||
}
|
||||
if let Some(node) = stack.pop() {
|
||||
if pre == i32::MIN {
|
||||
count = 1;
|
||||
} else if pre == node.borrow().val {
|
||||
count += 1;
|
||||
} else {
|
||||
count = 1;
|
||||
}
|
||||
match count.cmp(&max_count) {
|
||||
std::cmp::Ordering::Equal => res.push(node.borrow().val),
|
||||
std::cmp::Ordering::Greater => {
|
||||
max_count = count;
|
||||
res.clear();
|
||||
res.push(node.borrow().val);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
pre = node.borrow().val;
|
||||
cur = node.borrow().right.clone();
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
|
@ -493,6 +493,93 @@ object Solution {
|
||||
}
|
||||
```
|
||||
|
||||
## rust
|
||||
|
||||
构建二叉树的有序数组:
|
||||
|
||||
```rust
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
impl Solution {
|
||||
pub fn get_minimum_difference(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
let mut vec = vec![];
|
||||
Self::traversal(root, &mut vec);
|
||||
let mut min = i32::MAX;
|
||||
for i in 1..vec.len() {
|
||||
min = min.min(vec[i] - vec[i - 1])
|
||||
}
|
||||
min
|
||||
}
|
||||
pub fn traversal(root: Option<Rc<RefCell<TreeNode>>>, v: &mut Vec<i32>) {
|
||||
if root.is_none() {
|
||||
return;
|
||||
}
|
||||
let node = root.as_ref().unwrap().borrow();
|
||||
Self::traversal(node.left.clone(), v);
|
||||
v.push(node.val);
|
||||
Self::traversal(node.right.clone(), v);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
递归中解决
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn get_minimum_difference(root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
let mut pre = None;
|
||||
let mut min = i32::MAX;
|
||||
Self::inorder(root, &mut pre, &mut min);
|
||||
min
|
||||
}
|
||||
pub fn inorder(root: Option<Rc<RefCell<TreeNode>>>, pre: &mut Option<i32>, min: &mut i32) {
|
||||
if root.is_none() {
|
||||
return;
|
||||
}
|
||||
let node = root.as_ref().unwrap().borrow();
|
||||
Self::inorder(node.left.clone(), pre, min);
|
||||
if let Some(pre) = pre {
|
||||
*min = (node.val - *pre).min(*min);
|
||||
}
|
||||
*pre = Some(node.val);
|
||||
|
||||
Self::inorder(node.right.clone(), pre, min);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
迭代
|
||||
|
||||
```rust
|
||||
impl Solution {
|
||||
pub fn get_minimum_difference(mut root: Option<Rc<RefCell<TreeNode>>>) -> i32 {
|
||||
if root.is_none() {
|
||||
return 0;
|
||||
}
|
||||
let mut stack = vec![];
|
||||
let mut pre = -1;
|
||||
let mut res = i32::MAX;
|
||||
while root.is_some() || !stack.is_empty() {
|
||||
while let Some(node) = root {
|
||||
root = node.borrow().left.clone();
|
||||
stack.push(node);
|
||||
}
|
||||
|
||||
let node = stack.pop().unwrap();
|
||||
|
||||
if pre >= 0 {
|
||||
res = res.min(node.borrow().val - pre);
|
||||
}
|
||||
|
||||
pre = node.borrow().val;
|
||||
|
||||
root = node.borrow().right.clone();
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
|
@ -341,7 +341,7 @@ class Solution {
|
||||
if (node1.left == null && node2.left != null) {
|
||||
node1.left = node2.left;
|
||||
}
|
||||
// 若node2的左节点为空,直接赋值
|
||||
// 若node1的右节点为空,直接赋值
|
||||
if (node1.right == null && node2.right != null) {
|
||||
node1.right = node2.right;
|
||||
}
|
||||
@ -732,3 +732,4 @@ impl Solution {
|
||||
<a href="https://programmercarl.com/other/kstar.html" target="_blank">
|
||||
<img src="../pics/网站星球宣传海报.jpg" width="1000"/>
|
||||
</a>
|
||||
|
||||
|
@ -217,25 +217,25 @@ class Solution: # 贪心思路
|
||||
```
|
||||
|
||||
### Go
|
||||
```golang
|
||||
```go
|
||||
func maxProfit(prices []int, fee int) int {
|
||||
var minBuy int = prices[0] //第一天买入
|
||||
var res int
|
||||
for i:=0;i<len(prices);i++{
|
||||
for i := 0; i < len(prices); i++ {
|
||||
//如果当前价格小于最低价,则在此处买入
|
||||
if prices[i]<minBuy{
|
||||
minBuy=prices[i]
|
||||
if prices[i] < minBuy {
|
||||
minBuy = prices[i]
|
||||
}
|
||||
//如果以当前价格卖出亏本,则不卖,继续找下一个可卖点
|
||||
if prices[i]>=minBuy&&prices[i]-fee-minBuy<=0{
|
||||
if prices[i] >= minBuy && prices[i]-fee-minBuy <= 0 {
|
||||
continue
|
||||
}
|
||||
//可以售卖了
|
||||
if prices[i]>minBuy+fee{
|
||||
if prices[i] > minBuy+fee {
|
||||
//累加每天的收益
|
||||
res+=prices[i]-minBuy-fee
|
||||
res += prices[i]-minBuy-fee
|
||||
//更新最小值(如果还在收获利润的区间里,表示并不是真正的卖出,而计算利润每次都要减去手续费,所以要让minBuy = prices[i] - fee;,这样在明天收获利润的时候,才不会多减一次手续费!)
|
||||
minBuy=prices[i]-fee
|
||||
minBuy = prices[i]-fee
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
@ -179,7 +179,7 @@ class Solution:
|
||||
```
|
||||
|
||||
### Go
|
||||
```golang
|
||||
```go
|
||||
func monotoneIncreasingDigits(N int) int {
|
||||
s := strconv.Itoa(N)//将数字转为字符串,方便使用下标
|
||||
ss := []byte(s)//将字符串转为byte数组,方便更改。
|
||||
@ -187,10 +187,10 @@ func monotoneIncreasingDigits(N int) int {
|
||||
if n <= 1 {
|
||||
return N
|
||||
}
|
||||
for i:=n-1 ; i>0; i-- {
|
||||
if ss[i-1] > ss[i] {//前一个大于后一位,前一位减1,后面的全部置为9
|
||||
for i := n-1; i > 0; i-- {
|
||||
if ss[i-1] > ss[i] { //前一个大于后一位,前一位减1,后面的全部置为9
|
||||
ss[i-1] -= 1
|
||||
for j := i ; j < n; j++ {//后面的全部置为9
|
||||
for j := i; j < n; j++ { //后面的全部置为9
|
||||
ss[j] = '9'
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user