zoukankan      html  css  js  c++  java
  • 贪心算法练习集

    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
    ",get_min_stop_num(L,P,stop));
    
    return 0;
    }
  • 相关阅读:
    P1106 删数问题 / U83355 删数问题【升级版】
    P1955 [NOI2015] 程序自动分析
    P4447 [AHOI2018初中组]分组
    P1308 [NOIP2011 普及组] 统计单词数
    Django | 页面数据的缓存与使用
    Python 虚拟环境 | Mac/Linux下如何避坑安装配置Virtualenv
    python虚拟环境 | virtualenv 的简单使用 (图文)
    机器学习 | 浅谈K-近邻算法
    特征缩放 | 归一化和标准化 (下)
    简析方差、标准差与数值离散程度
  • 原文地址:https://www.cnblogs.com/KID-XiaoYuan/p/12257872.html
Copyright © 2011-2022 走看看