leetcode刷题之贪心算法(C++&Java)

(学习参考书:LeetCode101)

贪心算法

贪心算法采用贪心的策略,保证每次操作都是局部最优的,从而使最后得到是全局最优的。

解题步骤:

  1. 将问题分解为若干个子问题,寻找合适的贪心策略
  2. 求解每一个子集的最优解
  3. 将局部最优解迭代成全局最优解

力扣例题

455.分发饼干

分析:

因为饥饿度最小的孩子最容易吃饱,所以优先考虑这个孩子。为了使剩下的饼干尽可能的满足饥饿度更大的孩子,所以应该把大于等于这个孩子饥饿度的且最小的饼干给这个孩子。然后采取同样的策略,直到没有满足的饼干为止。

题解:

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
		//将饼干和孩子从小到大排序
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());

		//初始化辅助变量
        int cnt = 0;
        int j = 0;

		//循环至一方没有剩余
        while(cnt<g.size()&&j<s.size()){
			//当孩子能吃饱时,同时++进行下一组比对
			//当孩子不能吃饱时,这个孩子继续和下一个饼干匹配
            if(g[cnt]<=s[j]){
                ++cnt;
            }
            ++j;
        }

        return cnt;
    }
};
class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);

        int cnt = 0,j = 0;
        while(cnt<g.length&&j<s.length){
            if(g[cnt]<=s[j]){
                ++cnt;
            }
            ++j;
        }

        return cnt;
    }
}

135.分发糖果

分析:

只需要两次遍历,把所有孩子糖果数初始化为1;先从左到右遍历一遍,如果右边孩子的评分比左边的高,则右边更新为左边的糖果数+1;再从右往左遍历,如果左边的右边高,且左边孩子的糖果数不大于右边孩子的糖果数,则左边更新为右边的+1。

题解:

class Solution {
public:
    int candy(vector<int>& ratings) {
        int size = ratings.size();
		//如果只有一个孩子返回1即可
        if(size==1){
            return size;
        }
				
		//创建一个数组,表示每个孩子对应的糖果数,初始值都为1
        vector<int> v(size,1);

		//从左往右遍历
        for(int i=1;i<size;++i){
            if(ratings[i-1]<ratings[i]){
                v[i] = v[i-1]+1;
            }
        }

		//从右往左遍历
        for(int i=size-1;i>0;--i){
            if(ratings[i-1]>ratings[i]){
				//需要判断是否左边已经大于右边
                v[i-1] = max(v[i-1],v[i]+1);
            }
        }
				
		//求和得出需要的总糖果数
        return accumulate(v.begin(),v.end(),0);
    }
};
class Solution {
    public int candy(int[] ratings) {
        int[] candys = new int[ratings.length];
        for(int i=0;i<candys.length;++i){
            candys[i] = 1;
        }

        for(int i=0;i<ratings.length-1;++i){
            if (ratings[i+1]>ratings[i]){
                candys[i+1] = candys[i]+1;
            }
        }
        for(int i=ratings.length-1;i>=1;--i){
            if (ratings[i-1]>ratings[i]){
                if (candys[i-1]<=candys[i]){
                    candys[i-1] = candys[i]+1;
                }
            }
        }

        return IntStream.of(candys).sum();
    }
}

435.无重叠区间

分析:

选择的区间结尾越小,余留给其他区间的空间就越大,就能保留更多的区间。因此采取的贪心策略是,优先保留结尾笑且不相交的区间。先把区间按照结尾大小排序,每次选择结尾最小且与前一个选择的区间不重叠的区间。

题解:

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
		//无区间直接返回0
        if(intervals.empty()){
            return 0;
        }
				
		//使用自定义规则的sort函数对区间按照结尾大小排序
		//这里定义规则的vector<int> a用法没错,但是在力扣上超时
		//应该替换为const auto& a
        sort(intervals.begin(),intervals.end(),
        [](vector<int> a,vector<int> b){
            return a[1]<b[1];
        });

	    int cnt = 0;//计数器
        int start = intervals[0][1];//初始设置为第一个区间的结尾
        for(int i=1;i<intervals.size();++i){
            if(intervals[i][0]<start){
				//当下一个区间的开始与上一个区间的结尾重合时,应该删除该区间
                ++cnt;
            }
            else{
				//当不重合时,更新需要比较的区间的结尾
                start = intervals[i][1];
            }
        }

        return cnt;
    }
};
class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1]-o2[1];
            }
        });

        int cnt = 0;
        int start = intervals[0][1];
        for(int i=1;i<intervals.length;++i){
            if (start>intervals[i][0]){
                ++cnt;
            }
            else{
                start = intervals[i][1];
            }
        }

        return cnt;
    }
}

122.买卖股票的最佳时机2

分析:

由于买卖股票没有限制,因此只需要后一天比前一天价格高就买入,即所有的正值利润都交易。

题解:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size()<=1){
            return 0;
        }

        int cnt = 0;

        for(int i=1;i<prices.size();++i){
            if(prices[i]-prices[i-1]>0){
                cnt+=prices[i]-prices[i-1];
            }
        }

        return cnt;
    }
};
class Solution {
    public int maxProfit(int[] prices) {
        int profit = 0;
        for(int i=0;i<prices.length-1;++i){
            if(prices[i+1]>prices[i]){
                profit += prices[i+1]-prices[i];
            }
        }
        return profit;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值