【贪心问题总结】

贪心问题

455.分发饼干
题解:让胃口最小的孩子吃最小的饼干。能够吃饱的孩子个数小于等于饼干数和孩子数的最小值。

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
    sort(g.begin(), g.end());
    sort(s.begin(), s.end());
    int i = 0, j = 0;
    while(i < g.size() && j < s.size())
    {
    	if(g[i] <= s[j])	//胃口最小的孩子能吃饱时
    	{
    		i++;			//每吃饱一个i加一,因此i即为能吃饱的孩子数
    		j++;
    	}
    	else				//吃不饱时判断下一个饼干能否吃饱
    		j++;
    }
    return i;
};

135.分发糖果
题解:由于每个孩子最少会分配一个糖果,可以建立一个全为1且大小与孩子数一致的数组,代表每个孩子最少获得的糖果数。由于相邻两个孩子评分更高的会获得更多的糖果,因此有两种情况,单增与单减:单增子序列中第一个孩子获得一个糖果,其他孩子获得的糖果数为前一个孩子糖果数加一;单减子序列中最后一个孩子获得一个糖果,其他孩子为后一个孩子糖果数加一。由于单增子序列与单减子序列会出现重叠元素,因此进一步考虑如下例子[1,2,3,4,2,1],当单增遍历过后数组为[1,2,3,4,1,1],单减遍历时要判断前一个孩子的糖果数是否小于等于现在孩子的糖果数,只有满足上述条件才能继续使用单减子序列的规律。因此代码如下:

class Solution {
public:
    int candy(vector<int>& ratings) {
    	if(ratings.size() == 1)
    		return 1;
		vector<int> a(ratings.size(), 1);
		for(int i = 1;i<ratings.size();i++)		//单增遍历
		{
			if(ratings[i-1] < ratings[i])
				a[i] = a[i-1] + 1;
		}
		for(int i = ratings.size() - 1;i > 0;i--)	//单减遍历
		{
			if(ratings[i-1] > ratings[i])
				if(a[i-1] <= a[i])
					a[i-1] = a[i] + 1; 
		}
		int sum = 0;
		for(int i = 0;i<a.size();i++)
		{
			sum+=a[i];
		}
		return sum;
    }
};

605.种花问题
题解:由于题目保证所给数组不会出现1与1相邻,因此当flowerbed[i] = 1时,可能种植的位置为i+2;当flowerbed[i] = 0时,如果flowerbed[i+1] = 1则不能种植,可能种植的位置为i+3,若flowerbed[i+1] = 0则可以种植。考虑特殊情况[1, 0, 0],若flowerbed[i] = 0,且i为最后一个地址,则也可以种植。

class Solution {
public:
    bool canPlaceFlowers(vector<int>& flowerbed, int n) {
    	if(n == 0)
    		return true;
    	int i = 0;
    	while(i < flowerbed.size())
    	{
    		if(flowerbed[i] == 1)
    			i+=2;
    		else
    		{
    			if(i == flowerbed.size() - 1 || flowerbed[i+1] == 0)
    			{
    				n--;
    				i+=2;
    			}
    			else
    			{
    				i+=3;
    			}
    		}
    	}
    	return n<=0;
    }
};

122.买卖股票的最佳时机||
题解:买卖股票使得收益最大只需将所有的单增子序列找出,统计单增子序列差的和或最后元素和第一个元素差的和即可。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
    	int sum = 0;
    	for(int i = 1;i<prices.size();i++)
    	{
    		if(prices[i-1] < prices[i])
    			sum+=prices[i] - prices[i-1];
    	}
    	return sum;
    }
};

665.非递减数列
题解:统计数组中是否存在下降的元素,当下降元素超过一个则return false;若下降元素为0则return true;若下降元素为一个,则需根据下降元素的位置分情况讨论:当下降元素位置为第二个时,在这之后的元素全为非递减数列,故 return true;当下降元素的位置为最后一个时,前面的其他元素组成非递减数列,故return true;其他一般情况下,需要判断 i-1 与 i+1 位置的元素大小关系或 i-2 与 i 位置元素的大小关系是否满足非递减,如[1,2,3,4,3,3]与[1,2,3,6,3,5]。

