Leetcode-貪心演算法
貪心演算法(又稱貪婪演算法)是指,在對問題求解時,總是做出在當前看來是最好的選擇。 也就是說,不從整體最優上加以考慮,他所做出的是在某種意義上的區域性最優解。
455. 分發餅乾
思路
這道題目給了我們兩組array,一組代表小朋友的胃口值,另一組代表曲奇餅乾的大小。
我們要分發曲奇給儘可能多的小朋友,並且曲奇餅乾的大小要滿足小朋友的胃口。
所以,最好給孩子們分配與他胃口最接近的餅乾。
不能把大的曲奇去滿足很小胃口的小朋友,除非沒有選擇。儘可能的去把小曲奇發給小胃口的小朋友。
關鍵點:把兩個array 重新排列,從小到大。
方法1:10ms 100%
對兩個陣列進行排序並使用兩個指標。O(nlogn)
// 10ms
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int pointG = 0;
int pointS = 0;
while (pointG < g.length && pointS < s.length) {
if (g[pointG] <= s[pointS]) {
pointG++;
pointS++;
}
else {
pointS++;
}
}
return pointG;
}
}
方法2:16ms 38%
常規迴圈兩個陣列遍歷,無指標,效率慢
class Solution {
public int findContentChildren (int[] g, int[] s) {
int count=0;
Arrays.sort(g);
Arrays.sort(s);
int j=0;
for(int i=0; i<g.length; i++){
while(j<s.length && s[j]<g[i]) j++;
if(j==s.length) break;
count++;
j++;
}
return count;
}
}
55. Jump Game (M)
給定一個非負整數陣列,陣列中的每個元素表示該位置的最大跳躍長度。
從陣列的第一個索引(下標為0)開始,確定是否能夠跳到最後一個索引處。
Example 1:
Input: [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
Example 2:
Input: [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
思路
採用貪心的思路,採用farest變量表示到目前為止能跳到的最遠距離,即為全域性最優解。當遍歷到 i 的時候,區域性最優解為 A[i]+i,表示從當前一步出發能跳到的最遠距離。
因此,此時的全域性最優解即為 farest 和 A[i]+i 的最大值:farest = Math.max(farest, A[i] + i)。
關鍵點:“區域性最優和全域性最優解法”。全域性最優為 globalMax=Math.max(globalMax, localMax)
public boolean canJump(int[] A) {
int n = A.length;
int farest = 0;
for(int i = 0; i < n; i++){
if(farest < i) return false;
farest = Math.max(i + A[i], farest);
}
return true;
}
45. Jump Game II (H)
題目連結
給定一個非負整數陣列,陣列中的每個元素表示該位置的最大跳躍長度。
從陣列的第一個索引(下標為0)開始,需要我們以最小跳躍次數到達最後一個索引。
Example:
Input: [2,3,1,1,4] Output: 2
Explanation: The minimum number of jumps to reach the last index is 2. Jump 1 step from index 0 to 1, then 3 steps to the last index.
Note: You can assume that you can always reach the last index.
思路
這道題需要求的是最少的步數。
因此需要新增step變數記錄最少步數。至於什麼時候step需要加1?答案是當前的 i 超過了前一step的最遠位置。所以引入last變數記錄上一步step能到達的最遠位置。
當遍歷到 i 的時候,如果 i == last(即上一step能到達的最遠位置),說明步數需要加1(step++),此時仍需要更新last為當前最遠位置farest。
關鍵點:記錄最少步數step、判斷何時step++
public int jump(int[] A) {
int n = A.length;
int step = 0, last = 0, farest = 0;
for(int i = 0; i < n-1; i++) {
farest = Math.max(farest, i+A[i]);
if(farest >= n-1) return step+1; //skip scanning when find a way with minimum jumps
if(i == last) {
step++;
last = farest;
}
}
return step ;
}
122. Best Time to Buy and Sell Stock II
假設您有一個數組,
元素是第 i 天股票的價格。
設計演算法以找到最大利潤。 您可以根據需要完成儘可能多的交易(即,多次進行買入賣出)。
注意:您不得同時進行多筆交易(即,您必須在再次購買之前賣出股票)。
Example 1:
Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Example 2:
Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.
Example 3:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
思路
貪心演算法,在每一小段上升序列中最大差值累加得到結果。就是說在股票價格處於上升期的時候,在最低點買入,在最高點賣出。
class Solution {
public int maxProfit(int[] prices) {
int pro = 0;
for (int i = 1; i < prices.length; i++){
if (prices[i]> prices[i-1])
pro += prices[i] - prices[i-1];
}
return pro;
}
}
134. Gas Station (M)
沿著環形路線有N個加油站,在加油站 i 的汽油數是 gas[i]。
你有一輛帶有無限油箱的汽車,從加油站i 到下一加油站 (i+1) 需要消耗cost[i]汽油。 您使用空罐從其中任一個加油站啟程。如果您可以順時針方向繞環形一次,則返回起始加油站的索引,否則返回-1。
注意: 如果存在解決方案,則保證是唯一的。
Example 1:
Input: gas = [1,2,3,4,5]; cost = [3,4,5,1,2]
Output: 3
Explanation: Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3. Therefore, return 3 as the starting index.
Example 2:
Input: gas = [2,3,4] cost = [3,4,3]
Output: -1
Explanation: You can’t start at station 0 or 1, as there is not enough gas to travel to the next station. Let’s start at station 2 and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 0. Your tank = 4 - 3 + 2 = 3
Travel to station 1. Your tank = 3 - 3 + 3 = 3
You cannot travel back to station 2, as it requires 4 unit of gas but you only have 3. Therefore, you can’t travel around the circuit once no matter where you start.
思路
首先先要明白:如果一個數組的總和非負,那麼一定可以找到一個起始位置,從他開始繞陣列一圈,累加和一直都是非負的。
如果從 i 出發,那麼 gas[i]- cost[i] = dif[i] 一定是大於0的。
如果 dif[i] + dif[i+1] +……+ dif[k-1]>=0,而 dif[i] + dif[i+1] +……+ dif[k-1] + dif[k]<0,此時需要重新設定開始點,那麼需要從i+1開始嗎?從i+1開始肯定不可能到達k點(dif[i]肯定大於0,所以少加了一個正數)。
那麼需要設定開始點為 k+1
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int startpos = 0; // 記錄訪問的起始點
int totaldif = 0; // 從0位置開始,加的氣和消耗的氣的總差值
int startdif = 0; // 從start位置開始,加的氣和消耗的氣的總差值
for (int i = 0; i < gas.length; i++){
int dif = gas[i] - cost[i];
totaldif += dif;
startdif += dif;
if (startdif < 0){ // 走到i站是負數,說明走不到i站;也不能選取起始站到i站中的任何一站
startdif = 0;
startpos = i + 1; // 直接選擇下一站作為起始點
}
}
return totaldif >= 0 ? startpos : -1;
}
}
860. Lemonade Change
在檸檬水攤上,每個檸檬水的價格為5美元。
客戶站在佇列中向您購買,並一次訂購一個(按照賬單指定的順序)。
每位顧客只需購買一瓶檸檬水,並以5美元,10美元或20美元的鈔票付款。 您必須找給每個客戶正確的零錢。
請注意,您最初手頭沒有任何零錢。當且僅當您能為每位客戶提供正確的零錢時,才返回true。
Example 1:
Input: [5,5,5,10,20]
Output: true
Explanation: From the first 3 customers, we collect three $5 bills in order.
From the fourth customer, we collect a $10 bill and give back a $5.
From the fifth customer, we give a $10 bill and a $5 bill.
Since all customers got correct change, we output true.
Example 2:
Input: [5,5,10,10,20]
Output: false
Explanation: From the first two customers in order, we collect two $5 bills.
For the next two customers in order, we collect a $10 bill and give back a $5 bill.
For the last customer, we can’t give change of $15 back because we only have two $10 bills.
Since not every customer received correct change, the answer is false.
class Solution {
public boolean lemonadeChange(int[] bills) {
int five = 0, ten = 0;
for (int i : bills) {
if (i == 5) five++;
else if (i == 10) {five--; ten++;}
else if (ten > 0) {ten--; five--;}
else five -= 3;
if (five < 0) return false;
}
return true;
}
}