【LeetCode】贪心 greedy(共38题)

【44】Wildcard Matching html

【45】Jump Game II (2018年11月28日,算法群衍生题)git

题目背景和 55 同样的,问我能到达最后一个index的话,最少走几步。算法

题解:数组

 

【55】Jump Game (2018年11月27日,算法群)app

给了一个数组nums,nums[i] = k 表明站在第 i 个位置的状况下, 我最多能往前走 k 个单位。问我能不能到达最后一个 index。ide

题解:虽然是贪心分类,我仍是用dp解了。dp[i] 表明我能不能到达第 i 个位置。 ui

 1 class Solution {
 2 public:
 3     bool canJump(vector<int>& nums) {
 4         const int n = nums.size();
 5         if (n == 0) {return false;}
 6         vector<int> f(n, 0); //f[i] 表明第i个index是否是可达
 7         f[0] = 1;
 8         for (int i = 0; i < n; ++i) {
 9             if (f[i]) {
10                 const int k = nums[i];
11                 for (int j = 1; j <= k; ++j) {
12                     if (i+j >= n) {break;}
13                     f[i+j] = 1;
14                 }
15             }
16         }
17         return f[n-1] == 1;
18     }
19 };
View Code

  

【122】Best Time to Buy and Sell Stock II (2018年11月26日,算法群)google

这个题目股票系列里面说了,这里不重复写了。股票系列:http://www.javashuo.com/article/p-oeuyrmgz-ms.htmlspa

 

【134】Gas Station (2019年1月27日,谷歌tag)翻译

一个圆形的跑道,上面有 N 个加油站,每一个加油站能加的油是 gas[i],假设你的车能加无限的油量,从第 i 个加油站跑到第 i+1 个加油站所消耗的油是 cost[i], 返回从第几个加油站可以顺时针跑完一圈,若是从任意一个都不能跑完的话,就返回-1

题解:本题彷佛用到了一个数学定理/方法。就是若是能跑完一圈的话,一定存在从一个点开始,任意的点上的油量都不会为负数。

 1 class Solution {
 2 public:
 3     int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
 4         int total = 0;
 5         int sum = 0;
 6         int ans = 0;
 7         for(int i = 0; i < gas.size(); ++i){
 8             sum += gas[i] - cost[i];
 9             total += gas[i] - cost[i];
10             if(sum < 0){
11                 ans = i+1;
12                 sum = 0;
13             }
14         }
15         return total < 0? -1 : ans;
16     }
17 };
View Code

 

【135】Candy (2019年1月27日,谷歌tag)

每一个小孩有一个 rating,你要给这些小孩发糖果,知足两条规则:规则1. 每一个小孩至少一个糖果; 规则2. 若是一个小孩的rating比它的邻居高,那么他的糖果数量要比邻居多。问发完全部小孩的最少糖果数量。

题解:设置两个数组,一个front,从前日后应该发的糖果数量。一个back,表示从后往前应该发的糖果数量。final[i] = max(front[i], back[i]); O(N) with 2 pass

 1 //每一个小孩至少一个糖果,
 2 //若是当前小孩的rating比它前一个小孩大的话,就是它前一个小孩的糖果数量+1
 3 //若是当前小孩的rating比它后一个小孩大的话,就是它后一个小孩的糖果数量+1
 4 class Solution {
 5 public:
 6     int candy(vector<int>& ratings) {
 7         const int n = ratings.size();
 8         vector<int> front(n , 1), back(n, 1);
 9         for (int i = 1; i < n; ++i) {
10             front[i] = ratings[i-1] < ratings[i] ? front[i-1] + 1 : 1;
11         }
12         int res = max(front[n-1], back[n-1]);
13         for (int i = n - 2; i >= 0; --i) {
14             back[i] = ratings[i] > ratings[i+1] ? back[i+1] + 1 : 1;
15             res += max(front[i], back[i]);
16         }
17         return res;
18     }
19 };
View Code

 

【253】Meeting Rooms II 

题意是252的升级版,给了一个数组,数组里面的每一个元素表明一个会议的开始时间和结束时间,问想安排下全部的会议,至少须要多少个会议室。 

题解:这个题目在 sort 的分类里面说过,连接:http://www.javashuo.com/article/p-zyassihu-mr.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

 1 class Solution {
 2 public:
 3     bool increasingTriplet(vector<int>& nums) {
 4         int min1 = INT_MAX, min2 = INT_MAX;
 5         for (auto& num : nums) {
 6             if (num > min2) {return true;}
 7             else if (num < min1) {
 8                 min1 = num;
 9             } else if (min1 < num && num < min2) {
10                 min2 = num;
11             }
12         }
13         return false;
14     }
15 };
View Code

 

【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里面。

 1 class Solution {
 2 public:
 3     string rearrangeString(string s, int k) {
 4         if (k == 0) {return s;}
 5         int size = s.size();
 6         unordered_map<char, int> mp;
 7         for (auto& c : s) { mp[c]++; }
 8         priority_queue<pair<int, char>> pq;
 9         for (auto& p : mp) {
10             pq.push(make_pair(p.second, p.first));
11         }
12         string res = "";
13         while (!pq.empty()) {
14             vector<pair<int, char>> cache;
15             int count = min(size, k);
16             for (int i = 0; i < count; ++i) {
17                 if (pq.empty()) {return "";}
18                 auto p = pq.top();
19                 pq.pop();
20                 res += string(1, p.second);
21                 p.first--;
22                 size--;
23                 if (p.first > 0) {
24                     cache.push_back(p);
25                 }
26             }
27             for (auto& p: cache) {
28                 pq.push(p);
29             }
30         }
31         return res;
32     }
33 };
View Code

 

