[豪の算法奇妙冒险] 代码随想录算法训练营第二十九天 | 134-加油站、135-分发糖果、860-柠檬水找零、406-根据身高重建队列
代码随想录算法训练营第二十九天 | 134-加油站、135-分发糖果、860-柠檬水找零、406-根据身高重建队列
LeetCode134 加油站
题目链接:https://leetcode.cn/problems/gas-station/
文章讲解:https://programmercarl.com/0134.加油站.html
视频讲解:https://www.bilibili.com/video/BV1jA411r7WX/?vd_source=b989f2b109eb3b17e8178154a7de7a51
首先想到的是暴力法,遍历每一个加油站为起点的情况,模拟一圈。如果跑了一圈,中途没有断油,而且最后油量大于等于0,则说明这个起点是符合题意的
但是暴力方法时间复杂度是O(n^2),样例超时,未能AC

class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
for(int i = 0; i < gas.length; i++){
int restGas = gas[i] - cost[i];
int index = (i+1) % gas.length;
while(restGas > 0 && index != i){
restGas += gas[index] - cost[index];
index = (index+1) % gas.length;
}
if(restGas >= 0 && index == i){
return i;
}
}
return -1;
}
}
如果总油量减去总消耗大于等于零,则一定可以跑完一圈(因为当start = i+1, 且这个start没有被后序的更新替代,则说明从start到数组结束位置(gas.size()-1)之间的sum为正数,若记该sum为B,start之前的sum为A,那么A+B=totalSum, 已知totalSum>=0, A<0, B>0, 所以B>-A, 走完一圈的B+A>=0),说明各个站点的加油站剩油量rest[i]相加一定是大于等于零的
每个加油站的剩余量rest[i]为gas[i] - cost[i],i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum

class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int totalSum = 0;
int curSum = 0;
int start = 0;
for(int i = 0; i < gas.length; i++){
totalSum += gas[i] - cost[i];
curSum += gas[i] - cost[i];
if(curSum < 0){
curSum = 0;
start = i+1;
}
}
if(totalSum < 0){
return -1;
}
return start;
}
}
LeetCode135 分发糖果
题目链接:https://leetcode.cn/problems/candy/description/
文章讲解:https://programmercarl.com/0135.分发糖果.html
视频讲解:https://www.bilibili.com/video/BV1ev4y1r7wN/?vd_source=b989f2b109eb3b17e8178154a7de7a51
主要是要一步一步处理,防止顾此失彼
先确保比左边分数高的人有的糖果数更多,再确保比右边分数高的人有的糖果数更多,最后再统计总糖数即得到题解

class Solution {
public int candy(int[] ratings) {
int[] giveCandy = new int[ratings.length];
giveCandy[0] = 1;
for(int i = 1; i < ratings.length; i++){
if(ratings[i] > ratings[i-1]){
giveCandy[i] = giveCandy[i-1] + 1;
}else{
giveCandy[i] = 1;
}
}
for(int i = ratings.length - 2; i >= 0; i--){
if(ratings[i] > ratings[i+1]){
giveCandy[i] = Math.max(giveCandy[i+1] + 1, giveCandy[i]);
}
}
int totalSum = 0;
for(int i = 0; i < ratings.length; i++){
totalSum += giveCandy[i];
}
return totalSum;
}
}
LeetCode860 柠檬水找零
题目链接:https://leetcode.cn/problems/lemonade-change/description/
文章讲解:https://programmercarl.com/0860.柠檬水找零.html
视频讲解:https://www.bilibili.com/video/BV12x4y1j7DD/?vd_source=b989f2b109eb3b17e8178154a7de7a51
按顺序处理即可,别多想

class Solution {
public boolean lemonadeChange(int[] bills) {
int fiveNum = 0;
int tenNum = 0;
int twentyNum = 0;
for(int i = 0; i < bills.length; i++){
switch(bills[i]){
case 5: fiveNum++;break;
case 10:
fiveNum--;
tenNum++;
break;
case 20:
if(tenNum > 0){
tenNum--;
fiveNum--;
}else{
fiveNum -= 3;
}
}
if(fiveNum < 0){
return false;
}
}
return true;
}
}
LeetCode406 根据身高重建队列
题目链接:https://leetcode.cn/problems/queue-reconstruction-by-height/description/
文章讲解:https://programmercarl.com/0406.根据身高重建队列.html
视频讲解:https://www.bilibili.com/video/BV1EA411675Y/?vd_source=b989f2b109eb3b17e8178154a7de7a51
关于出现两个维度一起考虑的情况,其技巧都是确定一边然后贪心另一边,两边一起考虑,就会顾此失彼

class Solution {
public int[][] reconstructQueue(int[][] people) {
// 身高从大到小排(身高相同k小的站前面)
Arrays.sort(people, (a, b) -> {
if (a[0] == b[0]) return a[1] - b[1]; // a - b 是升序排列,故在a[0] == b[0]的狀況下,會根據k值升序排列
return b[0] - a[0]; //b - a 是降序排列,在a[0] != b[0],的狀況會根據h值降序排列
});
LinkedList<int[]> que = new LinkedList<>();
for (int[] p : people) {
que.add(p[1],p); //Linkedlist.add(index, value),會將value插入到指定index裡。
}
return que.toArray(new int[people.length][]);
}
}

浙公网安备 33010602011771号