【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

相關文章
相關標籤/搜索