【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 这个位置上。

 1 class Solution {
 2 public:
 3     vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
 4         const int n = people.size();
 5         if (n == 0) {return people;}
 6         sort(people.begin(), people.end(), cmp);
 7         vector<pair<int, int>> ret;
 8         for (int i = 0; i < people.size(); ++i) {
 9             ret.insert(ret.begin() + people[i].second, people[i]);
10         }
11         return ret;
12     }
13     static bool cmp(const pair<int, int>& p1, const pair<int, int>& p2) {
14         if (p1.first == p2.first) {
15             return p1.second < p2.second;
16         }
17         return p1.first > p2.first;
18     }
19 };
View Code

 

【435】Non-overlapping Intervals (2018年11月26日)

这题应该见过了orz,莫名的熟悉。题意就是给了一堆线段,问这些线段在不重叠的前提下,最少要剔除几条知足这个线段不重叠的条件。

题解:最少剔除几条才能让全部线段不重叠,其实翻译过来,就是这些线段最多多少条不重叠。咱们想这条直线上放尽量多的线段,须要什么样的策略呢?就是第一条线段的末端的数值尽量的小,这样后面能选择的空间才比较大。

因此先排序,按照线段末端从从小到大排序。而后贪心一个一个处理。(惟一一个注意点是线段的头尾都有多是负数。)

 1 /**
 2  * Definition for an interval.
 3  * struct Interval {
 4  *     int start;
 5  *     int end;
 6  *     Interval() : start(0), end(0) {}
 7  *     Interval(int s, int e) : start(s), end(e) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     int eraseOverlapIntervals(vector<Interval>& intervals) {
13         const int n = intervals.size();
14         if (n == 0) {return n;}
15         sort(intervals.begin(), intervals.end(), cmp);
16         int cnt = 0;
17         int b = intervals[0].start;
18         for (auto inter : intervals) {
19             if (inter.start >= b) {
20                 ++cnt;
21                 b = inter.end;
22             }
23         }
24         return n - cnt;
25     }
26     static bool cmp(const Interval& p1, const Interval& p2) {
27         if (p1.end == p2.end) {
28             return p1.start > p2.start;
29         }
30         return p1.end < p2.end;
31     }
32 };
View Code

  

【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)的时间复杂度。

 1 class Solution {
 2 public:
 3     int leastInterval(vector<char>& tasks, int n) {
 4         int size = tasks.size();
 5         unordered_map<char, int> mp;
 6         for (auto& c : tasks) { mp[c]++; }
 7         priority_queue<pair<int, char>> pq;
 8         for (auto& p : mp) {
 9             pq.push(make_pair(p.second, p.first));
10         }
11         int res = 0;
12         while (!pq.empty()) {
13             vector<pair<int, char>> cache;
14             int count = n + 1;
15             for (int i = 0; i < count; ++i) {
16                 if (pq.empty()) {
17                     ++res; 
18                     continue;
19                 }
20                 auto p = pq.top(); pq.pop();
21                 ++res;
22                 p.first--; size--;
23                 if (p.first > 0) {
24                     cache.push_back(p);
25                 }
26                 if (pq.empty() && cache.empty()) {break;}
27             }
28             for (auto& p : cache) {
29                 pq.push(p);
30             }
31         }
32         return res;
33     }
34 };
View Code

 

【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 结束了。

 1 //本题第一遍的时候不会作看了答案。
 2 class Solution {
 3 public:
 4     vector<int> partitionLabels(string S) {
 5         const int n = S.size();
 6         unordered_map<char, int> mp; //record the last pos of c appear in S
 7         for (int i = 0; i < n; ++i) {
 8             mp[S[i]] = i;
 9         }
10         int start = 0, end = 0;
11         vector<int> ret;
12         for (int i = 0; i < n; ++i) {
13             end = max(mp[S[i]], end);
14             if (end == i) {
15                 ret.push_back(end - start + 1);
16                 start = i + 1;
17             }
18         }
19         return ret;
20     }
21 };
View Code

  

【765】Couples Holding Hands 

 

【767】Reorganize String (2019年2月17日,谷歌tag,M)

给了一个字符串 S, 从新排列字符串,使得任意相邻的两个字母都不相同。

题解:仍是heap + 贪心,类似题,【358】Rearrange String k Distance Apart ,【621】Task Scheduler 

 1 class Solution {
 2 public:
 3     string reorganizeString(string S) {
 4         const int n = S.size();
 5         unordered_map<char, int> mp;
 6         for (auto& c : S) { mp[c]++; }
 7         priority_queue<pair<int, char>> pq;
 8         for (auto& p : mp) {
 9             pq.push(make_pair(p.second, p.first));
10         }
11         string res = "";
12         while (!pq.empty()) {
13             auto p = pq.top(); pq.pop();
14             if (!res.empty() && p.second == res.back()) {
15                 auto temp = p;
16                 if (pq.empty()) {return "";}
17                 p = pq.top(); pq.pop();
18                 pq.push(temp);
19             }
20             res += string(1, p.second);
21             p.first--; 
22             if (p.first > 0) {
23                 pq.push(p);
24             }
25         }
26         return res;
27     }
28 };
View Code

 

【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

相关文章
相关标签/搜索