KID_XiaoYuan

导航

贪心算法练习集

455. 分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

注意:

你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。

示例 1:

输入: [1,2,3], [1,1]

输出: 1

解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
示例 2:

输入: [1,2], [1,2,3]

输出: 2

解释:
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/assign-cookies
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 解题思路:

对饼干数组和孩子数组进行升序排序。

分析:那么对第cookie个饼干,如果不能满足孩子child,那么肯定也满足不了child以后的孩子

所以分两种情况:

1:第cookie个饼干>=第child个孩子的需求

这时候满足条件,child++,cookie++ 统计数counts++;

2:第cookie个饼干<第child个孩子的需求

这时候cookie++,换一个更大的饼干。

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        int counts =0;
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int child = 0,cookie = 0;
        while(child < g.size() && cookie < s.size())
        {
            if(g[child] <= s[cookie])
            {
                counts++;
                child++;
                cookie++;
            }
            else
            {
                cookie++;
            }
        }
        return counts;
    }
};

 

376. 摆动序列

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。

例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。

示例 1:

输入: [1,7,4,9,2,5]
输出: 6
解释: 整个序列均为摆动序列。
示例 2:

输入: [1,17,5,10,13,15,10,5,16,8]
输出: 7
解释: 这个序列包含几个长度为 7 摆动序列,其中一个可为[1,17,10,13,10,16,8]。
示例 3:

输入: [1,2,3,4,5,6,7,8,9]
输出: 2

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/wiggle-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析:

利用状态机模型对数列的状态进行判断并不断转换

 

 

 

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
    if(nums.size() < 2)
    {
        return nums.size();
    }
    int max_length = 1;
    static const int BEGIN_ = 1;
    static const int UP_ = 2;
    static const int DOWN_ = 3;
    int STATE = BEGIN_;
    for(int i = 1; i < nums.size();i++)//从第二个元素开始扫描
    {
        switch(STATE)
        {
        case BEGIN_:
            {
                if(nums[i-1] < nums[i])
                {
                    max_length ++;
                    STATE = UP_;
                }
                else if(nums[i-1] > nums[i])
                {
                    max_length ++;
                    STATE = DOWN_;
                }
                break;
            }
        case UP_:
            {
                if(nums[i-1] > nums[i])
                {
                    max_length ++;
                    STATE = DOWN_;
                }
                break;
            }
        case DOWN_:
            {
                if(nums[i-1] < nums[i])
                {
                    max_length ++;
                    STATE = UP_;
                }
                break;
            }
        }
    }
    return max_length;
    }
};

 

402. 移掉K位数字

给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:

num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
示例 1 :

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
示例 2 :

输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :

输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-k-digits
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析:

使用栈存储最终结果或者删除。

从高位往低位遍历num,如果遍历数字大于栈顶元素,则将该数字push入栈

如果小于栈顶元素则进行pop弹栈,直到栈空或者不能再删除数字。(K==0)或者栈顶小于当前元素为止。

 

注意的地方:

如果一次遍历后K不为0,则继续循环直到K为0为止(说明一轮的删除之后还未完成任务)

如果最高位数字不为0或者栈不空的时候可以把当前数字入栈。

class Solution {
public:
    string removeKdigits(string num, int k) {
        vector <int> S;//模拟栈
        string result  = "";//保存最终结果
        for(int i = 0; i < num.length(); i++)
        {
            int number = num[i] - '0';
            while(S.size() != 0 && S[S.size() - 1] > number && k >0)
            {//当栈不为空,栈顶元素大于number的时候,仍然可以删除数字时while继续循环
                S.pop_back();
                k--;
            }
            if(number != 0 || S.size() != 0)
            {
                S.push_back(number);//将数字number入栈
            }
        }
         while(S.size() != 0 && k > 0)
            {//如果栈不空且仍然可以删除数字,删除数字后更新K
                S.pop_back();
                k--;
            }
            for(int i = 0; i < S.size(); i++)
            {//将栈从头遍历,结果存到result中
                result.append(1,'0' + S[i]);
            }
        if(result == "")
        {
            result ="0";
        }
        return result;
}
};

 

55. 跳跃游戏

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个位置。

示例 1:

输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例 2:

输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

1:求从第i个位置最远可以跳到第index[i]个位置,建立index数组,表示第i个位置最远可以跳nums[i]+i步

2:初始化:设置变量jump代表当前所处的位置,初始化为0。设置变量max_index表示从第0个位置到第 jump 个位置的过程中所能到达的最远位置 初始化为index[0]。

3:利用jump扫描index数组,直到jump到达index数组尾部或jump超过max_index,扫描过程中,更新max_index。

4:若jump是最终的数组长度,返回true否则为false。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        vector <int> index;//最远可跳的位置
        for(int i = 0; i < nums.size();i++)
        {
            index.push_back(i + nums[i]);//计算index数组
        }
        int jump = 0;//初始jump和max_index
        int max_index =index[0];
        while(jump < index.size() && jump <= max_index)
        {
            if(max_index < index[jump])
            {
                max_index = index[jump];//如果可以跳的更远就更新max_inde
            }
            jump++;//扫描数组
        }
        if(jump == index.size())
        {
            return true;//如果可以到达数组尾部就是真
        }

        else
        {
            return false;
        }
    }
};

 

45. 跳跃游戏 II

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

示例:

输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
  从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:

假设你总是可以到达数组的最后一个位置。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

