拆解为子问题最优
局部最优导致全局最优
严格证明可行:数学归纳法,反证法证明贪心可行,一般举反例就行
排序!!!
举简单例子,看看怎么解,能不能推导出一般解法,也就是局部推整体
455. 分发饼干 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int findContentChildren(vector<int>& g, vector<int>& s) { 4 sort(g.begin(),g.end()); 5 sort(s.begin(),s.end()); 6 int num = 0; 7 for(int i=0,j=0;i<g.size()&&j<s.size();i++,j++){ 8 if(g[i]<=s[j]) 9 num++; 10 else 11 i--; 12 } 13 return num; 14 } 15 };
376. 摆动序列 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int wiggleMaxLength(vector<int>& nums) {//初始化难 4 if(nums.size()==0) 5 return 0; 6 if(nums.size()==1) 7 return 1; 8 int startIndex = 0; 9 int temp = nums[startIndex]-nums[startIndex+1]; 10 while(temp==0&&startIndex+1+1<nums.size()){//找到第一个不为0的差值 11 startIndex++; 12 temp = nums[startIndex]-nums[startIndex+1]; 13 } 14 int num = 1; 15 temp*=-1;//自己造一个temp,找到第一个不为0的差值,取他相反数 16 for(int i=startIndex;i+1<nums.size();i++){ 17 if(temp*( nums[i]-nums[i+1])>=0)//逻辑前后就是乘机应当<0 18 continue; 19 temp = nums[i]-nums[i+1]; 20 num++; 21 22 } 23 return num; 24 } 25 };
53. 最大子数组和 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int maxSubArray(vector<int>& nums) { 4 int sum = 0,ans = -1e4; 5 for(int i=0;i<nums.size();i++){ 6 sum+=nums[i]; 7 ans = max(ans,sum); 8 if(sum<0) 9 sum = 0; 10 } 11 return ans; 12 } 13 };
122. 买卖股票的最佳时机 II - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int maxProfit(vector<int>& prices) {//示例一二,共同计算方法,第二天卖就行 4 int ans = 0; 5 for(int i=1;i<prices.size();i++){ 6 if(prices[i]-prices[i-1]>0) 7 ans+=prices[i]-prices[i-1]; 8 } 9 return ans; 10 } 11 };
55. 跳跃游戏 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool canJump(vector<int>& nums) { 4 int mx = 0; 5 for(int i=0;i<nums.size()&&i<=mx;i++){ 6 mx = max(mx,nums[i]+i); 7 } 8 if(mx>=nums.size()-1) 9 return true; 10 return false; 11 } 12 };
45. 跳跃游戏 II - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int jump(vector<int>& nums) { 4 int mx = 0,mxx = 0; 5 int ans = 0; 6 for(int i=0;i<nums.size()&&mx<nums.size()-1;i++){//位置下标 7 for(;i<=mx&&mx<nums.size()-1;i++){ 8 if(mxx<i+nums[i]){ 9 mxx = max(mxx,i + nums[i]); 10 } 11 } 12 if(mx<=mxx){ 13 mx = mxx; 14 ans++; 15 } 16 } 17 return ans; 18 } 19 };
134. 加油站 - 力扣(LeetCode) (leetcode-cn.com)
我自己的想法,类似最大连续区间和
**其实我不认为这种方式是贪心算法,因为没有找出局部最优,而是直接从全局最优的角度上思考问题**。
但这种解法又说不出是什么方法,这就是一个从全局角度选取最优解的模拟操作。
1 class Solution { 2 public: 3 int canCompleteCircuit(vector<int>& gas, vector<int>& cost) { 4 int n = cost.size(),nums[100000] = {0};//差值数组 5 int startindex=-1;//初始化,用于第一位就是大于0,往后sum一直大于0,那么最大连续区间和前一位就是-1 6 for(int i=0;i<cost.size();i++){ 7 nums[i] = gas[i]-cost[i]; 8 } 9 int sum = 0; 10 for(int i=0;i<n;i++){//类似连续区间和最大,找到起始坐标的前一位很快,+1就是起始 11 sum+=nums[i]; 12 if(sum<0){ 13 sum = 0; 14 startindex = i; 15 } 16 } 17 //找到起始位置后还得验证是不是能走完 18 sum=0; 19 int size = 0;//结束for循环用 20 for(int i=startindex+1;size<n;i++){ 21 sum+=nums[i%n]; 22 if(sum<0){ 23 return -1; 24 } 25 size++; 26 } 27 return startindex+1; 28 } 29 };
贪心答案
1 class Solution { 2 public: 3 int canCompleteCircuit(vector<int>& gas, vector<int>& cost) { 4 int curSum = 0; 5 int totalSum = 0; 6 int start = 0; 7 for (int i = 0; i < gas.size(); i++) { 8 curSum += gas[i] - cost[i]; 9 totalSum += gas[i] - cost[i]; 10 if (curSum < 0) { // 当前累加rest[i]和 curSum一旦小于0 11 start = i + 1; // 起始位置更新为i+1 12 curSum = 0; // curSum从0开始 13 } 14 } 15 if (totalSum < 0) return -1; // 说明怎么走都不可能跑一圈了 16 return start; 17 } 18 };
135. 分发糖果 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int candy(vector<int>& ratings) { 4 vector<int>ans(20000,1); 5 int sum = 0; 6 for(int i=0;i<ratings.size();i++){ 7 if(i-1>=0&&ratings[i]>ratings[i-1]){ 8 ans[i] = max(ans[i],ans[i-1]+1); 9 } 10 } 11 for(int i=ratings.size()-1;i>=0;i--){ 12 if(i+1<ratings.size()&&ratings[i]>ratings[i+1]){ 13 ans[i] = max(ans[i],ans[i+1]+1); 14 } 15 } 16 for(int i=0;i<ratings.size();i++) 17 sum+=ans[i]; 18 return sum; 19 } 20 };
860. 柠檬水找零 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 bool lemonadeChange(vector<int>& bills) { 4 vector<int> a(21,0); 5 for(int i=0;i<bills.size();i++){ 6 if(bills[i]==5) 7 a[5]++; 8 else if(bills[i]==10){ 9 if(a[5]==0) 10 return false; 11 a[5]--; 12 a[10]++; 13 }else if(bills[i]==20){ 14 if(a[10]>=1&&a[5]>=1){ 15 a[10]--; 16 a[5]--; 17 a[20]++; 18 }else if(a[5]>=3){ 19 a[5]-=3; 20 a[20]++; 21 }else 22 return false; 23 } 24 25 } 26 return true; 27 } 28 };
452. 用最少数量的箭引爆气球 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution {// static bool cmp(const vector<int>& a, const vector<int>& b) {return a[0] < b[0]; } 2 public: 3 int findMinArrowShots(vector<vector<int>>& points) {//思路混乱,化整体为局部,就看第一个先。无序的一定排序看看 4 sort(points.begin(),points.end());//排序啊我是傻逼 5 int ans = 0; 6 long long end = -2147489999; 7 for(int i=0;i<points.size();i++){ 8 if(end>=points[i][0]){ 9 end = min(end,(long long)points[i][1]); 10 }else { 11 end = points[i][1]; 12 ans++; 13 } 14 } 15 return ans; 16 } 17 };
56. 合并区间 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 vector<vector<int>> merge(vector<vector<int>>& intervals) { 4 vector<vector<int>> ans; 5 vector<int> path(2);//老忘记加大小 6 if(intervals.size()==0) 7 return ans; 8 sort(intervals.begin(),intervals.end()); 9 path[0] = intervals[0][0]; 10 path[1] = intervals[0][1]; 11 for(int i=1;i<intervals.size();i++){ 12 if(path[1]>=intervals[i][0]){ 13 path[1] = max(path[1],intervals[i][1]); 14 }else{ 15 ans.push_back(path); 16 path[0] = intervals[i][0]; 17 path[1] = intervals[i][1]; 18 } 19 } 20 ans.push_back(path); 21 return ans; 22 } 23 };
738. 单调递增的数字 - 力扣(LeetCode) (leetcode-cn.com)
1 class Solution { 2 public: 3 int monotoneIncreasingDigits(int n) { 4 string strNum = to_string(n); 5 int startIndex = strNum.size(); 6 for(int i = strNum.size()-1;i>0;i--){ 7 if(strNum[i-1]>strNum[i]){ 8 strNum[i-1]--; 9 startIndex = i; 10 } 11 } 12 for(int i=startIndex;i<strNum.size();i++){ 13 strNum[i] = '9'; 14 } 15 return stoi(strNum); 16 } 17 };