134.加油站
代码随想录
代码随想录
索引 | 0 | 1 | 2 | 3 | 4 |
gas | 1 | 2 | 3 | 4 | 5 |
cost | 3 | 4 | 5 | 1 | 2 |
计算每个加油站的剩余油量,累计sum,一旦<0就从下一个重新计数。
我还没理解为什么我们不需要计算环路的sum,而是只需要遍历一次。
因为使用了两个变量:curSum 和totalSum ,totalSum最终一旦小于0,说明怎么都不可能跑完一圈。curSum是为了求取出发点。
假设直到B点curSum才<0,意味着从A点出发,初始油箱是有油的,油箱有油都无法到达,从A点重新出发,油箱为空的情况下,又怎么能到达呢? 同样的,到达C点时油箱有油,意味着肯定比从C点开始出发更稳妥,更优,因为解唯一,所以一定是最优的那个。这也解释了为什么题目是环路,而我们只需要顺序遍历一次。
代码
class Solution {
public int canCompleteCircuit(int[] gas, int[] cost) {
int curSum = 0;
int totalSum = 0;
int start = 0;
for(int i = 0;i<gas.length;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.分发糖果
代码随想录
代码随想录
一次遍历两边都要考虑会顾此失彼,正确思路是先确定一边,再确定另一边。
正序先确定一边,因为第一个小孩糖果数确定为1:右边小孩比左边小孩得分高,if(right>left) candy[i] = candy[i-1]+1;
倒序再确定另一边,因为最后一个小孩糖果数确定为1:左孩子比右边孩子得分高,if(left
>right) candy[i] = Math.max(candy[i-1]+1,candy[i]);
局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。
关于倒序取Max值的困惑:
问:听不懂为什么可以取最值就行了。第一遍遍历得到的糖果,取决于他左边的小孩的糖果数,和这两个人的相对大小关系,第二遍遍历得到的糖果,取决于他右边小孩的糖果数和他们两个人的大小关系,取最大值不会破坏第一遍遍历的相对关系吗?
答:
你想吧,对于第i个元素来说,假设它比左边的元素(第i-1个)大。第一次遍历使得第i个元素比它左边的元素(第i-1个)大对吧;第二次遍历的时候,第i个元素要么持平,要么增大(max操作),所以第二次遍历结束后,第i个元素还是比他左边的元素大是吧,所以就没有破坏第一次的遍历结果呀~
代码
class Solution {
public int candy(int[] ratings) {
int[] candy = new int[ratings.length];
candy[0] = 1;
for (int i = 1;i<ratings.length;i++){
candy[i] = (ratings[i]>ratings[i-1])?candy[i-1]+1:1;
}
for(int i = ratings.length-2;i>=0;i--){
if(ratings[i]>ratings[i+1]){
candy[i] = Math.max(candy[i+1]+1,candy[i]);
}
}
return getSum(candy);
}
public int getSum(int[] candy){
int sum = 0;
for (int i : candy) {
sum+=i;
}
return sum;
}
}
860.柠檬水找零
代码随想录
代码
class Solution {
public boolean lemonadeChange(int[] bills) {
int fiveCount = 0;
int tenCount = 0;
for(int i = 0;i<bills.length;i++){
if(bills[i]==5) {
fiveCount++;
}else if(bills[i]==10){
tenCount++;
fiveCount--;
}else if(bills[i]==20){
if(tenCount>0){
tenCount--;
fiveCount--;
}else{
fiveCount = fiveCount-3;
}
}
if(fiveCount<0||tenCount<0){
return false;
}
}
return true;
}
}
406.身高排序[代码重刷]
代码随想录
代码随想录
先确定H维度;按照身高从大到小排列,当身高相同时按照K从小到大排列。就保证了数组向前插入时前面的人身高一定比它高,从而保证被插入的数组K值不会有任何影响。
再确定K维度:再按照K值插到前面的位置。
代码
Arrays.sort自定义排序使用,LinkedList适合挪动元素插入删除操作,linkedList转换成nt[][]数组,这些调用都不会,因此需要代码重刷
class Solution {
public int[][] reconstructQueue(int[][] people) {
Arrays.sort(people,(a,b)->{
if(a[0]==b[0]) return a[1]-b[1];//身高相同时,按照K值升序排列
return b[0]-a[0];//否则直接按照身高降序排列
});
LinkedList<int[]> deque = new LinkedList<>();
for (int[] person : people) {
deque.add(person[1],person);
}
return deque.toArray(new int[people.length][]);
}
}