class Solution {
public:
    bool checkPossibility(vector<int>& nums) {
    	int sum = 0;
    	int index = 0;
    	for(int i = 1;i<nums.size();i++)
    	{
    		if(nums[i-1] > nums[i])
    		{
    			sum++;
    			index = i;
    		}
    	}
    	if(sum > 1)
    		return false;
    	else if(sum == 1)
    	{
    		if(index == 1 || index == nums.size() - 1)
    			return true;
    		else if(nums[index - 1] <= nums[index + 1] || nums[index - 2] <= nums[index])
    			return true;
    		return false;
    	}
    	return true;
    }
};

435.无重叠区间
题解:由于区间终点大于起点,故通过对终点升序排列,可以保证排列之后的区间终点大于等于前一个区间的终点,此时出现区间重叠的情况只有第i个区间的起点小于前一个区间的终点(相等不算重叠):若重叠则剔除重叠区间,剔除区间有剔除终点大的区间与剔除终点小的区间两种,为保证剔除区间数最小即最终的区间覆盖长度最长,应剔除终点大的区间并使当前最终区间的终点不变;若不重叠,则当前最终区间的终点变长。代码如下:

class Solution {
public:
	static bool compare(const vector<int>& a, const vector<int>& b)
	{
		return a[1] < b[1];
	}
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
    	sort(intervals.begin(),  intervals.end(), compare);
    	int res = 0, pre = intervals[0][1];
    	for(int i = 1;i<intervals.size();i++)
    	{
    		if(pre > intervals[i][0])
    		{	
    			res++;
    		}
    		else
    		{
    			pre = intervals[i][1];
			}
    	}
    	return res;
    }
};

452.用最少数量的箭引爆气球
题解:本题也要针对重叠区间进行操作,因此同上题将区间按终点升序排列。与上题不同的是,上题寻找非重叠区间的并集(终点与起点相同不算重合),本题寻找重叠区间的交集(终点与起点相同算重合),交集包括的区间数越多需要的箭越少。故当重叠发生时,当前最终区间的终点不变,所需箭数不变;若不重叠则所需箭数增加,当前最终区间的终点改变。代码如下:

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
    	sort(points.begin(), points.end(), [](const vector<int>& a, const vector<int>& b)
    	{
    		return a[1] < b[1];
    	});
    	int res = 1, pre = points[0][1];
    	for(int i = 1;i<points.size();i++)
    	{
    		if(pre < points[i][0])
    		{
    			pre = points[i][1];
    			res++;
			}
    	}
    	return res;
    }
};

406.根据身高重建队列
题解:题目要求返回一个二维数组,因此创建一个空的二维数组,通过在其中插入元素,完成题目。假设已有一个符合题设的队列存在,身高越高的数组插入队列会影响其后面数组的排序,因此对于一个空队列,在插入数组时应先从身高最高的开始降序遍历插入,从而保证插入数组不会影响已经存在的前后关系(前后关系指某一个数组一直排在另一数组前面或后面,不一定是紧随)。身高相同的数组,前面排的人数越少的,插入会影响同样身高的数组前后关系,因此身高相同的数组应按照前面排的人数大小升序遍历。将二维数组排序后,遍历插入空队列仅需判断排在前面人数的大小与空队列的大小关系。代码如下:

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        vector<vector<int>> res;
        sort(people.begin(), people.end(), [](const vector<int>& a, const vector<int>& b)
        {
            if(a[0] == b[0])
                return a[1] < b[1];
            return a[0] > b[0];
        });
        for(const vector<int>& a : people)
        {
            if(a[1] <= people.size())
            {
                res.insert(res.begin() + a[1], a);
            }
            else
            {
                res.push_back(a);
            }
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值