代码随想录DAY29|134. 加油站、135. 分发糖果、860.柠檬水找零、406.根据身高重建队列

1. 加油站

力扣

从第一个开始遍历所有加油站,记录当前站点的油量变化量gas[i] - cost[i],并加到currentSum和totalSum上。如果在某一站currentSum<0,证明无法到达当前节点,就要将下一节点i+1当作start节点,并将currentSum置零。遍历完后如果totalSum>0证明可以环游一圈,当前start即为开始节点。
本题有以下两个可能的疑问:
1.会不会存在0-start中间的某个节点,从那里到当前节点也可以实现currtSum>0?
实际上不会,假设存在这个节点,区间2>0,那么区间和1必定<0,根据我们定的规则仍然是从start也就是该节点下一个开始。
在这里插入图片描述
2.假如从中途某个节点开始,那currentSum只记录了后面的变化和,能否保证走完前面的路程?
假设start前面区间和为A,后面区间和为B,A<0,B>0,A+B=totalSum>0,那么A的绝对值一定小于B,即可以走完前面的路程。

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int currentSum = 0;
        int totalSum = 0;
        int start = 0;
        for(int i = 0; i < gas.length; i++){
            currentSum += gas[i] - cost[i];
            totalSum += gas[i] - cost[i];
            if(currentSum < 0){
                start = i + 1;
                currentSum = 0;
            }
        }
        if(totalSum < 0){
            return -1;
        }
        return start;
    }
}

2. 分发糖果

力扣
本题涉及的思想是要处理好一边再去处理另一边

先从左向右遍历贪心一遍,即右边大于左边的情况。如果当前的比前一个大就加一,否则就置为1。再从右向左遍历一遍,即左边大于右边的情况。这个遍历不能做左向右,因为当前比较要根据右边的比较结果,如下图。遍历时如果当前节点比左边大,那么有两个取值:原本的candyVec[i]和新的candyVec[i+1]+1,取二者中大的那个,这样保证对左右都是更大的那个。
在这里插入图片描述

class Solution {
    public int candy(int[] ratings) {
        int[] candyVec = new int[ratings.length];
        candyVec[0] = 1;
        for(int i = 1; i < candyVec.length; i++){
            candyVec[i] = ratings[i] > ratings[i-1] ? candyVec[i-1] + 1 : 1;
        }
        for(int i = candyVec.length - 2; i >= 0; i--){
            if(ratings[i] > ratings[i + 1]){
                candyVec[i] = Math.max(candyVec[i+1] + 1, candyVec[i]);
            }
        }
        int count = 0;
        for(int num : candyVec){
            count += num;
        }
        return count;
    }
}

3. 柠檬水找零

力扣
如果对一道题没有思路,将所有的情况都罗列出来,想好对应的处理方法,会找到一些解决方法。

用三个数记录不同面额钱的数量,遍历数组,对每个元素分别讨论,如果无法处理就返回false。

class Solution {
    public boolean lemonadeChange(int[] bills) {
        if(bills[0] != 5){
            return false;
        }
        int five = 0;
        int ten = 0;
        int twenty = 0;
        for(int i = 0; i < bills.length; i++){
            if(bills[i] == 5){
                five++;
            }
            if(bills[i] == 10){
                if(five <= 0){
                    return false;
                }
                five--;
                ten++;
            }
            if(bills[i] == 20){
                if(ten > 0 && five > 0){
                    ten--;
                    five--;
                }else if(five >= 3){
                    five -= 3;
                }else{
                    return false;
                }
            }
        }
        return true;
    }
}

4. 根据身高重建队列

力扣
本题和分发糖果有一点类似,都是先处理一边再处理另一边。

本题要求重新排列二维数组,对每个数组中的两个元素[身高,前面大于等于本身高的人数]都有要求,要先处理好一个再处理另一个。发现先按从大到小排列身高可以满足要求。
在这里插入图片描述
按从大到小排列身高,如果说身高相同元素[2]小的在前面。按照身高排好后,从前往后遍历,如果当前元素的[2]不符合直接插到对应下标即可。因为后面的都比前面的小,插到前面也不会影响原本已插入的节点。java中可以用链表实现。

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people, (a,b) ->{
            if(a[0] == b[0]){
                return a[1] - b[1];
            }
            return b[0] - a[0];
        });
        LinkedList<int[]> que = new LinkedList<>();
        for(int[] p : people){
            que.add(p[1], p);
        }
        return que.toArray(new int[people.length][]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值