文章目录【134.加油站】【135.分发糖果】【860.柠檬树找零】【406.根据身高重建队列】【134.加油站】思路每个加油站的剩余量rest[i]为gas[i] - cost[i]。i从0开始累加rest[i]和记为curSum一旦curSum小于零说明[0, i]区间都不能作为起始位置因为这个区间选择任何一个位置作为起点到i这里都会断油那么起始位置从i1算起再从0计算curSum。那有没有可能 [0i] 区间 选某一个作为起点累加到 i这里 curSum是不会小于零呢 如图这里是重点如果 curSum0 说明 区间和1 区间和2 0 那么 假设从上图中的位置开始计数curSum不会小于0的话就是 区间和20。区间和1 区间和2 0 同时 区间和20只能说明区间和1 0 那么就会从假设的箭头初就开始从新选择起始位置了。那么局部最优当前累加rest[i]的和curSum一旦小于0起始位置至少要是i1因为从i之前开始一定不行。全局最优找到可以跑一圈的起始位置。class Solution { public: int canCompleteCircuit(vectorint gas, vectorint cost) { int curSum 0; int totalSum 0; int start 0; for (int i 0; i gas.size(); i) { curSum gas[i] - cost[i]; totalSum gas[i] - cost[i]; if (curSum 0) { // 当前累加rest[i]和 curSum一旦小于0 start i 1; // 起始位置更新为i1 curSum 0; // curSum从0开始 } } if (totalSum 0) return -1; // 说明怎么走都不可能跑一圈了 return start; } };【135.分发糖果】思路这道题目一定是要确定一边之后再确定另一边例如比较每一个孩子的左边然后再比较右边如果两边一起考虑一定会顾此失彼。先确定右边评分大于左边的情况也就是从前向后遍历此时局部最优只要右边评分比左边大右边的孩子就多一个糖果全局最优相邻的孩子中评分高的右孩子获得比左边孩子更多的糖果局部最优可以推出全局最优。如果ratings[i] ratings[i - 1] 那么[i]的糖 一定要比[i - 1]的糖多一个所以贪心candyVec[i] candyVec[i - 1] 1代码如下// 从前向后for(inti1;iratings.size();i){if(ratings[i]ratings[i-1])candyVec[i]candyVec[i-1]1;}如图再确定左孩子大于右孩子的情况从后向前遍历为什么不能从前向后遍历呢因为 rating[5]与rating[4]的比较 要利用上 rating[5]与rating[6]的比较结果所以 要从后向前遍历。如果从前向后遍历rating[5]与rating[4]的比较 就不能用上 rating[5]与rating[6]的比较结果了 。所以确定左孩子大于右孩子的情况一定要从后向前遍历class Solution { public: int candy(vectorint ratings) { vectorint candyVec(ratings.size(), 1); // 从前向后 for (int i 1; i ratings.size(); i) { if (ratings[i] ratings[i - 1]) candyVec[i] candyVec[i - 1] 1; } // 从后向前 for (int i ratings.size() - 2; i 0; i--) { if (ratings[i] ratings[i 1] ) { candyVec[i] max(candyVec[i], candyVec[i 1] 1); } } // 统计结果 int result 0; for (int i 0; i candyVec.size(); i) result candyVec[i]; return result; } };【860.柠檬树找零】思路简单写起来也顺利。class Solution { public: bool lemonadeChange(vectorint bills) { int five 0, ten 0, twenty 0; for(int i 0; i bills.size(); i){ if(bills[i] 5){ five; } if(bills[i] 10){ ten; five--; } if(bills[i] 20){ twenty; if(ten 0){ ten--; five--; }else{ five - 3; } } if(five 0 || ten 0 || twenty 0) return false; } return true; } };【406.根据身高重建队列】思路如果按照k来从小到大排序排完之后会发现k的排列并不符合条件身高也不符合条件两个维度哪一个都没确定下来。那么按照身高h来排序呢身高一定是从大到小排身高相同的话则k小的站前面让高个子在前面。此时我们可以确定一个维度了就是身高前面的节点一定都比本节点高那么只需要按照k为下标重新插入队列就可以了局部最优优先按身高高的people的k来插入。插入操作过后的people满足队列属性全局最优最后都做完插入操作整个队列满足题目队列属性class Solution { public: static bool cmp(const vectorint a, const vectorint b){ if(a[0] b[0]){// 身高相同的话按照k从小到大排序 return a[1] b[1]; } return a[0] b[0];// 否则按照身高从大到小排序 } vectorvectorint reconstructQueue(vectorvectorint people) { sort(people.begin(), people.end(), cmp); vectorvectorint que; for(int i 0; i people.size(); i){ int position people[i][1]; que.insert(que.begin() position, people[i]); } return que; } };插入使用链表会更快class Solution { public: // 身高从大到小排身高相同k小的站前面 static bool cmp(const vectorint a, const vectorint b) { if (a[0] b[0]) return a[1] b[1]; return a[0] b[0]; } vectorvectorint reconstructQueue(vectorvectorint people) { sort (people.begin(), people.end(), cmp); listvectorint que; // list底层是链表实现插入效率比vector高的多 for (int i 0; i people.size(); i) { int position people[i][1]; // 插入到下标为position的位置 std::listvectorint::iterator it que.begin(); while (position--) { // 寻找在插入位置 it; } que.insert(it, people[i]); } return vectorvectorint(que.begin(), que.end()); } };