diff --git a/notes/src/SUMMARY.md b/notes/src/SUMMARY.md index 4d96cbe..3876dd0 100644 --- a/notes/src/SUMMARY.md +++ b/notes/src/SUMMARY.md @@ -89,4 +89,42 @@ - [216. 组合总和 III](./day25/lc216.md) - [17. 电话号码的字母组合](./day25/lc17.md) - [day 27](./day27.md) + - [39. 组合总和](./day27/lc39.md) + - [40. 组合总和II](./day27/lc40.md) + - [131. 分割回文串](./day27/lc131.md) +- [day 28](./day28.md) + - [93.复原IP地址](./day28/lc93.md) + - [78.子集](./day28/lc78.md) + - [90.子集II](./day28/lc90.md) +- [day 29](./day29.md) + - [491.递增子序列](./day29/lc491.md) + - [46.全排列](./day29/lc46.md) + - [47.全排列 II](./day29/lc47.md) +- [day 30](./day30.md) + - [332.重新安排行程](./day30/332.md) + - [51. N皇后](./day30/lc51.md) + - [37. 解数独](./day30/lc37.md) +- [day 31](./day31.md) + - [455.分发饼干](./day31/lc455.md) + - [376. 摆动序列](./day31/lc376.md) + - [53. 最大子序和](./day31/lc53.md) +- [day 32](./day32.md) + - [122.买卖股票的最佳时机II](./day32/lc122.md) + - [55. 跳跃游戏](./day32/lc55.md) + - [45.跳跃游戏II](./day32/lc45.md) +- [day 34](./day34.md) + - [1005.K次取反后最大化的数组和](./day34/lc1005.md) + - [134. 加油站](./day34/lc134.md) + - [135. 分发糖果](./day34/lc135.md) +- [day 35](./day35.md) + - [860.柠檬水找零](./day35/lc860.md) + - [406.根据身高重建队列](./day35/lc406.md) + - [452. 用最少数量的箭引爆气球](./day35/lc452.md) +- [day 36](./day36.md) + - [435. 无重叠区间](./day36/lc435.md) + - [763.划分字母区间](./day36/lc763.md) + - [56. 合并区间](./day36/lc56.md) +- [day 37](./day37.md) + - [738.单调递增的数字](./day37/lc738.md) + - [968.监控二叉树](./day37/lc968.md) - [remains](./remains.md) \ No newline at end of file diff --git a/notes/src/day27.md b/notes/src/day27.md index e69de29..4f65a1b 100644 --- a/notes/src/day27.md +++ b/notes/src/day27.md @@ -0,0 +1,29 @@ +# 第七章 回溯算法part03 + + 详细布置 + +## 39. 组合总和 + +本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制 + +题目链接/文章讲解:https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html +视频讲解:https://www.bilibili.com/video/BV1KT4y1M7HJ + +## 40.组合总和II + +本题开始涉及到一个问题了:去重。 + +注意题目中给我们 集合是有重复元素的,那么求出来的 组合有可能重复,但题目要求不能有重复组合。 + +题目链接/文章讲解:https://programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html +视频讲解:https://www.bilibili.com/video/BV12V4y1V73A + +## 131.分割回文串 + +本题较难,大家先看视频来理解 分割问题,明天还会有一道分割问题,先打打基础。 + +https://programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html +视频讲解:https://www.bilibili.com/video/BV1c54y1e7k6 + + + diff --git a/notes/src/day27/lc131.md b/notes/src/day27/lc131.md new file mode 100644 index 0000000..b3c045f --- /dev/null +++ b/notes/src/day27/lc131.md @@ -0,0 +1,24 @@ +# 131.分割回文串 + +```cpp +class Solution { +public: + string s;vector>res;vectorcur; + bool valid(int l,int r){ + int lptr=l,rptr=r;while(lptr<=r){if(s[lptr]!=s[rptr])return false;lptr++;rptr--;}return true; + } + void bt(int start){ + if(start==s.size()){res.push_back(cur);return;} + for(int i=start;i> partition(string s) { + this->s=s;bt(0);return res; + } +}; +``` diff --git a/notes/src/day27/lc39.md b/notes/src/day27/lc39.md new file mode 100644 index 0000000..a366e3c --- /dev/null +++ b/notes/src/day27/lc39.md @@ -0,0 +1,21 @@ +# 39. 组合总和 + +```cpp +class Solution { +public: + vector>res; + vectorcur;vectorcandidates; + int s=0,t; + void bt(int start){ + if(s>=t){if(s==t)res.push_back(cur);return;} + for(int j=start;j> combinationSum(vector& candidates, int target) { + t=target;this->candidates=candidates;bt(0);return res; + } +}; +``` diff --git a/notes/src/day27/lc40.md b/notes/src/day27/lc40.md new file mode 100644 index 0000000..1908c73 --- /dev/null +++ b/notes/src/day27/lc40.md @@ -0,0 +1,28 @@ +# 40.组合总和II + +```cpp +class Solution { +public: + vector>res; + vectorcur;vectorcandidates; + int s=0,t; + void bt(int start){ + if(s>=t){if(s==t)res.push_back(cur);return;} + for(int j=start;jstart&&candidates[j]==candidates[j-1])continue; + cur.push_back(i);s+=i; + bt(j+1); + cur.pop_back();s-=i; + } + } + vector> combinationSum2(vector& candidates, int target) { + t=target;sort(candidates.begin(),candidates.end());this->candidates=candidates;bt(0);return res; + } +}; +``` + +`if(j>start&&candidates[j]==candidates[j-1])continue;`这而想了很久,一直以为是j大于0 + +为了结果不重复,所以剪枝是必须要进行的操作 diff --git a/notes/src/day28.md b/notes/src/day28.md new file mode 100644 index 0000000..e0d62f3 --- /dev/null +++ b/notes/src/day28.md @@ -0,0 +1,26 @@ +# 28 第七章 回溯算法 +● 93.复原IP地址 +● 78.子集 +● 90.子集II + + 详细布置 + +## 93.复原IP地址 + +本期本来是很有难度的,不过 大家做完 分割回文串 之后,本题就容易很多了 + +题目链接/文章讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html +视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/ + +## 78.子集 + +子集问题,就是收集树形结构中,每一个节点的结果。 整体代码其实和 回溯模板都是差不多的。 + +题目链接/文章讲解:https://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html +视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci +## 90.子集II + +大家之前做了 40.组合总和II 和 78.子集 ,本题就是这两道题目的结合,建议自己独立做一做,本题涉及的知识,之前都讲过,没有新内容。 + +题目链接/文章讲解:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html +视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J diff --git a/notes/src/day28/lc78.md b/notes/src/day28/lc78.md new file mode 100644 index 0000000..f59c06d --- /dev/null +++ b/notes/src/day28/lc78.md @@ -0,0 +1,19 @@ + + + +# 78.子集 + +```cpp +class Solution { +public:vector>res;vectorcur;vectorv;void bt(int start){res.push_back(cur); + if(start>=v.size())return;for(int i=start;i> subsets(vector& nums) { + v=nums;bt(0);return res; + } +}; +``` + +如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么**组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点**! diff --git a/notes/src/day28/lc90.md b/notes/src/day28/lc90.md new file mode 100644 index 0000000..17a44f3 --- /dev/null +++ b/notes/src/day28/lc90.md @@ -0,0 +1,16 @@ + +# 90.子集II + +```cpp +class Solution { +public:vector>res;vectorcur;vectorv;void bt(int start){res.push_back(cur); + if(start==v.size())return;for(int i=start;istart&&v[i]==v[i-1])continue; + cur.push_back(v[i]);bt(i+1);cur.pop_back(); + } +} + vector> subsetsWithDup(vector& nums) { + sort(nums.begin(),nums.end());v=nums;bt(0);return res; + } +}; +``` diff --git a/notes/src/day28/lc93.md b/notes/src/day28/lc93.md new file mode 100644 index 0000000..0f93a04 --- /dev/null +++ b/notes/src/day28/lc93.md @@ -0,0 +1,28 @@ + +# 93.复原IP地址 + +```cpp +class Solution { +public: + vectorres;string cur;string s;void bt(int start,int cnt){ + if(cnt==4||start>=s.size()){if(cnt==4&&start==s.size())res.push_back(string(cur.begin(),cur.end()-1));return;} + for(int i=1;i<=3;i++){ + string sub=string(s.begin()+start,s.begin()+start+i); + if(valid(sub)){ + auto l=cur.size(); + cur+=sub+"."; + bt(start+i,cnt+1); + cur.erase(l); + } + } + } + bool valid(string s){ + if(s.size()==0)return false; + if(s[0]=='0')return s.size()==1; + int a=stoi(s);return a>=0 && a<=255; + } + vector restoreIpAddresses(string s) {this->s=s; + bt(0,0);return res; + } +}; +``` diff --git a/notes/src/day29.md b/notes/src/day29.md new file mode 100644 index 0000000..1c095df --- /dev/null +++ b/notes/src/day29.md @@ -0,0 +1,27 @@ +# 第七章 回溯算法part05 + +* 491.递增子序列 +* 46.全排列 +* 47.全排列 II + +详细布置 + +## 491.递增子序列 + +本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。 +https://programmercarl.com/0491.%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97.html + +视频讲解:https://www.bilibili.com/video/BV1EG4y1h78v + + +## 46.全排列 +本题重点感受一下,排列问题 与 组合问题,组合总和,子集问题的区别。 为什么排列问题不用 startIndex +https://programmercarl.com/0046.%E5%85%A8%E6%8E%92%E5%88%97.html +视频讲解:https://www.bilibili.com/video/BV19v4y1S79W + +## 47.全排列 II +本题 就是我们讲过的 40.组合总和II 去重逻辑 和 46.全排列 的结合,可以先自己做一下,然后重点看一下 文章中 我讲的拓展内容。 used[i - 1] == true 也行,used[i - 1] == false 也行 + +https://programmercarl.com/0047.%E5%85%A8%E6%8E%92%E5%88%97II.html + +视频讲解:https://www.bilibili.com/video/BV1R84y1i7Tm diff --git a/notes/src/day29/lc46.md b/notes/src/day29/lc46.md new file mode 100644 index 0000000..cc346e9 --- /dev/null +++ b/notes/src/day29/lc46.md @@ -0,0 +1,26 @@ + +# 46.全排列 + + +https://programmercarl.com/0046.%E5%85%A8%E6%8E%92%E5%88%97.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE +```cpp +class Solution { +public: + vectorused; + vectorcur; + vectorv; + vector>res; + void bt() { + if(cur.size()==v.size()) + {res.push_back(cur);return;} + for(int i=0;i> permute(vector& nums) { + v=nums;used=vector(v.size(),0);bt();return res; + } +}; +``` diff --git a/notes/src/day29/lc47.md b/notes/src/day29/lc47.md new file mode 100644 index 0000000..345b6e9 --- /dev/null +++ b/notes/src/day29/lc47.md @@ -0,0 +1,34 @@ +# 47.全排列 II + +```cpp +class Solution { +public: + vectorused; + vectorcur; + vectorv; + vector>res; + void bt() { + if(cur.size()==v.size()){ + res.push_back(cur);return; + } + for(int i=0;i0&&v[i]==v[i-1]&&used[i-1]==0)continue; + used[i]=1; + cur.push_back(v[i]); + bt(); + cur.pop_back(); + used[i]=0; + } + } + vector> permuteUnique(vector& nums) { + v=nums;sort(v.begin(),v.end()); + used=vector(v.size(),0); + bt(); + return res; + } +}; +``` + +如何剪枝同一层使用过的:`&&used[i-1]==0`,一下子想不到。 + diff --git a/notes/src/day29/lc491.md b/notes/src/day29/lc491.md new file mode 100644 index 0000000..879eb95 --- /dev/null +++ b/notes/src/day29/lc491.md @@ -0,0 +1,28 @@ + +# 491.递增子序列 + +```cpp +class Solution { + public:vector>res; + vectorcur; + vectorv; + void bt(int start){ + if(cur.size()>1)res.push_back(cur); + if(start>=v.size())return; + unordered_set uset; + for(int i=start;i=cur.back()) + { + if(uset.find(v[i])!=uset.end())continue; + uset.insert(v[i]); + cur.push_back(v[i]);bt(i+1);cur.pop_back(); + } + } + + } + vector> findSubsequences(vector& nums) {v=nums;bt(0);return res;} +}; + +``` + +本层访问过的元素不再访问,误以为是前后不用重复的就行,需要使用set diff --git a/notes/src/day30.md b/notes/src/day30.md new file mode 100644 index 0000000..481ee51 --- /dev/null +++ b/notes/src/day30.md @@ -0,0 +1,30 @@ +# 第七章 回溯算法part06 +● 332.重新安排行程 +● 51. N皇后 +● 37. 解数独 +● 总结 + +详细布置 + +今天这三道题都非常难,那么这么难的题,为啥一天做三道? + +因为 一刷 也不求大家能把这么难的问题解决,所以 大家一刷的时候,就了解一下题目的要求,了解一下解题思路,不求能直接写出代码,先大概熟悉一下这些题,二刷的时候,随着对回溯算法的深入理解,再去解决如下三题。 + +大家今天的任务,其实是 对回溯算法章节做一个总结就行。 + +重点是看 回溯算法总结篇: +https://programmercarl.com/%E5%9B%9E%E6%BA%AF%E6%80%BB%E7%BB%93.html + +## 332.重新安排行程(可跳过) +https://programmercarl.com/0332.%E9%87%8D%E6%96%B0%E5%AE%89%E6%8E%92%E8%A1%8C%E7%A8%8B.html + +## 51. N皇后(可跳过) +https://programmercarl.com/0051.N%E7%9A%87%E5%90%8E.html +视频讲解:https://www.bilibili.com/video/BV1Rd4y1c7Bq + +## 37. 解数独(可跳过) +https://programmercarl.com/0037.%E8%A7%A3%E6%95%B0%E7%8B%AC.html +视频讲解:https://www.bilibili.com/video/BV1TW4y1471V + +总结 +https://programmercarl.com/%E5%9B%9E%E6%BA%AF%E6%80%BB%E7%BB%93.html diff --git a/notes/src/day30/lc332.md b/notes/src/day30/lc332.md new file mode 100644 index 0000000..bd9e795 --- /dev/null +++ b/notes/src/day30/lc332.md @@ -0,0 +1,42 @@ +# 332.重新安排行程 + +```cpp +class Solution { +public: + unordered_map> targets; + vector res; + int ticketNum; + bool bt() { + if(res.size()==ticketNum+1)return true; + for( pair& target: targets[res.back()]) { + if (target.second > 0) { + res.push_back(target.first); + target.second -- ; + if (bt())return true; + res.pop_back(); + target.second ++ ; + + } + } + return false; + } + vector findItinerary(vector>& tickets) { + for(auto v : tickets) { + targets[v[0]][v[1]] ++ ; + } + res.push_back("JFK"); + ticketNum = tickets.size(); + bt(); + return res; + } +}; +``` + +这个我是不会的,完全抄了随想录。 + +本质是,深度优先搜索 + +做之前心里的一些疑虑: +1. 怎么比较字母序大小,结果直接用map自动帮我排好序 +2. 怎么表示这个有向图,然后是用了两个map嵌套 + diff --git a/notes/src/day30/lc37.md b/notes/src/day30/lc37.md new file mode 100644 index 0000000..4ae892f --- /dev/null +++ b/notes/src/day30/lc37.md @@ -0,0 +1,39 @@ +# 37. 解数独 + +```cpp +class Solution { +public: + vector> b; + bool check(int i,int j,int val) { + for(int k=0;k<9;k++)if(b[i][k]==val||b[k][j]==val)return false; + int ibase = i/3*3, jbase = j/3*3; + for(int u=0;u<3;u++)for(int v=0;v<3;v++)if(b[ibase+u][jbase+v]==val)return false; + return true; + } + bool bt(int pos) { + int i = pos/9, j = pos%9; + if(i==9)return true; + if(b[i][j]!='.')return bt(pos+1); + for(int v=1; v<=9; v++) { + if(check(i,j,'0'+v)) { + b[i][j]='0'+v; + if(bt(pos+1))return true; + b[i][j]='.'; + } + } + return false; // unreachable + } + void solveSudoku(vector>& board) { + b=board; + bt(0); + // for(int i=0;i<9;i++){ + // for(int j=0;j<9;j++){ + // cout<> res; + vector chess; + int N; + bool checkpos(int i, int j) { + for(int k=i+1;k=N||y>=N)break; + if(chess[x][y]=='Q')return false; + } + for(int k=0;k=N||y<0)break; + if(chess[x][y]=='Q')return false; + } + return true; + } + void bt(int depth) { + if (depth < 0) { + res.push_back(chess); + return; + } + for(int pos=0;pos> solveNQueens(int n) { + N=n; + for (int i=0;i&v) { + // + auto tail = unique(v.begin(),v.end()); + v.erase(tail,v.end()); + // + if(v.size()<=2)return v.size(); + int cnt = 0; + for (int i = 1; i < v.size() - 1; i ++ ) { + int pdir = v[i] - v[i-1]; + int cdir = v[i+1] - v[i]; + cnt += pdir*cdir<0?1:0; + } + return cnt+2; + } +}; +``` + +去重之后就不用考虑这么多复杂的情况 diff --git a/notes/src/day31/lc455.md b/notes/src/day31/lc455.md new file mode 100644 index 0000000..79bd12c --- /dev/null +++ b/notes/src/day31/lc455.md @@ -0,0 +1,26 @@ +# 455. 分发饼干 + +```cpp +// Custom comparator function for sorting in reverse order +bool reverseComparator(int a, int b) { + return a > b; // '>' will sort in descending order (reverse), '<' will sort in ascending order +} +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(s.begin(),s.end(),reverseComparator); + sort(g.begin(),g.end(),reverseComparator); + int cnt = 0; + int p = 0; + for (int cookiesize : s) { + while (p < g.size() && g[p] > cookiesize) p ++ ; + if (p >= g.size()) break; + // if (cookiesize >= g[p]) { + cnt ++ ; + p ++; + // } + } + return cnt; + } +}; +``` diff --git a/notes/src/day31/lc53.md b/notes/src/day31/lc53.md new file mode 100644 index 0000000..2999f76 --- /dev/null +++ b/notes/src/day31/lc53.md @@ -0,0 +1,20 @@ + +# 53. 最大子数组和 + +```cpp +class Solution { +public: + int maxSubArray(vector& nums) { + int res = INT_MIN; + int cnt = 0; + for (int num : nums) { + cnt += num; + res = max(res,cnt); + if (cnt < 0) cnt = 0; + } + return res; + } +}; +``` + +`res = max(res,cnt);`和`if (cnt < 0) cnt = 0;`这两行顺序一开始搞错了, 导致input只是一个-1的时候有问题 diff --git a/notes/src/day32.md b/notes/src/day32.md new file mode 100644 index 0000000..10e82dc --- /dev/null +++ b/notes/src/day32.md @@ -0,0 +1,24 @@ +# 第八章 贪心算法 part02 +● 122.买卖股票的最佳时机II +● 55. 跳跃游戏 +● 45.跳跃游戏II + + 详细布置 + +## 122.买卖股票的最佳时机II + +本题解法很巧妙,大家可以看题思考一下,在看题解。 + +https://programmercarl.com/0122.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAII.html + +## 55. 跳跃游戏 + +本题如果没接触过,很难想到,所以不要自己憋时间太久,读题思考一会,没思路立刻看题解 + +https://programmercarl.com/0055.%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F.html + +## 45.跳跃游戏II + +本题同样不容易想出来。贪心就是这样,有的时候 会感觉简单到离谱,有时候,难的不行,主要是不容易想到。 + +https://programmercarl.com/0045.%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8FII.html diff --git a/notes/src/day32/lc122.md b/notes/src/day32/lc122.md new file mode 100644 index 0000000..048cb9e --- /dev/null +++ b/notes/src/day32/lc122.md @@ -0,0 +1,22 @@ + + +# 122. 买卖股票的最佳时机 II + + +如果想到其实最终利润是可以分解的,那么本题就很容易了! + + +```cpp +class Solution { +public: + int maxProfit(vector& prices) { + int res = 0; + for ( int i = 1; i < prices.size(); i ++ ) { + int a = prices[i] - prices[i-1]; + res += a>0?a:0; + } + return res; + } +}; +``` + diff --git a/notes/src/day32/lc45.md b/notes/src/day32/lc45.md new file mode 100644 index 0000000..c447b2a --- /dev/null +++ b/notes/src/day32/lc45.md @@ -0,0 +1,28 @@ +# 45.跳跃游戏 II + +```cpp +class Solution { +public: + int jump(vector& nums) { + int res = 1; + int predist = nums[0]; + int maxdist = predist; + int i = 0; + if(nums.size()==1)return 0; + if (maxdist>=nums.size()-1) return 1; + while (i <= maxdist) { + int nextdist = i+nums[i]; + maxdist=max(maxdist,nextdist); + if (maxdist>=nums.size()-1) break; + if (i == predist) { + res ++ ; + predist = maxdist; + } + i ++ ; + + } + return res + 1; + } +}; +``` + diff --git a/notes/src/day32/lc55.md b/notes/src/day32/lc55.md new file mode 100644 index 0000000..93f3f04 --- /dev/null +++ b/notes/src/day32/lc55.md @@ -0,0 +1,17 @@ +# 55. 跳跃游戏 + +```cpp +class Solution { +public: + bool canJump(vector& nums) { + int dst = 0; + int i = 0; + while (i <= dst) { + dst = max(dst,i+nums[i]); + i ++ ; + if (dst >= nums.size() - 1) return true; + } + return false; + } +}; +``` diff --git a/notes/src/day34.md b/notes/src/day34.md new file mode 100644 index 0000000..ee00642 --- /dev/null +++ b/notes/src/day34.md @@ -0,0 +1,20 @@ +# 第八章 贪心算法 part03 +● 1005.K次取反后最大化的数组和 +● 134. 加油站 +● 135. 分发糖果 + + 详细布置 + +## 1005.K次取反后最大化的数组和 +本题简单一些,估计大家不用想着贪心 ,用自己直觉也会有思路。 +https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.html + + +## 134. 加油站 +本题有点难度,不太好想,推荐大家熟悉一下方法二 +https://programmercarl.com/0134.%E5%8A%A0%E6%B2%B9%E7%AB%99.html + + +## 135. 分发糖果 +本题涉及到一个思想,就是想处理好一边再处理另一边,不要两边想着一起兼顾,后面还会有题目用到这个思路 +https://programmercarl.com/0135.%E5%88%86%E5%8F%91%E7%B3%96%E6%9E%9C.html diff --git a/notes/src/day34/lc1005.md b/notes/src/day34/lc1005.md new file mode 100644 index 0000000..06dd944 --- /dev/null +++ b/notes/src/day34/lc1005.md @@ -0,0 +1,18 @@ +# 1005.K次取反后最大化的数组和 + +```cpp +class Solution { +public: + int largestSumAfterKNegations(vector& v, int k) { + sort(v.begin(),v.end()); + for(int& i: v){ + if (i >= 0) break; + i=-i;k--;if(k==0)break; + }if(k==0)return accumulate(v.begin(), v.end(), 0); + sort(v.begin(),v.end()); + while (k>0){v[0]=-v[0];k--;} + return accumulate(v.begin(), v.end(), 0); + } +}; +``` + diff --git a/notes/src/day34/lc134.md b/notes/src/day34/lc134.md new file mode 100644 index 0000000..94384eb --- /dev/null +++ b/notes/src/day34/lc134.md @@ -0,0 +1,31 @@ +# 134. 加油站 + +```cpp +class Solution { +public: + int canCompleteCircuit(vector& g, vector& c) { + int n = g.size(); + vector h(n,0); + // h[i] -> gas change from i-1 -> i + h[0] = g[n-1] - c[n-1]; + for (int i = 1 ; i < n ; i ++ ) { + h[i] = g[i-1]-c[i-1]; + } + int start = 0; + int pos = start; + int csum = 0; + while (pos < start + n && start < n) { + csum += h[(1+pos)%n]; + if (csum < 0) { + start = pos + 1; + csum = 0; + } + pos ++ ; + } + return start& v) { + // 1,3,4,5,2 + // 1,2,3,4,1 + // + vectorres(v.size(),1); + for (int i = 1 ; i < v.size() ; i ++ ) { + if (v[i] > v[i-1]) res[i] = res[i-1] + 1; + } + for (int i = v.size() - 2; i >= 0 ; i -- ) { + if (v[i] > v[i+1] && res[i] <= res[i+1]) res[i] = res[i+1] + 1; + } + return accumulate(res.begin(),res.end(),0); + } +}; +``` + +WA了一发漏了`&& res[i] <= res[i+1]` + diff --git a/notes/src/day35.md b/notes/src/day35.md new file mode 100644 index 0000000..d6dfbbc --- /dev/null +++ b/notes/src/day35.md @@ -0,0 +1,22 @@ +# 第八章 贪心算法 part04 + +● 860.柠檬水找零 +● 406.根据身高重建队列 +● 452. 用最少数量的箭引爆气球 + + 详细布置 + +## 860.柠檬水找零 + +本题看上好像挺难,其实挺简单的,大家先尝试自己做一做。 +https://programmercarl.com/0860.%E6%9F%A0%E6%AA%AC%E6%B0%B4%E6%89%BE%E9%9B%B6.html + +## 406.根据身高重建队列 + +本题有点难度,和分发糖果类似,不要两头兼顾,处理好一边再处理另一边。 +https://programmercarl.com/0406.%E6%A0%B9%E6%8D%AE%E8%BA%AB%E9%AB%98%E9%87%8D%E5%BB%BA%E9%98%9F%E5%88%97.html + +## 452. 用最少数量的箭引爆气球 + +本题是一道 重叠区间的题目,好好做一做,因为明天三道题目,都是 重叠区间。 +https://programmercarl.com/0452.%E7%94%A8%E6%9C%80%E5%B0%91%E6%95%B0%E9%87%8F%E7%9A%84%E7%AE%AD%E5%BC%95%E7%88%86%E6%B0%94%E7%90%83.html \ No newline at end of file diff --git a/notes/src/day35/lc406.md b/notes/src/day35/lc406.md new file mode 100644 index 0000000..98fd7ca --- /dev/null +++ b/notes/src/day35/lc406.md @@ -0,0 +1,61 @@ +# 406.根据身高重建队列 +错误解答 +```cpp + +bool f(const vector&a, const vector&b) { + if (a[1]==b[1])return a[0]>b[0];return a[1]> reconstructQueue(vector>& p) { + vector> res; + sort(p.begin(),p.end(),f); + for ( auto peo: p ) { + if (peo[1]!=0) break; + res.push_back(peo); + } + reverse(res.begin(),res.end()); + for (int i = res.size(); i < p.size(); i ++ ) { + auto x = p[i]; + int insert_pos = 0; int cnt = 0; + while ( cnt < x[1] + 1 ) { + if (p[insert_pos][0] >= x[0]) cnt ++ ; + insert_pos ++ ; + } + res.insert(res.begin()+insert_pos - 1,x); + } + return res; + } +}; +``` + +> 这道题我没有能够做出来 + +在135. 分发糖果 (opens new window)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。 + +如果两个维度一起考虑一定会顾此失彼。 + +> 我就是错误的按照k来从小到大排序了 + +```cpp + +bool f(vector& a, vector& b){ + if(a[0]==b[0])return a[1]b[0]; +} +class Solution { +public: + vector> reconstructQueue(vector>& p) { + vector> res; + sort(p.begin(),p.end(),f); + for (int i = 0; i < p.size(); i ++ ) { + auto x = p[i]; + int pos = x[1]; + res.insert(res.begin()+pos,x); + } + return res; + } +}; +``` + +先按照身高排序,固定住规律。按照k排序没法获得额外的规律 + diff --git a/notes/src/day35/lc452.md b/notes/src/day35/lc452.md new file mode 100644 index 0000000..1f76f13 --- /dev/null +++ b/notes/src/day35/lc452.md @@ -0,0 +1,29 @@ +# 452. 用最少数量的箭引爆气球 + +想不出来用什么数据结构 + +```cpp +class Solution { +public: + int findMinArrowShots(vector>& v) { + int res = 1; + sort(v.begin(),v.end()); + for ( int i = 1 ; i < v.size(); i ++ ) { + if ( v[i][0] > v[i-1][1] ) { + res ++ ; + } else { + v[i][1] = min(v[i][1],v[i-1][1]); + } + } + return res; + } +}; +``` + +发现不用数据结构,要点是每次右端点取重合的最小值 + +```plaintext + ====== +==================== +``` + diff --git a/notes/src/day35/lc860.md b/notes/src/day35/lc860.md new file mode 100644 index 0000000..ac83fd8 --- /dev/null +++ b/notes/src/day35/lc860.md @@ -0,0 +1,36 @@ +# 860.柠檬水找零 + +```cpp +class Solution { +public: + bool lemonadeChange(vector& bills) { + int c5 = 0, c10 = 0; + for ( int bill : bills) { + switch (bill) { + case 5: + c5 ++ ; + break; + case 10: + if (c5 == 0) return false; + c5 -- ; + c10 ++ ; + break; + default: + if (c10>0&&c5>0) { + c10 -- ; c5 -- ; continue; + } + if (c5 >= 3) { + c5 -= 3; continue; + } + return false; + break; + } + } + return true; + } +}; +``` + + +模拟题 + diff --git a/notes/src/day36.md b/notes/src/day36.md new file mode 100644 index 0000000..2b8516b --- /dev/null +++ b/notes/src/day36.md @@ -0,0 +1,20 @@ +# 第八章 贪心算法 part05 +● 435. 无重叠区间 +● 763.划分字母区间 +● 56. 合并区间 + + 详细布置 + +今天的三道题目,都算是 重叠区间 问题,大家可以好好感受一下。 都属于那种看起来好复杂,但一看贪心解法,惊呼:这么巧妙! +还是属于那种,做过了也就会了,没做过就很难想出来。 +不过大家把如下三题做了之后, 重叠区间 基本上差不多了 +## 435. 无重叠区间 + +https://programmercarl.com/0435.%E6%97%A0%E9%87%8D%E5%8F%A0%E5%8C%BA%E9%97%B4.html +## 763.划分字母区间 + +https://programmercarl.com/0763.%E5%88%92%E5%88%86%E5%AD%97%E6%AF%8D%E5%8C%BA%E9%97%B4.html +## 56. 合并区间 +本题相对来说就比较难了。 + +https://programmercarl.com/0056.%E5%90%88%E5%B9%B6%E5%8C%BA%E9%97%B4.html \ No newline at end of file diff --git a/notes/src/day36/lc435.md b/notes/src/day36/lc435.md new file mode 100644 index 0000000..4eec2f3 --- /dev/null +++ b/notes/src/day36/lc435.md @@ -0,0 +1,56 @@ +# 435. 无重叠区间 + +```cpp +bool f(const vector&a,const vector&b) { + if(a[0]==b[0])return a[1]>b[1];return a[0]>& v) { + int res = 0; + sort(v.begin(),v.end(),f); + for ( int i = 1 ; i < v.size(); i ++ ) { + cout << v[i][0] << v[i][1] << endl; + if ( v[i][0] >= v[i-1][1] ) { + } else { + res ++ ; + // v[i][1] = min(v[i][1],v[i-1][1]); + } + } + return res; + } +}; +``` + +不会做,不知道怎么处理这种情况 + +```plaintext + ------- ------- ------- ------- +====== ======= ====== ======= ===== +``` + +求`需要移除区间的最小数量,使剩余区间互不重叠` -> 求最大的不交叉区间个数 + +```cpp +bool f(const vector&a,const vector&b) { + return a[1]>& v) { + int cnt = 1; + sort(v.begin(),v.end(),f); + int rend = v[0][1]; + for ( int i = 1 ; i < v.size(); i ++ ) { + if (rend <= v[i][0]) { + rend = v[i][1]; + cnt ++ ; + } + } + return v.size() - cnt; + } +}; +``` + +通用技巧,求不重合区间的最大个数 + diff --git a/notes/src/day36/lc56.md b/notes/src/day36/lc56.md new file mode 100644 index 0000000..ce7da22 --- /dev/null +++ b/notes/src/day36/lc56.md @@ -0,0 +1,28 @@ +# 56. 合并区间 + +```cpp +bool f(const vector&a,const vector&b) { + if(a[0]==b[0])return a[1]>res; + vector> merge(vector>& v) { + sort(v.begin(),v.end(),f); + int l = v[0][0], r = v[0][1]; + for ( int i = 1; i < v.size(); i ++ ) { + if (v[i][0]<=r) r = max(r,v[i][1]); + else { + res.push_back(vector{l, r}); + l = v[i][0]; + r = v[i][1]; + } + } + res.push_back(vector{l, r}); + return res; + } +}; +``` + +这个 很直接 + diff --git a/notes/src/day36/lc763.md b/notes/src/day36/lc763.md new file mode 100644 index 0000000..639d93b --- /dev/null +++ b/notes/src/day36/lc763.md @@ -0,0 +1,25 @@ +# 763.划分字母区间 + +```cpp +class Solution { +public: + vector partitionLabels(string s) { + int v[26] = {0}; + vector res; + for (int i = 0; i < s.size(); i ++ ) { + v[s[i]-'a']=i; + } + int last = v[s[0]-'a']; + int pre = 0; + for (int i = 0; i < s.size(); i ++ ) { + last = max(last,v[s[i]-'a']); + if (last == i) { + res.push_back(i - pre + 1); + pre = i + 1; + } + } + return res; + } +}; +``` + diff --git a/notes/src/day37.md b/notes/src/day37.md new file mode 100644 index 0000000..52a24ac --- /dev/null +++ b/notes/src/day37.md @@ -0,0 +1,20 @@ +# 第八章 贪心算法 part06 + +● 738.单调递增的数字 +● 968.监控二叉树 +● 总结 + + 详细布置 + +## 738.单调递增的数字 +https://programmercarl.com/0738.%E5%8D%95%E8%B0%83%E9%80%92%E5%A2%9E%E7%9A%84%E6%95%B0%E5%AD%97.html + +## 968.监控二叉树 (可以跳过) + +本题是贪心和二叉树的一个结合,比较难,一刷大家就跳过吧。 +https://programmercarl.com/0968.%E7%9B%91%E6%8E%A7%E4%BA%8C%E5%8F%89%E6%A0%91.html +## 总结 + +可以看看贪心算法的总结,贪心本来就没啥规律,能写出个总结篇真的不容易了。 +https://programmercarl.com/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95%E6%80%BB%E7%BB%93%E7%AF%87.html + diff --git a/notes/src/day37/lc738.md b/notes/src/day37/lc738.md new file mode 100644 index 0000000..7311701 --- /dev/null +++ b/notes/src/day37/lc738.md @@ -0,0 +1,69 @@ +# 738.单调递增的数字 + +```cpp +class Solution { +public: + int monotoneIncreasingDigits(int n) { + vector a; + int nn = n; + while(n > 0) { + int item = n % 10; + a.push_back(item); + n /= 10; + } + reverse(a.begin(),a.end()); + for (int i = 1; i < a.size(); i ++ ) { + if (a[i] < a[i-1]) { + int cnt = a.size() - i; + int shift = cnt; + int right = 0; + while (cnt > 0) { + right *= 10; + right += 9; + cnt -- ; + } + int left = 0; + for (int j = 0; j < i; j ++ ) { + left *= 10; + left += a[j]; + } + left = monotoneIncreasingDigits(left - 1); + return left * 10 * shift + right; + } + } + return nn; + // 1232 -> 1229 + // 2312 -> 2299 + // 9123 -> 8999 + // 100001 -> + } +}; +``` + + +332 -- 329 × +332 -- 299 √ +想不出了,原来是要从后往前 + +```cpp +class Solution { +public: + int monotoneIncreasingDigits(int n) { + string s = to_string(n); + int flag = s.size(); + for ( int i = s.size() - 1; i > 0; i -- ) { + if (s[i-1] > s[i]) { + flag = i; + s[i-1] -- ; + } + } + for ( int i = flag; i < s.size() ; i ++ ) { + s[i] = '9'; + } + return stoi(s); + } +}; +``` + +草 真优雅 + diff --git a/notes/src/day37/lc968.md b/notes/src/day37/lc968.md new file mode 100644 index 0000000..0090aad --- /dev/null +++ b/notes/src/day37/lc968.md @@ -0,0 +1,59 @@ +# 968.监控二叉树 + +```cpp +class Solution { +public: + int cnt = 0; + bool f(TreeNode*r) { // should not be null + // if(!r)return true; + if(!r->left&&!r->right)return false; // no monitor + bool lres = false; + if(r->left)res=f(r->left); + if(!res&&r->right)res=f(r->right); + if(res == true) return false; + else { + cnt ++ ; + return true; + } + } + int minCameraCover(TreeNode* r) {if(!r->left&&!r->right)return 1; + f(r); + return cnt; + } +}; +``` + +想不明白:在二叉树中如何从低向上推导呢? + +```cpp +class Solution { +public: + int cnt = 0; + int f(TreeNode*p) { + // 0 -- 没有覆盖 + // 1 -- 有覆盖了 + // 2 -- 有摄像头 + if(!p)return 1; + int l = f(p->left); + int r = f(p->right); + if (l==1 && r==1) return 0;////// + if (l==0 || r==0) {////////////// + cnt ++ ; + return 2; + } + return 1; + } + int minCameraCover(TreeNode* r) {if(!r->left&&!r->right)return 1; + if(f(r)==0)cnt++;/////// + return cnt; + } +}; +``` + +[0,0,null,null,0,0,null,null,0,0] + 0 + 0 n +n 0 + 0 n +n 0 + 0 \ No newline at end of file diff --git a/notes/src/remains.md b/notes/src/remains.md index 2490d9b..0090aad 100644 --- a/notes/src/remains.md +++ b/notes/src/remains.md @@ -1,874 +1,3 @@ -# 39. 组合总和 - -```cpp -class Solution { -public: - vector>res; - vectorcur;vectorcandidates; - int s=0,t; - void bt(int start){ - if(s>=t){if(s==t)res.push_back(cur);return;} - for(int j=start;j> combinationSum(vector& candidates, int target) { - t=target;this->candidates=candidates;bt(0);return res; - } -}; -``` - -# 40.组合总和II - -```cpp -class Solution { -public: - vector>res; - vectorcur;vectorcandidates; - int s=0,t; - void bt(int start){ - if(s>=t){if(s==t)res.push_back(cur);return;} - for(int j=start;jstart&&candidates[j]==candidates[j-1])continue; - cur.push_back(i);s+=i; - bt(j+1); - cur.pop_back();s-=i; - } - } - vector> combinationSum2(vector& candidates, int target) { - t=target;sort(candidates.begin(),candidates.end());this->candidates=candidates;bt(0);return res; - } -}; -``` - -`if(j>start&&candidates[j]==candidates[j-1])continue;`这而想了很久,一直以为是j大于0 - -为了结果不重复,所以剪枝是必须要进行的操作 - -# 131.分割回文串 - -```cpp -class Solution { -public: - string s;vector>res;vectorcur; - bool valid(int l,int r){ - int lptr=l,rptr=r;while(lptr<=r){if(s[lptr]!=s[rptr])return false;lptr++;rptr--;}return true; - } - void bt(int start){ - if(start==s.size()){res.push_back(cur);return;} - for(int i=start;i> partition(string s) { - this->s=s;bt(0);return res; - } -}; -``` - -# 93.复原IP地址 - -```cpp -class Solution { -public: - vectorres;string cur;string s;void bt(int start,int cnt){ - if(cnt==4||start>=s.size()){if(cnt==4&&start==s.size())res.push_back(string(cur.begin(),cur.end()-1));return;} - for(int i=1;i<=3;i++){ - string sub=string(s.begin()+start,s.begin()+start+i); - if(valid(sub)){ - auto l=cur.size(); - cur+=sub+"."; - bt(start+i,cnt+1); - cur.erase(l); - } - } - } - bool valid(string s){ - if(s.size()==0)return false; - if(s[0]=='0')return s.size()==1; - int a=stoi(s);return a>=0 && a<=255; - } - vector restoreIpAddresses(string s) {this->s=s; - bt(0,0);return res; - } -}; -``` - -# 78.子集 - -```cpp -class Solution { -public:vector>res;vectorcur;vectorv;void bt(int start){res.push_back(cur); - if(start>=v.size())return;for(int i=start;i> subsets(vector& nums) { - v=nums;bt(0);return res; - } -}; -``` - -如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么**组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点**! - -# 90.子集II - -```cpp -class Solution { -public:vector>res;vectorcur;vectorv;void bt(int start){res.push_back(cur); - if(start==v.size())return;for(int i=start;istart&&v[i]==v[i-1])continue; - cur.push_back(v[i]);bt(i+1);cur.pop_back(); - } -} - vector> subsetsWithDup(vector& nums) { - sort(nums.begin(),nums.end());v=nums;bt(0);return res; - } -}; -``` - -# 491.递增子序列 - -```cpp -class Solution { - public:vector>res; - vectorcur; - vectorv; - void bt(int start){ - if(cur.size()>1)res.push_back(cur); - if(start>=v.size())return; - unordered_set uset; - for(int i=start;i=cur.back()) - { - if(uset.find(v[i])!=uset.end())continue; - uset.insert(v[i]); - cur.push_back(v[i]);bt(i+1);cur.pop_back(); - } - } - - } - vector> findSubsequences(vector& nums) {v=nums;bt(0);return res;} -}; - -``` - -本层访问过的元素不再访问,误以为是前后不用重复的就行,需要使用set - -# 46.全排列 - - -https://programmercarl.com/0046.%E5%85%A8%E6%8E%92%E5%88%97.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE -```cpp -class Solution { -public: - vectorused; - vectorcur; - vectorv; - vector>res; - void bt() { - if(cur.size()==v.size()) - {res.push_back(cur);return;} - for(int i=0;i> permute(vector& nums) { - v=nums;used=vector(v.size(),0);bt();return res; - } -}; -``` -# 47.全排列 II - -```cpp -class Solution { -public: - vectorused; - vectorcur; - vectorv; - vector>res; - void bt() { - if(cur.size()==v.size()){ - res.push_back(cur);return; - } - for(int i=0;i0&&v[i]==v[i-1]&&used[i-1]==0)continue; - used[i]=1; - cur.push_back(v[i]); - bt(); - cur.pop_back(); - used[i]=0; - } - } - vector> permuteUnique(vector& nums) { - v=nums;sort(v.begin(),v.end()); - used=vector(v.size(),0); - bt(); - return res; - } -}; -``` - -如何剪枝同一层使用过的:`&&used[i-1]==0`,一下子想不到。 - -# 332.重新安排行程 - -```cpp -class Solution { -public: - unordered_map> targets; - vector res; - int ticketNum; - bool bt() { - if(res.size()==ticketNum+1)return true; - for( pair& target: targets[res.back()]) { - if (target.second > 0) { - res.push_back(target.first); - target.second -- ; - if (bt())return true; - res.pop_back(); - target.second ++ ; - - } - } - return false; - } - vector findItinerary(vector>& tickets) { - for(auto v : tickets) { - targets[v[0]][v[1]] ++ ; - } - res.push_back("JFK"); - ticketNum = tickets.size(); - bt(); - return res; - } -}; -``` - -这个我是不会的,完全抄了随想录。 - -本质是,深度优先搜索 - -做之前心里的一些疑虑: -1. 怎么比较字母序大小,结果直接用map自动帮我排好序 -2. 怎么表示这个有向图,然后是用了两个map嵌套 - -# 51. N皇后 - -```cpp -class Solution { -public: - vector> res; - vector chess; - int N; - bool checkpos(int i, int j) { - for(int k=i+1;k=N||y>=N)break; - if(chess[x][y]=='Q')return false; - } - for(int k=0;k=N||y<0)break; - if(chess[x][y]=='Q')return false; - } - return true; - } - void bt(int depth) { - if (depth < 0) { - res.push_back(chess); - return; - } - for(int pos=0;pos> solveNQueens(int n) { - N=n; - for (int i=0;i> b; - bool check(int i,int j,int val) { - for(int k=0;k<9;k++)if(b[i][k]==val||b[k][j]==val)return false; - int ibase = i/3*3, jbase = j/3*3; - for(int u=0;u<3;u++)for(int v=0;v<3;v++)if(b[ibase+u][jbase+v]==val)return false; - return true; - } - bool bt(int pos) { - int i = pos/9, j = pos%9; - if(i==9)return true; - if(b[i][j]!='.')return bt(pos+1); - for(int v=1; v<=9; v++) { - if(check(i,j,'0'+v)) { - b[i][j]='0'+v; - if(bt(pos+1))return true; - b[i][j]='.'; - } - } - return false; // unreachable - } - void solveSudoku(vector>& board) { - b=board; - bt(0); - // for(int i=0;i<9;i++){ - // for(int j=0;j<9;j++){ - // cout< b; // '>' will sort in descending order (reverse), '<' will sort in ascending order -} -class Solution { -public: - int findContentChildren(vector& g, vector& s) { - sort(s.begin(),s.end(),reverseComparator); - sort(g.begin(),g.end(),reverseComparator); - int cnt = 0; - int p = 0; - for (int cookiesize : s) { - while (p < g.size() && g[p] > cookiesize) p ++ ; - if (p >= g.size()) break; - // if (cookiesize >= g[p]) { - cnt ++ ; - p ++; - // } - } - return cnt; - } -}; -``` - -# 376. 摆动序列 - -```cpp -class Solution { -public: - int wiggleMaxLength(vector&v) { - // - auto tail = unique(v.begin(),v.end()); - v.erase(tail,v.end()); - // - if(v.size()<=2)return v.size(); - int cnt = 0; - for (int i = 1; i < v.size() - 1; i ++ ) { - int pdir = v[i] - v[i-1]; - int cdir = v[i+1] - v[i]; - cnt += pdir*cdir<0?1:0; - } - return cnt+2; - } -}; -``` - -去重之后就不用考虑这么多复杂的情况 - -# 53. 最大子数组和 - -```cpp -class Solution { -public: - int maxSubArray(vector& nums) { - int res = INT_MIN; - int cnt = 0; - for (int num : nums) { - cnt += num; - res = max(res,cnt); - if (cnt < 0) cnt = 0; - } - return res; - } -}; -``` - -`res = max(res,cnt);`和`if (cnt < 0) cnt = 0;`这两行顺序一开始搞错了, 导致input只是一个-1的时候有问题 - -# 122. 买卖股票的最佳时机 II - - -如果想到其实最终利润是可以分解的,那么本题就很容易了! - - -```cpp -class Solution { -public: - int maxProfit(vector& prices) { - int res = 0; - for ( int i = 1; i < prices.size(); i ++ ) { - int a = prices[i] - prices[i-1]; - res += a>0?a:0; - } - return res; - } -}; -``` - -# 55. 跳跃游戏 - -```cpp -class Solution { -public: - bool canJump(vector& nums) { - int dst = 0; - int i = 0; - while (i <= dst) { - dst = max(dst,i+nums[i]); - i ++ ; - if (dst >= nums.size() - 1) return true; - } - return false; - } -}; -``` -# 45.跳跃游戏 II - -```cpp -class Solution { -public: - int jump(vector& nums) { - int res = 1; - int predist = nums[0]; - int maxdist = predist; - int i = 0; - if(nums.size()==1)return 0; - if (maxdist>=nums.size()-1) return 1; - while (i <= maxdist) { - int nextdist = i+nums[i]; - maxdist=max(maxdist,nextdist); - if (maxdist>=nums.size()-1) break; - if (i == predist) { - res ++ ; - predist = maxdist; - } - i ++ ; - - } - return res + 1; - } -}; -``` - -# 1005.K次取反后最大化的数组和 - -```cpp -class Solution { -public: - int largestSumAfterKNegations(vector& v, int k) { - sort(v.begin(),v.end()); - for(int& i: v){ - if (i >= 0) break; - i=-i;k--;if(k==0)break; - }if(k==0)return accumulate(v.begin(), v.end(), 0); - sort(v.begin(),v.end()); - while (k>0){v[0]=-v[0];k--;} - return accumulate(v.begin(), v.end(), 0); - } -}; -``` - -# 134. 加油站 - -```cpp -class Solution { -public: - int canCompleteCircuit(vector& g, vector& c) { - int n = g.size(); - vector h(n,0); - // h[i] -> gas change from i-1 -> i - h[0] = g[n-1] - c[n-1]; - for (int i = 1 ; i < n ; i ++ ) { - h[i] = g[i-1]-c[i-1]; - } - int start = 0; - int pos = start; - int csum = 0; - while (pos < start + n && start < n) { - csum += h[(1+pos)%n]; - if (csum < 0) { - start = pos + 1; - csum = 0; - } - pos ++ ; - } - return start& v) { - // 1,3,4,5,2 - // 1,2,3,4,1 - // - vectorres(v.size(),1); - for (int i = 1 ; i < v.size() ; i ++ ) { - if (v[i] > v[i-1]) res[i] = res[i-1] + 1; - } - for (int i = v.size() - 2; i >= 0 ; i -- ) { - if (v[i] > v[i+1] && res[i] <= res[i+1]) res[i] = res[i+1] + 1; - } - return accumulate(res.begin(),res.end(),0); - } -}; -``` - -WA了一发漏了`&& res[i] <= res[i+1]` - -# 860.柠檬水找零 - -```cpp -class Solution { -public: - bool lemonadeChange(vector& bills) { - int c5 = 0, c10 = 0; - for ( int bill : bills) { - switch (bill) { - case 5: - c5 ++ ; - break; - case 10: - if (c5 == 0) return false; - c5 -- ; - c10 ++ ; - break; - default: - if (c10>0&&c5>0) { - c10 -- ; c5 -- ; continue; - } - if (c5 >= 3) { - c5 -= 3; continue; - } - return false; - break; - } - } - return true; - } -}; -``` - - -模拟题 - -# 406.根据身高重建队列 -错误解答 -```cpp - -bool f(const vector&a, const vector&b) { - if (a[1]==b[1])return a[0]>b[0];return a[1]> reconstructQueue(vector>& p) { - vector> res; - sort(p.begin(),p.end(),f); - for ( auto peo: p ) { - if (peo[1]!=0) break; - res.push_back(peo); - } - reverse(res.begin(),res.end()); - for (int i = res.size(); i < p.size(); i ++ ) { - auto x = p[i]; - int insert_pos = 0; int cnt = 0; - while ( cnt < x[1] + 1 ) { - if (p[insert_pos][0] >= x[0]) cnt ++ ; - insert_pos ++ ; - } - res.insert(res.begin()+insert_pos - 1,x); - } - return res; - } -}; -``` - -> 这道题我没有能够做出来 - -在135. 分发糖果 (opens new window)我就强调过一次,遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。 - -如果两个维度一起考虑一定会顾此失彼。 - -> 我就是错误的按照k来从小到大排序了 - -```cpp - -bool f(vector& a, vector& b){ - if(a[0]==b[0])return a[1]b[0]; -} -class Solution { -public: - vector> reconstructQueue(vector>& p) { - vector> res; - sort(p.begin(),p.end(),f); - for (int i = 0; i < p.size(); i ++ ) { - auto x = p[i]; - int pos = x[1]; - res.insert(res.begin()+pos,x); - } - return res; - } -}; -``` - -先按照身高排序,固定住规律。按照k排序没法获得额外的规律 - -# 452. 用最少数量的箭引爆气球 - -想不出来用什么数据结构 - -```cpp -class Solution { -public: - int findMinArrowShots(vector>& v) { - int res = 1; - sort(v.begin(),v.end()); - for ( int i = 1 ; i < v.size(); i ++ ) { - if ( v[i][0] > v[i-1][1] ) { - res ++ ; - } else { - v[i][1] = min(v[i][1],v[i-1][1]); - } - } - return res; - } -}; -``` - -发现不用数据结构,要点是每次右端点取重合的最小值 - -```plaintext - ====== -==================== -``` - -# 435. 无重叠区间 - -```cpp -bool f(const vector&a,const vector&b) { - if(a[0]==b[0])return a[1]>b[1];return a[0]>& v) { - int res = 0; - sort(v.begin(),v.end(),f); - for ( int i = 1 ; i < v.size(); i ++ ) { - cout << v[i][0] << v[i][1] << endl; - if ( v[i][0] >= v[i-1][1] ) { - } else { - res ++ ; - // v[i][1] = min(v[i][1],v[i-1][1]); - } - } - return res; - } -}; -``` - -不会做,不知道怎么处理这种情况 - -```plaintext - ------- ------- ------- ------- -====== ======= ====== ======= ===== -``` - -求`需要移除区间的最小数量,使剩余区间互不重叠` -> 求最大的不交叉区间个数 - -```cpp -bool f(const vector&a,const vector&b) { - return a[1]>& v) { - int cnt = 1; - sort(v.begin(),v.end(),f); - int rend = v[0][1]; - for ( int i = 1 ; i < v.size(); i ++ ) { - if (rend <= v[i][0]) { - rend = v[i][1]; - cnt ++ ; - } - } - return v.size() - cnt; - } -}; -``` - -通用技巧,求不重合区间的最大个数 - -# 763.划分字母区间 - -```cpp -class Solution { -public: - vector partitionLabels(string s) { - int v[26] = {0}; - vector res; - for (int i = 0; i < s.size(); i ++ ) { - v[s[i]-'a']=i; - } - int last = v[s[0]-'a']; - int pre = 0; - for (int i = 0; i < s.size(); i ++ ) { - last = max(last,v[s[i]-'a']); - if (last == i) { - res.push_back(i - pre + 1); - pre = i + 1; - } - } - return res; - } -}; -``` - -# 56. 合并区间 - -```cpp -bool f(const vector&a,const vector&b) { - if(a[0]==b[0])return a[1]>res; - vector> merge(vector>& v) { - sort(v.begin(),v.end(),f); - int l = v[0][0], r = v[0][1]; - for ( int i = 1; i < v.size(); i ++ ) { - if (v[i][0]<=r) r = max(r,v[i][1]); - else { - res.push_back(vector{l, r}); - l = v[i][0]; - r = v[i][1]; - } - } - res.push_back(vector{l, r}); - return res; - } -}; -``` - -这个 很直接 - -# 738.单调递增的数字 - -```cpp -class Solution { -public: - int monotoneIncreasingDigits(int n) { - vector a; - int nn = n; - while(n > 0) { - int item = n % 10; - a.push_back(item); - n /= 10; - } - reverse(a.begin(),a.end()); - for (int i = 1; i < a.size(); i ++ ) { - if (a[i] < a[i-1]) { - int cnt = a.size() - i; - int shift = cnt; - int right = 0; - while (cnt > 0) { - right *= 10; - right += 9; - cnt -- ; - } - int left = 0; - for (int j = 0; j < i; j ++ ) { - left *= 10; - left += a[j]; - } - left = monotoneIncreasingDigits(left - 1); - return left * 10 * shift + right; - } - } - return nn; - // 1232 -> 1229 - // 2312 -> 2299 - // 9123 -> 8999 - // 100001 -> - } -}; -``` - - -332 -- 329 × -332 -- 299 √ -想不出了,原来是要从后往前 - -```cpp -class Solution { -public: - int monotoneIncreasingDigits(int n) { - string s = to_string(n); - int flag = s.size(); - for ( int i = s.size() - 1; i > 0; i -- ) { - if (s[i-1] > s[i]) { - flag = i; - s[i-1] -- ; - } - } - for ( int i = flag; i < s.size() ; i ++ ) { - s[i] = '9'; - } - return stoi(s); - } -}; -``` - -草 真优雅 - # 968.监控二叉树 ```cpp