This commit is contained in:
programmercarl
2023-02-08 17:28:04 +08:00
parent d107b53a4a
commit 1ec9d9bcb4
22 changed files with 146 additions and 148 deletions

View File

@ -25,21 +25,15 @@
## 思路 ## 思路
大家应该都感觉到了,此题一定要排序,那么按照左边界排序,还是右边界排序呢? 本题的本质其实还是判断重叠区间问题。
都可以! 大家如果认真做题的话,话发现和我们刚刚讲过的[452. 用最少数量的箭引爆气球](https://programmercarl.com/0452.用最少数量的箭引爆气球.html) 和 [435. 无重叠区间](https://programmercarl.com/0435.无重叠区间.html) 都是一个套路。
那么我按照左边界排序,排序之后局部最优:每次合并都取最大的右边界,这样就可以合并更多的区间了,整体最优:合并所有重叠的区间。 这几道题都是判断区间重叠,区别就是判断区间重叠后的逻辑,本题是判断区间重贴后要进行区间合并。
局部最优可以推出全局最优,找不出反例,试试贪心 所以一样的套路,先排序,让所有的相邻区间尽可能的重叠在一起,按左边界,或者右边界排序都可以,处理逻辑稍有不同
那有同学问了,本来不就应该合并最大右边界么,这和贪心有啥关系? 按照左边界从小到大排序之后,如果 `intervals[i][0] <= intervals[i - 1][1]` 即intervals[i]的左边界 <= intervals[i - 1]的右边界,则一定有重叠。(本题相邻区间也算重贴,所以是<=
有时候贪心就是常识!哈哈
按照左边界从小到大排序之后,如果 `intervals[i][0] < intervals[i - 1][1]` 即intervals[i]左边界 < intervals[i - 1]右边界则一定有重复因为intervals[i]的左边界一定是大于等于intervals[i - 1]的左边界
intervals[i]的左边界在intervals[i - 1]左边界和右边界的范围内那么一定有重复
这么说有点抽象,看图:(**注意图中区间都是按照左边界排序之后了** 这么说有点抽象,看图:(**注意图中区间都是按照左边界排序之后了**
@ -54,54 +48,21 @@ C++代码如下:
```CPP ```CPP
class Solution { class Solution {
public: public:
// 按照区间左边界从小到大排序
static bool cmp (const vector<int>& a, const vector<int>& b) {
return a[0] < b[0];
}
vector<vector<int>> merge(vector<vector<int>>& intervals) { vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result; vector<vector<int>> result;
if (intervals.size() == 0) return result; if (intervals.size() == 0) return result; // 区间集合为空直接返回
sort(intervals.begin(), intervals.end(), cmp);
bool flag = false; // 标记最后一个区间有没有合并
int length = intervals.size();
for (int i = 1; i < length; i++) {
int start = intervals[i - 1][0]; // 初始为i-1区间的左边界
int end = intervals[i - 1][1]; // 初始i-1区间的右边界
while (i < length && intervals[i][0] <= end) { // 合并区间
end = max(end, intervals[i][1]); // 不断更新右区间
if (i == length - 1) flag = true; // 最后一个区间也合并了
i++; // 继续合并下一个区间
}
// start和end是表示intervals[i - 1]的左边界右边界所以最优intervals[i]区间是否合并了要标记一下
result.push_back({start, end});
}
// 如果最后一个区间没有合并将其加入result
if (flag == false) {
result.push_back({intervals[length - 1][0], intervals[length - 1][1]});
}
return result;
}
};
```
当然以上代码有冗余一些可以优化一下如下思路是一样的
```CPP
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> result;
if (intervals.size() == 0) return result;
// 排序的参数使用了lambda表达式 // 排序的参数使用了lambda表达式
sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];}); sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b){return a[0] < b[0];});
result.push_back(intervals[0]); // 第一个区间就可以放进结果集里后面如果重叠在result上直接合并
result.push_back(intervals[0]);
for (int i = 1; i < intervals.size(); i++) { for (int i = 1; i < intervals.size(); i++) {
if (result.back()[1] >= intervals[i][0]) { // 合并区间 if (result.back()[1] >= intervals[i][0]) { // 发现重叠区间
result.back()[1] = max(result.back()[1], intervals[i][1]); // 合并区间只更新右边界就好因为result.back()的左边界一定是最小值,因为我们按照左边界排序的
result.back()[1] = max(result.back()[1], intervals[i][1]);
} else { } else {
result.push_back(intervals[i]); result.push_back(intervals[i]); // 区间不重叠
} }
} }
return result; return result;
@ -109,25 +70,6 @@ public:
}; };
``` ```
* 时间复杂度O(nlog n) 有一个快排
* 空间复杂度O(n)有一个快排最差情况(倒序)需要n次递归调用因此确实需要O(n)的栈空间
## 总结
对于贪心算法很多同学都是**如果能凭常识直接做出来就会感觉不到自己用了贪心, 一旦第一直觉想不出来, 可能就一直想不出来了**。
跟着代码随想录刷题的录友应该感受过贪心难起来真的难
那应该怎么办呢
正如我贪心系列开篇词[关于贪心算法,你该了解这些!](https://programmercarl.com/贪心算法理论基础.html)中讲解的一样贪心本来就没有套路也没有框架所以各种常规解法需要多接触多练习自然而然才会想到
代码随想录会把贪心常见的经典题目覆盖到大家只要认真学习打卡就可以了
## 其他语言版本 ## 其他语言版本

View File

@ -65,7 +65,7 @@ public:
for (int i = 0; i < cost.size(); i++) { for (int i = 0; i < cost.size(); i++) {
int rest = gas[i] - cost[i]; // 记录剩余油量 int rest = gas[i] - cost[i]; // 记录剩余油量
int index = (i + 1) % cost.size(); int index = (i + 1) % cost.size();
while (rest > 0 && index != i) { // 模拟以i为起点行驶一圈 while (rest > 0 && index != i) { // 模拟以i为起点行驶一圈如果有rest==0那么答案就不唯一了
rest += gas[index] - cost[index]; rest += gas[index] - cost[index];
index = (index + 1) % cost.size(); index = (index + 1) % cost.size();
} }

View File

@ -59,10 +59,15 @@ for (int i = 1; i < ratings.size(); i++) {
遍历顺序这里有同学可能会有疑问,为什么不能从前向后遍历呢? 遍历顺序这里有同学可能会有疑问,为什么不能从前向后遍历呢?
因为如果从前向后遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果了 因为 rating[5]与rating[4]的比较 要利用上 rating[5]与rating[6]的比较结果,所以 要从后向前遍历
如果从前向后遍历rating[5]与rating[4]的比较 就不能用上 rating[5]与rating[6]的比较结果了 。如图:
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230202102044.png)
**所以确定左孩子大于右孩子的情况一定要从后向前遍历!** **所以确定左孩子大于右孩子的情况一定要从后向前遍历!**
如果 ratings[i] > ratings[i + 1]此时candyVec[i]第i个小孩的糖果数量就有两个选择了一个是candyVec[i + 1] + 1从右边这个加1得到的糖果数量一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。 如果 ratings[i] > ratings[i + 1]此时candyVec[i]第i个小孩的糖果数量就有两个选择了一个是candyVec[i + 1] + 1从右边这个加1得到的糖果数量一个是candyVec[i](之前比较右孩子大于左孩子得到的糖果数量)。
那么又要贪心了局部最优取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优相邻的孩子中评分高的孩子获得更多的糖果。 那么又要贪心了局部最优取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优相邻的孩子中评分高的孩子获得更多的糖果。

View File

@ -33,6 +33,11 @@
* 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] * 输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
* 输出: false * 输出: false
# 算法公开课
**《代码随想录》算法视频公开课:[你的背包如何装满?| LeetCode139.单词拆分](https://www.bilibili.com/video/BV1pd4y147Rh/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
看到这道题目的时候,大家应该回想起我们之前讲解回溯法专题的时候,讲过的一道题目[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html),就是枚举字符串的所有分割情况。 看到这道题目的时候,大家应该回想起我们之前讲解回溯法专题的时候,讲过的一道题目[回溯算法:分割回文串](https://programmercarl.com/0131.分割回文串.html),就是枚举字符串的所有分割情况。

View File

@ -16,18 +16,23 @@
完全平方数 是一个整数其值等于另一个整数的平方换句话说其值等于一个整数自乘的积。例如1、4、9 和 16 都是完全平方数,而 3 和 11 不是。 完全平方数 是一个整数其值等于另一个整数的平方换句话说其值等于一个整数自乘的积。例如1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1 示例 1
输入n = 12 * 输入n = 12
输出3 * 输出3
解释12 = 4 + 4 + 4 * 解释12 = 4 + 4 + 4
示例 2 示例 2
输入n = 13 * 输入n = 13
输出2 * 输出2
解释13 = 4 + 9 * 解释13 = 4 + 9
提示: 提示:
* 1 <= n <= 10^4 * 1 <= n <= 10^4
# 算法公开课
**《代码随想录》算法视频公开课:[换汤不换药!| LeetCode279.完全平方数](https://www.bilibili.com/video/BV12P411T7Br/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
可能刚看这种题感觉没啥思路,又平方和的,又最小数的。 可能刚看这种题感觉没啥思路,又平方和的,又最小数的。

View File

@ -13,25 +13,25 @@
你可以认为每种硬币的数量是无限的。 你可以认为每种硬币的数量是无限的。
示例 1 示例 1
输入coins = [1, 2, 5], amount = 11 * 输入coins = [1, 2, 5], amount = 11
输出3 * 输出3
解释11 = 5 + 5 + 1 * 解释11 = 5 + 5 + 1
示例 2 示例 2
输入coins = [2], amount = 3 * 输入coins = [2], amount = 3
输出:-1 * 输出:-1
示例 3 示例 3
输入coins = [1], amount = 0 * 输入coins = [1], amount = 0
输出0 * 输出0
示例 4 示例 4
输入coins = [1], amount = 1 * 输入coins = [1], amount = 1
输出1 * 输出1
示例 5 示例 5
输入coins = [1], amount = 2 * 输入coins = [1], amount = 2
输出2 * 输出2
提示: 提示:
@ -39,6 +39,12 @@
* 1 <= coins[i] <= 2^31 - 1 * 1 <= coins[i] <= 2^31 - 1
* 0 <= amount <= 10^4 * 0 <= amount <= 10^4
# 算法公开课
**《代码随想录》算法视频公开课:[装满背包最少的物品件数是多少?| LeetCode322.零钱兑换](https://www.bilibili.com/video/BV14K411R7yv/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
在[动态规划518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中我们已经兑换一次零钱了,这次又要兑换,套路不一样! 在[动态规划518.零钱兑换II](https://programmercarl.com/0518.零钱兑换II.html)中我们已经兑换一次零钱了,这次又要兑换,套路不一样!

View File

@ -172,7 +172,8 @@ return {val2, val1};
以示例1为例dp数组状态如下**注意用后序遍历的方式推导** 以示例1为例dp数组状态如下**注意用后序遍历的方式推导**
![337.打家劫舍III](https://code-thinking.cdn.bcebos.com/pics/337.打家劫舍III.jpg)
![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230203110031.png)
**最后头结点就是 取下标0 和 下标1的最大值就是偷得的最大金钱** **最后头结点就是 取下标0 和 下标1的最大值就是偷得的最大金钱**

View File

@ -15,8 +15,8 @@
示例: 示例:
nums = [1, 2, 3] * nums = [1, 2, 3]
target = 4 * target = 4
所有可能的组合为: 所有可能的组合为:
(1, 1, 1, 1) (1, 1, 1, 1)
@ -31,6 +31,10 @@ target = 4
因此输出为 7。 因此输出为 7。
# 算法公开课
**《代码随想录》算法视频公开课:[装满背包有几种方法?求排列数?| LeetCode377.组合总和IV](https://www.bilibili.com/video/BV1V14y1n7B6/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
对完全背包还不了解的同学,可以看这篇:[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html) 对完全背包还不了解的同学,可以看这篇:[动态规划:关于完全背包,你该了解这些!](https://programmercarl.com/背包问题理论基础完全背包.html)

View File

@ -17,19 +17,24 @@
数组的大小不会超过 200 数组的大小不会超过 200
示例 1: 示例 1:
输入: [1, 5, 11, 5] * 输入: [1, 5, 11, 5]
输出: true * 输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11]. * 解释: 数组可以分割成 [1, 5, 5] 和 [11].
示例 2: 示例 2:
输入: [1, 2, 3, 5] * 输入: [1, 2, 3, 5]
输出: false * 输出: false
解释: 数组不能分割成两个元素和相等的子集. * 解释: 数组不能分割成两个元素和相等的子集.
提示: 提示:
* 1 <= nums.length <= 200 * 1 <= nums.length <= 200
* 1 <= nums[i] <= 100 * 1 <= nums[i] <= 100
# 算法公开课
**《代码随想录》算法视频公开课:[动态规划之背包问题,这个包能装满吗?| LeetCode416.分割等和子集](https://www.bilibili.com/video/BV1rt4y1N7jE/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
这道题目初步看,和如下两题几乎是一样的,大家可以用回溯法,解决如下两题 这道题目初步看,和如下两题几乎是一样的,大家可以用回溯法,解决如下两题

View File

@ -44,7 +44,8 @@
如图: 如图:
![455.分发饼干](https://img-blog.csdnimg.cn/20201123161809624.png) ![](https://code-thinking-1253855093.file.myqcloud.com/pics/20230203105634.png)
这个例子可以看出饼干9只有喂给胃口为7的小孩这样才是整体最优解并想不出反例那么就可以撸代码了。 这个例子可以看出饼干9只有喂给胃口为7的小孩这样才是整体最优解并想不出反例那么就可以撸代码了。

View File

@ -16,16 +16,16 @@
示例 1 示例 1
输入strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3 * 输入strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出4 * 输出4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。 * 解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。 其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。
示例 2 示例 2
输入strs = ["10", "0", "1"], m = 1, n = 1 * 输入strs = ["10", "0", "1"], m = 1, n = 1
输出2 * 输出2
解释:最大的子集是 {"0", "1"} ,所以答案是 2 。 * 解释:最大的子集是 {"0", "1"} ,所以答案是 2 。
提示: 提示:
@ -34,6 +34,11 @@
* strs[i] 仅由 '0' 和 '1' 组成 * strs[i] 仅由 '0' 和 '1' 组成
* 1 <= m, n <= 100 * 1 <= m, n <= 100
# 算法公开课
**《代码随想录》算法视频公开课:[装满这个背包最多用多少个物品?| LeetCode474.一和零](https://www.bilibili.com/video/BV1rW4y1x7ZQ/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
如果对背包问题不都熟悉先看这两篇: 如果对背包问题不都熟悉先看这两篇:

View File

@ -7,7 +7,7 @@
# 494. 目标和 # 494.目标和
[力扣题目链接](https://leetcode.cn/problems/target-sum/) [力扣题目链接](https://leetcode.cn/problems/target-sum/)
@ -19,15 +19,15 @@
示例: 示例:
输入nums: [1, 1, 1, 1, 1], S: 3 * 输入nums: [1, 1, 1, 1, 1], S: 3
输出5 * 输出5
解释: 解释:
-1+1+1+1+1 = 3 * -1+1+1+1+1 = 3
+1-1+1+1+1 = 3 * +1-1+1+1+1 = 3
+1+1-1+1+1 = 3 * +1+1-1+1+1 = 3
+1+1+1-1+1 = 3 * +1+1+1-1+1 = 3
+1+1+1+1-1 = 3 * +1+1+1+1-1 = 3
一共有5种方法让最终目标和为3。 一共有5种方法让最终目标和为3。
@ -37,6 +37,11 @@
* 初始的数组的和不会超过 1000 。 * 初始的数组的和不会超过 1000 。
* 保证返回的最终结果能被 32 位整数存下。 * 保证返回的最终结果能被 32 位整数存下。
# 算法公开课
**《代码随想录》算法视频公开课:[装满背包有多少种方法?| LeetCode494.目标和](https://www.bilibili.com/video/BV1o8411j73x/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
如果对背包问题不都熟悉先看这两篇: 如果对背包问题不都熟悉先看这两篇:

View File

@ -6,12 +6,10 @@
# 518. 零钱兑换 II # 518.零钱兑换II
[力扣题目链接](https://leetcode.cn/problems/coin-change-ii/) [力扣题目链接](https://leetcode.cn/problems/coin-change-ii/)
难度:中等
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。  给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 
示例 1: 示例 1:
@ -43,6 +41,12 @@
* 硬币种类不超过 500 种 * 硬币种类不超过 500 种
* 结果符合 32 位符号整数 * 结果符合 32 位符号整数
# 算法公开课
**《代码随想录》算法视频公开课:[装满背包有多少种方法?组合与排列有讲究!| LeetCode518.零钱兑换II](https://www.bilibili.com/video/BV1KM411k75j/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路

View File

@ -17,15 +17,15 @@
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。 注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
示例 1: 示例 1:
输入: prices = [1, 3, 2, 8, 4, 9], fee = 2 * 输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
输出: 8 * 输出: 8
解释: 能够达到的最大利润: 解释: 能够达到的最大利润:
在此处买入 prices[0] = 1 * 在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8 * 在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4 * 在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9 * 在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8. * 总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
注意: 注意:
* 0 < prices.length <= 50000. * 0 < prices.length <= 50000.
@ -34,14 +34,14 @@
## 思路 ## 思路
在讲解贪心专题的时候我们已经讲过本题了[贪心算法:买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费.html) 在讲解贪心专题的时候我们已经讲过本题了[贪心算法:买卖股票的最佳时机含手续费](https://programmercarl.com/0714.买卖股票的最佳时机含手续费.html)
使用贪心算法的性能是 使用贪心算法的性能是
* 时间复杂度O(n) * 时间复杂度O(n)
* 空间复杂度O(1) * 空间复杂度O(1)
那么我们再来看看是使用动规的方法如何解题 本题使用贪心算法并不好理解也很容易出错那么我们再来看看是使用动规的方法如何解题
相对于[动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html)本题只需要在计算卖出操作的时候减去手续费就可以了代码几乎是一样的 相对于[动态规划122.买卖股票的最佳时机II](https://programmercarl.com/0122.买卖股票的最佳时机II动态规划.html)本题只需要在计算卖出操作的时候减去手续费就可以了代码几乎是一样的

View File

@ -35,6 +35,7 @@
```CPP ```CPP
class Solution { class Solution {
private: private:
// 判断一个数字的各位上是否是递增
bool checkNum(int num) { bool checkNum(int num) {
int max = 10; int max = 10;
while (num) { while (num) {
@ -47,15 +48,15 @@ private:
} }
public: public:
int monotoneIncreasingDigits(int N) { int monotoneIncreasingDigits(int N) {
for (int i = N; i > 0; i--) { for (int i = N; i > 0; i--) { // 从大到小遍历
if (checkNum(i)) return i; if (checkNum(i)) return i;
} }
return 0; return 0;
} }
}; };
``` ```
* 时间复杂度:$O(n × m)$ m为n的数字长度 * 时间复杂度O(n × m) m为n的数字长度
* 空间复杂度:$O(1)$ * 空间复杂度O(1)
## 贪心算法 ## 贪心算法
@ -65,20 +66,12 @@ public:
这一点如果想清楚了,这道题就好办了。 这一点如果想清楚了,这道题就好办了。
**局部最优遇到strNum[i - 1] > strNum[i]的情况让strNum[i - 1]--然后strNum[i]给为9可以保证这两位变成最大单调递增整数**
**全局最优得到小于等于N的最大单调递增的整数**
**但这里局部最优推出全局最优还需要其他条件即遍历顺序和标记从哪一位开始统一改成9**
此时是从前向后遍历还是从后向前遍历呢? 此时是从前向后遍历还是从后向前遍历呢?
从前向后遍历的话遇到strNum[i - 1] > strNum[i]的情况让strNum[i - 1]减一但此时如果strNum[i - 1]减一了可能又小于strNum[i - 2]。 从前向后遍历的话遇到strNum[i - 1] > strNum[i]的情况让strNum[i - 1]减一但此时如果strNum[i - 1]减一了可能又小于strNum[i - 2]。
这么说有点抽象举个例子数字332从前向后遍历的话那么就把变成了329此时2又小于了第一位的3了真正的结果应该是299。 这么说有点抽象举个例子数字332从前向后遍历的话那么就把变成了329此时2又小于了第一位的3了真正的结果应该是299。
**所以从前后向遍历会改变已经遍历过的结果!**
那么从后向前遍历就可以重复利用上次比较得出的结果了从后向前遍历332的数值变化为332 -> 329 -> 299 那么从后向前遍历就可以重复利用上次比较得出的结果了从后向前遍历332的数值变化为332 -> 329 -> 299
确定了遍历顺序之后,那么此时局部最优就可以推出全局,找不出反例,试试贪心。 确定了遍历顺序之后,那么此时局部最优就可以推出全局,找不出反例,试试贪心。
@ -108,8 +101,8 @@ public:
``` ```
* 时间复杂度:$O(n)$n 为数字长度 * 时间复杂度O(n)n 为数字长度
* 空间复杂度:$O(n)$,需要一个字符串,转化为字符串操作更方便 * 空间复杂度O(n),需要一个字符串,转化为字符串操作更方便
## 总结 ## 总结

View File

@ -68,8 +68,8 @@ public:
}; };
``` ```
* 时间复杂度:$O(n)$ * 时间复杂度O(n)
* 空间复杂度:$O(1)$使用的hash数组是固定大小 * 空间复杂度O(1)使用的hash数组是固定大小
## 总结 ## 总结

View File

@ -4,7 +4,7 @@
</a> </a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p> <p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 827. 最大人工岛 # 827.最大人工岛
[力扣链接](https://leetcode.cn/problems/making-a-large-island/) [力扣链接](https://leetcode.cn/problems/making-a-large-island/)

View File

@ -4,7 +4,7 @@
</a> </a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p> <p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
## 1049. 最后一块石头的重量 II # 1049.最后一块石头的重量II
[力扣题目链接](https://leetcode.cn/problems/last-stone-weight-ii/) [力扣题目链接](https://leetcode.cn/problems/last-stone-weight-ii/)
@ -35,6 +35,11 @@
* 1 <= stones.length <= 30 * 1 <= stones.length <= 30
* 1 <= stones[i] <= 1000 * 1 <= stones[i] <= 1000
# 算法公开课
**《代码随想录》算法视频公开课:[这个背包最多能装多少LeetCode1049.最后一块石头的重量II](https://www.bilibili.com/video/BV14M411C7oV/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 思路 ## 思路
如果对背包问题不都熟悉先看这两篇: 如果对背包问题不都熟悉先看这两篇:

View File

@ -3,11 +3,13 @@
<img src="../pics/训练营.png" width="1000"/> <img src="../pics/训练营.png" width="1000"/>
</a> </a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p> <p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 贪心算法:根据身高重建队列(续集) # 贪心算法:根据身高重建队列(续集)
在讲解[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html)中我们提到了使用vectorC++中的动态数组来进行insert操作是费时的。 在讲解[贪心算法:根据身高重建队列](https://programmercarl.com/0406.根据身高重建队列.html)中我们提到了使用vectorC++中的动态数组来进行insert操作是费时的。
但是在解释的过程中有不恰当的地方,所以来专门写一篇文章来详细说一说这个问题。 这里专门写一篇文章来详细说一说这个问题。
使用vector的代码如下 使用vector的代码如下
```CPP ```CPP

View File

@ -4,7 +4,11 @@
</a> </a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p> <p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 动态规划:关于01背包问题,你该了解这些! # 动态规划01背包理论基础
**《代码随想录》算法视频公开课:[带你学透0-1背包问题](https://www.bilibili.com/video/BV1cg411g7Y6/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
这周我们正式开始讲解背包问题! 这周我们正式开始讲解背包问题!

View File

@ -4,7 +4,10 @@
</a> </a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p> <p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 动态规划:关于01背包问题,你该了解这些!(滚动数组) # 动态规划01背包理论基础(滚动数组)
**《代码随想录》算法视频公开课:[带你学透0-1背包问题滚动数组](https://www.bilibili.com/video/BV1BU4y177kY/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
昨天[动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)中是用二维dp数组来讲解01背包。 昨天[动态规划关于01背包问题你该了解这些](https://programmercarl.com/背包理论基础01背包-1.html)中是用二维dp数组来讲解01背包。

View File

@ -5,10 +5,13 @@
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p> <p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 动态规划:关于完全背包,你该了解这些! # 动态规划:完全背包理论基础
**《代码随想录》算法视频公开课:[带你学透完全背包问题! ](https://www.bilibili.com/video/BV1uK411o7c9/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。
## 完全背包 ## 完全背包
有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品都有无限个(也就是可以放入背包多次)**,求解将哪些物品装入背包里物品价值总和最大。 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品都有无限个(也就是可以放入背包多次)**,求解将哪些物品装入背包里物品价值总和最大。
**完全背包和01背包问题唯一不同的地方就是每种物品有无限件** **完全背包和01背包问题唯一不同的地方就是每种物品有无限件**