【LeetCode】贪心 greedy(共38题)
【44】Wildcard Matching
【45】Jump Game II (2018年11月28日,算法群衍生题)
题目背景和 55 一样的,问我能到达最后一个index的话,最少走几步。
题解:
【55】Jump Game (2018年11月27日,算法群)
给了一个数组nums,nums[i] = k 代表站在第 i 个位置的情况下, 我最多能往前走 k 个单位。问我能不能到达最后一个 index。
题解:虽然是贪心分类,我还是用dp解了。dp[i] 代表我能不能到达第 i 个位置。
class Solution {
public:
bool canJump(vector<int>& nums) {
const int n = nums.size();
if (n == ) {return false;}
vector<int> f(n, ); //f[i] 代表第i个index是不是可达
f[] = ;
for (int i = ; i < n; ++i) {
if (f[i]) {
const int k = nums[i];
for (int j = ; j <= k; ++j) {
if (i+j >= n) {break;}
f[i+j] = ;
}
}
}
return f[n-] == ;
}
};
【122】Best Time to Buy and Sell Stock II (2018年11月26日,算法群)
这个题目股票系列里面说了,这里不重复写了。股票系列:https://www.cnblogs.com/zhangwanying/p/9360841.html
【134】Gas Station (2019年1月27日,谷歌tag)
一个圆形的跑道,上面有 N 个加油站,每个加油站能加的油是 gas[i],假设你的车能加无限的油量,从第 i 个加油站跑到第 i+1 个加油站所消耗的油是 cost[i], 返回从第几个加油站能够顺时针跑完一圈,如果从任意一个都不能跑完的话,就返回-1
题解:本题似乎用到了一个数学定理/方法。就是如果能跑完一圈的话,必定存在从一个点开始,任意的点上的油量都不会为负数。
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int total = ;
int sum = ;
int ans = ;
for(int i = ; i < gas.size(); ++i){
sum += gas[i] - cost[i];
total += gas[i] - cost[i];
if(sum < ){
ans = i+;
sum = ;
}
}
return total < ? - : ans;
}
};
【135】Candy (2019年1月27日,谷歌tag)
每个小孩有一个 rating,你要给这些小孩发糖果,满足两条规则:规则1. 每个小孩至少一个糖果; 规则2. 如果一个小孩的rating比它的邻居高,那么他的糖果数量要比邻居多。问发完所有小孩的最少糖果数量。
题解:设置两个数组,一个front,从前往后应该发的糖果数量。一个back,表示从后往前应该发的糖果数量。final[i] = max(front[i], back[i]); O(N) with 2 pass
//每个小孩至少一个糖果,
//如果当前小孩的rating比它前一个小孩大的话,就是它前一个小孩的糖果数量+1
//如果当前小孩的rating比它后一个小孩大的话,就是它后一个小孩的糖果数量+1
class Solution {
public:
int candy(vector<int>& ratings) {
const int n = ratings.size();
vector<int> front(n , ), back(n, );
for (int i = ; i < n; ++i) {
front[i] = ratings[i-] < ratings[i] ? front[i-] + : ;
}
int res = max(front[n-], back[n-]);
for (int i = n - ; i >= ; --i) {
back[i] = ratings[i] > ratings[i+] ? back[i+] + : ;
res += max(front[i], back[i]);
}
return res;
}
};
【253】Meeting Rooms II
题意是252的升级版,给了一个数组,数组里面的每个元素代表一个会议的开始时间和结束时间,问想安排下所有的会议,至少需要多少个会议室。
题解:这个题目在 sort 的分类里面说过,链接:https://www.cnblogs.com/zhangwanying/p/9914941.html
【316】Remove Duplicate Letters
【321】Create Maximum Number
【330】Patching Array
【334】Increasing Triplet Subsequence (2019年2月14日,google tag)(greedy)
给了一个数组 nums,判断是否有三个数字组成子序列,使得子序列递增。题目要求time complexity: O(N),space complexity: O(1)
Return true if there exists i, j, k
such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false.
题解:可以dp做,LIS 最少 nlog(n)。 这个题可以greedy,可以做到O(N). 我们用两个变量,min1 表示当前最小的元素,min2表示当前第二小的元素。可以分成三种情况讨论:
(1)nums[i] < min1, -> min1 = nums[i]
(2)nums[i] > min1 && nums[i] < min2 -> min2 = nums[i]
(3)nums[i] > min2 -> return true
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int min1 = INT_MAX, min2 = INT_MAX;
for (auto& num : nums) {
if (num > min2) {return true;}
else if (num < min1) {
min1 = num;
} else if (min1 < num && num < min2) {
min2 = num;
}
}
return false;
}
};
【358】Rearrange String k Distance Apart (2019年2月17日,谷歌tag) (H)
给了一个非空的字符串 s 和一个整数 k,重新排列这个字符串使得新的字符串相同字母之间的距离至少为 k。返回新的字符串。没有这样的答案的话,返回一个空的字符串。
Input: s = "aabbcc", k = 3
Output: "abcabc"
Explanation: The same letters are at least distance 3 from each other.
题解:我们用贪心的想法,我们选一个字符放在新字符串的当前位置,那么怎么选择这个字符呢,首先它的剩余次数需要是最多的,其次它不能在当前的 k 窗口里面出现过。所以我们用一个mp统计所有字母的频次。然后按照频次从大到小塞到heap里面。我们用k当作一个窗口,循环查找窗口中每个值。每次我们从heap里面弹出一个最大频次的字符,放在当前位置,如果它的频次减去1,剩下的值大于 0 的话,说明这个字符还存在,以后还会用到,那么就把它放在一个 cache 里面,防止在当前的 k 窗口内部继续抽到它。结束了当前 k 的窗口,把 cache 里面所有的元素都放进heap里面。
class Solution {
public:
string rearrangeString(string s, int k) {
if (k == ) {return s;}
int size = s.size();
unordered_map<char, int> mp;
for (auto& c : s) { mp[c]++; }
priority_queue<pair<int, char>> pq;
for (auto& p : mp) {
pq.push(make_pair(p.second, p.first));
}
string res = "";
while (!pq.empty()) {
vector<pair<int, char>> cache;
int count = min(size, k);
for (int i = ; i < count; ++i) {
if (pq.empty()) {return "";}
auto p = pq.top();
pq.pop();
res += string(, p.second);
p.first--;
size--;
if (p.first > ) {
cache.push_back(p);
}
}
for (auto& p: cache) {
pq.push(p);
}
}
return res;
}
};
【376】Wiggle Subsequence
【392】Is Subsequence
【402】Remove K Digits
【406】Queue Reconstruction by Height(2018年11月26日)
给了一个 people 的数组,数组里面每个元素是一个 pair (h, k) 代表 这个人身高是 h, 在排序好的队列中前面有 k 个人的升高大于等于 h。返回这个排序好的队列。
题解:有点类似于插入排序。我们先把people排序,排序按照身高降序,身高相同就按照 k 递增排序。然后做插入排序。对于排序好的people的每个元素 people[i],直接插入ret数组中的 people[i].second = k 这个位置上。
class Solution {
public:
vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
const int n = people.size();
if (n == ) {return people;}
sort(people.begin(), people.end(), cmp);
vector<pair<int, int>> ret;
for (int i = ; i < people.size(); ++i) {
ret.insert(ret.begin() + people[i].second, people[i]);
}
return ret;
}
static bool cmp(const pair<int, int>& p1, const pair<int, int>& p2) {
if (p1.first == p2.first) {
return p1.second < p2.second;
}
return p1.first > p2.first;
}
};
【435】Non-overlapping Intervals (2018年11月26日)
这题应该见过了orz,莫名的熟悉。题意就是给了一堆线段,问这些线段在不重叠的前提下,最少要剔除几条满足这个线段不重叠的条件。
题解:最少剔除几条才能让所有线段不重叠,其实翻译过来,就是这些线段最多多少条不重叠。我们想这条直线上放尽可能多的线段,需要什么样的策略呢?就是第一条线段的末端的数值尽可能的小,这样后面能选择的空间才比较大。
所以先排序,按照线段末端从从小到大排序。然后贪心一个一个处理。(唯一一个注意点是线段的头尾都有可能是负数。)
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
class Solution {
public:
int eraseOverlapIntervals(vector<Interval>& intervals) {
const int n = intervals.size();
if (n == ) {return n;}
sort(intervals.begin(), intervals.end(), cmp);
int cnt = ;
int b = intervals[].start;
for (auto inter : intervals) {
if (inter.start >= b) {
++cnt;
b = inter.end;
}
}
return n - cnt;
}
static bool cmp(const Interval& p1, const Interval& p2) {
if (p1.end == p2.end) {
return p1.start > p2.start;
}
return p1.end < p2.end;
}
};
【452】Minimum Number of Arrows to Burst Balloons
【455】Assign Cookies
【484】Find Permutation
【502】IPO
【621】Task Scheduler (2019年2月17日)
给了一个 list 的 tasks,每个task占用一个时钟,给了一个数字 n,任意两个相同的task必须间隔 n 个时钟以上。返回最小所有任务都能完成的时间。
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
Explanation: A -> B -> idle -> A -> B -> idle -> A -> B.
题解:本题同 358 Rearrange String k Distance Apart 一个解法。用一个 heap,和一个窗口 n + 1做。有个需要注意的点是,有可能当前已经没有task了,但是窗口还没有走完,需要及时break循环。时间复杂度是O(N),因为字母有限,建立堆是O(26log26)的时间复杂度。
class Solution {
public:
int leastInterval(vector<char>& tasks, int n) {
int size = tasks.size();
unordered_map<char, int> mp;
for (auto& c : tasks) { mp[c]++; }
priority_queue<pair<int, char>> pq;
for (auto& p : mp) {
pq.push(make_pair(p.second, p.first));
}
int res = ;
while (!pq.empty()) {
vector<pair<int, char>> cache;
int count = n + ;
for (int i = ; i < count; ++i) {
if (pq.empty()) {
++res;
continue;
}
auto p = pq.top(); pq.pop();
++res;
p.first--; size--;
if (p.first > ) {
cache.push_back(p);
}
if (pq.empty() && cache.empty()) {break;}
}
for (auto& p : cache) {
pq.push(p);
}
}
return res;
}
};
【630】Course Schedule III
【649】Dota2 Senate
【651】4 Keys Keyboard
【659】Split Array into Consecutive Subsequences
【714】Best Time to Buy and Sell Stock with Transaction Fee
【738】Monotone Increasing Digits
【757】Set Intersection Size At Least Two
【759】Employee Free Time
【763】Partition Labels (2018年11月27日)(这题第一遍的时候不会写,看了答案才会写。)
给了一个只含有小写字母的字符串,求这个字符串的能变成 partition label 的所有子串的长度(partition的越多越好)。能变成 partition label 的条件是,一个label里面含有的字母不能在其他label里面含有。
题解:我们用一个 map 记录每个字母最后一次出现的下标。然后用两个变量, start 和 end 表示当前 label 的开始和截止位置。遍历整个字符串,更新 end = max(mp[S[i]], end), 当我们发现 i == end 的时候,这个时候就是这个 label 结束了。
//本题第一遍的时候不会做看了答案。
class Solution {
public:
vector<int> partitionLabels(string S) {
const int n = S.size();
unordered_map<char, int> mp; //record the last pos of c appear in S
for (int i = ; i < n; ++i) {
mp[S[i]] = i;
}
int start = , end = ;
vector<int> ret;
for (int i = ; i < n; ++i) {
end = max(mp[S[i]], end);
if (end == i) {
ret.push_back(end - start + );
start = i + ;
}
}
return ret;
}
};
【765】Couples Holding Hands
【767】Reorganize String (2019年2月17日,谷歌tag,M)
给了一个字符串 S, 重新排列字符串,使得任意相邻的两个字母都不相同。
题解:还是heap + 贪心,相似题,【358】Rearrange String k Distance Apart ,【621】Task Scheduler
class Solution {
public:
string reorganizeString(string S) {
const int n = S.size();
unordered_map<char, int> mp;
for (auto& c : S) { mp[c]++; }
priority_queue<pair<int, char>> pq;
for (auto& p : mp) {
pq.push(make_pair(p.second, p.first));
}
string res = "";
while (!pq.empty()) {
auto p = pq.top(); pq.pop();
if (!res.empty() && p.second == res.back()) {
auto temp = p;
if (pq.empty()) {return "";}
p = pq.top(); pq.pop();
pq.push(temp);
}
res += string(, p.second);
p.first--;
if (p.first > ) {
pq.push(p);
}
}
return res;
}
};
【842】Split Array into Fibonacci Sequence
【860】Lemonade Change
【861】Score After Flipping Matrix
【870】Advantage Shuffle
【874】Walking Robot Simulation
【881】Boats to Save People
【LeetCode】贪心 greedy(共38题)的更多相关文章
- Leetcode 简略题解 - 共567题
Leetcode 简略题解 - 共567题 写在开头:我作为一个老实人,一向非常反感骗赞.收智商税两种行为.前几天看到不止两三位用户说自己辛苦写了干货,结果收藏数是点赞数的三倍有余,感觉自己的 ...
- 【LeetCode】设计题 design(共38题)
链接:https://leetcode.com/tag/design/ [146]LRU Cache [155]Min Stack [170]Two Sum III - Data structure ...
- 算法与数据结构基础 - 贪心(Greedy)
贪心基础 贪心(Greedy)常用于解决最优问题,以期通过某种策略获得一系列局部最优解.从而求得整体最优解. 贪心从局部最优角度考虑,只适用于具备无后效性的问题,即某个状态以前的过程不影响以后的状态. ...
- 贪心/构造/DP 杂题选做Ⅱ
由于换了台电脑,而我的贪心 & 构造能力依然很拉跨,所以决定再开一个坑( 前传: 贪心/构造/DP 杂题选做 u1s1 我预感还有Ⅲ(欸,这不是我在多项式Ⅱ中说过的原话吗) 24. P5912 ...
- 剑指offer 面试38题
面试38题: 题:字符串的排列 题目:输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,ca ...
- 贪心/构造/DP 杂题选做Ⅲ
颓!颓!颓!(bushi 前传: 贪心/构造/DP 杂题选做 贪心/构造/DP 杂题选做Ⅱ 51. CF758E Broken Tree 讲个笑话,这道题是 11.3 模拟赛的 T2,模拟赛里那道题的 ...
- 【LeetCode】堆 heap(共31题)
链接:https://leetcode.com/tag/heap/ [23] Merge k Sorted Lists [215] Kth Largest Element in an Array (无 ...
- 【LeetCode】排序 sort(共20题)
链接:https://leetcode.com/tag/sort/ [56]Merge Intervals (2019年1月26日,谷歌tag复习) 合并区间 Input: [[1,3],[2,6], ...
- 【LeetCode】动态规划(下篇共39题)
[600] Non-negative Integers without Consecutive Ones [629] K Inverse Pairs Array [638] Shopping Offe ...
随机推荐
- Jenkins镜像
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
- 如何添加筛选器 (Reporting Services)
如果您希望在计算或显示时包含或排除特定值,可向数据集.数据区域或组添加筛选器.在运行时应用筛选器的顺序为:先对数据集,再对数据区域,最后对组,并按照组层次结构自上而下的顺序.在表.矩阵或列表中,对行组 ...
- 【説明する】STL
作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的. STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现. 所以今天要整理的东西就是STL!(orz 杨 ...
- 测开之路七十三:用kafka实现消息队列之环境搭建
一:装java环境,确保java能正确调用 kafka下载地址:http://kafka.apache.org/downloads 下载并解压kafka: 新建两个文件夹,用于存放zookeeper和 ...
- Delphi中Tlist实例
http://blog.163.com/jiandande3218@126/blog/static/74728469201132721428194/ Delphi中Tlist实例 2011-04-27 ...
- linux crontab 执行任务(7秒执行)
创建的contab 文件中,每一行都代表一项任务,每行的每个字段代表一项设置.前五个字段是时间,第六个字段是要执行的命令 minute hour day month week co ...
- Mac011--DbWrench Database安装
Mac--DbWrench Database安装 DbWrench <=> powerdesigner 下载网址:http://dbwrench.com/download/install/ ...
- 微信小程序列表时间戳转换
第一步先写js 随便命名为times.js function toDate(number){ var n=number * 1000; var date = new Date(n) ...
- 如何在Python中使用Linux epoll
如何在Python中使用Linux epoll 内容 介绍 阻塞套接字编程示例 异步套接字和Linux epoll的好处 epoll的异步套接字编程示例 性能考量 源代码 介绍 从2.6版开始,Pyt ...
- c.vim
放在 /usr/share/vim/vim80/syntax/c.vim 最后: syn match cFunctions "\<[a-zA-Z_][a-zA-Z_0-9]*\> ...