跳跃路径选择:假设当前位置可以跳到位置i,那么就选取从当前位置到位置i之间的能跳的最远的位置进行跳跃。

算法设计:

设置current_max_index表示当前可以到达的最原位置

设置pre_max_max_index为在遍历各个位置过程中,各个位置可以到达的最原位置

设置jump_min表示最小跳跃次数

利用i遍历muns数组,如果i超过current,则jump+1,current = pre_max

在遍历过程中,如果index[i]更大,则更新pre_max = index[i]

(index[i] = nums[i]+i)

初始化:current为nums[0]

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size() < 2)
        {
            return 0;//长度为1则不用跳跃
        }
        int current_max_index = nums[0];//当前最远可以到达的位置
        int pre_max_max_index = nums[0];//遍历各个位置中可以到达的最远位置
        int jump_min = 1;
        for(int i = 0; i < nums.size(); i++)
        {
            if(i > current_max_index)//若无法再向前移动了,才进行跳跃
            {
                jump_min++;//更新当前可到达的最远位置
                current_max_index = pre_max_max_index;
            }
            if(pre_max_max_index < nums[i] + i)
            {
                pre_max_max_index = nums[i] + i;//更新pre_max_max_index
            }
        }
        return jump_min;
    }
};

 

452. 用最少数量的箭引爆气球

在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以y坐标并不重要,因此只要知道开始和结束的x坐标就足够了。开始坐标总是小于结束坐标。平面内最多存在104个气球。

一支弓箭可以沿着x轴从不同点完全垂直地射出。在坐标x处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。

Example:

输入:
[[10,16], [2,8], [1,6], [7,12]]

输出:
2

解释:
对于该样例,我们可以在x = 6(射爆[2,8],[1,6]两个气球)和 x = 11(射爆另外两个气球)。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析:每次优先射中当前重叠气球最多的位置。

若下个气球开始坐标在当前气球的结束坐标前,则我们可以用一支箭一起引爆;若下个气球的开始坐标在当前气球的结束坐标后,则我们必须增加箭的数量。并跟踪下个气球的结束坐标。

算法设计:

根据 x_end 将气球进行排序。
初始化 first_end 为第一个气球结束的坐标 points[0][1]。
初始化箭的数量 arrows = 1。
遍历所有的气球:
如果气球的开始坐标大于 first_end:
则增加箭的数量。
将 first_end 设置为当前气球的 x_end。
返回 arrows。

class Solution {
  public:
  int findMinArrowShots(vector<vector<int>>& points) {
    if (points.size() == 0) return 0;

    // sort by x_end
    sort(begin(points), end(points),
         [](const vector<int> &o1, const vector<int> &o2) {
      return (o1[1] < o2[1]);
    });

    int arrows = 1;
    int xStart, xEnd, firstEnd = points[0][1];
    for (auto p : points) {
      xStart = p[0];
      xEnd = p[1];
      // if the current balloon starts after the end of another one,
      // one needs one more arrow
      if (firstEnd < xStart) {
        arrows++;
        firstEnd = xEnd;
      }
    }
    return arrows;
  }
};

 OPJ 2431

一辆卡车,初始时,距离终点L,油量为P,在起点到终点途中有n个加油站,每个加油站油量有限,而卡车的油箱容量无限,卡车在行车途中,每走一个单位的距离消耗一个单位的油量,给定n个加油站距离终点的距离以及油存储量。问卡车是否能到达终点,如果可达,最少需要加多少次油,否则输出-1.

例:

输入:

4
4 4
5 2
11 5
15 10
25 10

输出:

2

思路分析:

设置一个最大堆用来存储经过加油站的汽油量。

按照从起点到终点的方向,遍历各个加油站之间的距离。

每次需要走两个加油站之间的距离d,如果发现汽油不够走距离d时候,从最大堆中取出一个汽油添加,直到可以足够走距离d。

如果最大堆的汽油都添加了还是不够行进距离d,则说明无法到达终点。

当前油量P减少d。

将当前加油站的油量添加到最大堆。

#include<stdio.h>
#include<queue>
#include<vector>
#include<functional>
#include<map>
#include<algorithm>
#include<string>
using namespace std;
bool cmp (const pair <int,int> &a, const pair <int,int> &b)
{
    return a.first > b.first;
}
int get_min_stop_num(int L,int P,vector <pair<int,int> > &stop)
{
    priority_queue <int> Q;
    int result = 0;//加油次数
    stop.push_back(make_pair(0,0));
    sort(stop.begin(),stop.end(),cmp);
    for(int i=0; i <stop.size();i++)
    {
        int dis = L - stop[i].first;
        while(!Q.empty() && P < dis)
        {
            P += Q.top();
            Q.pop();
            result++;
        }
        if(Q.empty()&& P < dis)
        {
            return -1;
        }
        P = P - dis;
        L = stop[i].first;
        Q.push(stop[i].second);
    }
    return result;
}

int main()
{
    vector<pair<int,int> > stop;
    int N,L,P,distance,fuel;
    scanf("%d",&N);
    for(int i = 0; i < N; i++)
    {
        scanf("%d %d",&distance,&fuel);
        stop.push_back(make_pair(distance,fuel));
    }
    scanf("%d %d",&L,&P);
    printf("%d\n",get_min_stop_num(L,P,stop));

return 0;
}

 

posted on 2020-02-03 22:48  KID_XiaoYuan  阅读(248)  评论(0编辑  收藏  举报