134. 加油站
題目連結:https://leetcode.cn/problems/gas-station/
題目難度:中等
文章講解:https://programmercarl.com/0134.加油站.html
影片講解:https://www.bilibili.com/video/BV1jA411r7WX
題目狀態:沒有思路,學習題解
思路一:全域性最優解
首先將所有路徑的加油量和耗油量加一起,看是否大於0,若小於0,表示整體的加油量小於耗油量,不可能跑完全程,直接返回-1;若大於0,看其到每一站儲存的油量最小值是否大於等於0,若是,則表示其在每一站都是可以跑完的,直接返回0(表示從0開始出發可以完成全程);若並不是這樣的,則反向加出發點,看其什麼時候的最小值不會為負數,此時就是出發點的位置。
程式碼一:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int min = INT_MAX;
for(int i = 0; i < gas.size(); ++i) {
int rest = gas[i] - cost[i];
curSum += rest;
min = std::min(min, curSum);
}
if(curSum < 0) return -1;
if(min >= 0) return 0;
for(int i = gas.size() - 1; i >= 0; --i) {
int rest = gas[i] - cost[i];
min += rest;
if(min >= 0) return i;
}
return -1;
}
};
思路二:貪心演算法
區域性最優,首先當所有路徑的油差之和小於0,直接返回-1,其不可能跑完全程;再次,若從A點到B點的油差和小於0,要從B點的下一點重新記錄,因為A到B之間無論從哪一點開始,都跑不完,最後返回合適的位置。
程式碼:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int totalSum = 0;
int start = 0;
for(int i = 0; i < cost.size(); ++i) {
curSum += gas[i] - cost[i];
totalSum += gas[i] - cost[i];
if(curSum < 0) {
start = i + 1;
curSum = 0;
}
}
if(totalSum < 0) return -1;
return start;
}
};
135. 分發糖果
題目連結:https://leetcode.cn/problems/candy/
題目難度:困難
文章講解:https://programmercarl.com/0135.分發糖果.html
影片講解:https://www.bilibili.com/video/BV1ev4y1r7wN
題目狀態:好難,要長腦子了
思路:
首先建立一個陣列,儲存每個孩子手裡的糖。
- 首先,每個孩子手裡都要有一顆糖。
- 從左向右,判斷右邊孩子分數是否要大於左邊孩子,若大於,就把右邊孩子手裡加一顆糖。
- 從右向左,判斷左邊孩子的分數是否大於右邊孩子,若大於,則判斷左邊孩子手裡的糖是否已經大於右邊孩子了,若不大於,則將左邊孩子手裡的糖加到比右邊孩子大。
程式碼:
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> candyVal(ratings.size(), 1);
for(int i = 1; i < ratings.size(); ++i) {
if(ratings[i] > ratings[i - 1]) candyVal[i] = candyVal[i - 1] + 1;
}
for(int i = ratings.size() - 2; i >= 0; --i) {
if(ratings[i] > ratings[i + 1]) candyVal[i] = max(candyVal[i], candyVal[i + 1] + 1);
}
int res = 0;
for(auto &val : candyVal) res += val;
return res;
}
};
860. 檸檬水找零
題目連結:https://leetcode.cn/problems/lemonade-change/
題目難度:簡單
文章講解:https://programmercarl.com/0860.檸檬水找零.html
影片講解:https://www.bilibili.com/video/BV12x4y1j7DD
題目狀態:沒繞過來,看完題解豁然開朗
思路:
維護五塊錢和十塊錢的個數five和ten
- 當給5元時,five++;
- 當給10元時,five--;
- 當給20元時,要麼ten--和five--,要麼five-3。
程式碼:
class Solution {
public:
bool lemonadeChange(vector<int>& bills) {
int five = 0, ten = 0;
for(int i = 0; i < bills.size(); ++i) {
if(bills[i] == 5) five++;
if(bills[i] == 10) {
if(five <= 0) return false;
five--;
ten++;
}
if(bills[i] == 20) {
if(five > 0 && ten > 0) {
five--;
ten--;
} else if(five >= 3) {
five -= 3;
} else {
return false;
}
}
}
return true;
}
};
406. 根據身高重建佇列
題目連結:https://leetcode.cn/problems/queue-reconstruction-by-height/
題目難度:中等
文章講解:https://programmercarl.com/0406.根據身高重建佇列.html
影片講解:https://www.bilibili.com/video/BV1EA411675Y
題目狀態:繼續學習題解...
思路:
首先對整個陣列進行排序,排序規則是比較身高,最高的排在前面,若身高相同,比較前方人數,人數低的排在前面。
之後開始插入返回陣列,按照排序後的陣列依次插入,插入的位置是自己的前方人數,下圖更容易理解插入的過程。
程式碼實現:
class Solution {
public:
static bool cmp(const vector<int> &a, const vector<int> &b) {
if(a[0] == b[0]) return a[1] < b[1];
return a[0] > b[0];
}
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort(people.begin(), people.end(), cmp);
vector<vector<int>> que;
for(int i = 0; i < people.size(); ++i) {
int position = people[i][1];
que.insert(que.begin() + position, people[i]);
}
return que;
}
};
連結串列程式碼:(效能更好)
class Solution {
public:
// 身高從大到小排(身高相同k小的站前面)
static bool cmp(const vector<int>& a, const vector<int>& b) {
if (a[0] == b[0]) return a[1] < b[1];
return a[0] > b[0];
}
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
sort (people.begin(), people.end(), cmp);
list<vector<int>> que; // list底層是連結串列實現,插入效率比vector高的多
for (int i = 0; i < people.size(); i++) {
int position = people[i][1]; // 插入到下標為position的位置
std::list<vector<int>>::iterator it = que.begin();
while (position--) { // 尋找在插入位置
it++;
}
que.insert(it, people[i]);
}
return vector<vector<int>>(que.begin(), que.end());
}
};