贪心算法练习集
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) 编辑 收藏 举报