代码随想录训练营第二十九天 | 134. 加油站 135. 分发糖果 860.柠檬水找零 406.根据身高重建队列

134. 加油站

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        int[] need = new int[n];
        for(int i=0; i<n; i++){
            need[i] = cost[i] - gas[i];
        }
        int start=0;
        while(start<n){
            int temp = 0;
            int i=start;
            for(; i<(start+n); i++){
                temp+=need[i%n];
                if(temp>0) break;
            }
            if(temp>0) start=i+1;
            else break;
        }
        if(start<n) return start;
        else return -1;
        
    }
}

135. 分发糖果

如随想录中所说,想一次性将所有条件全考虑完,会导致顾此失彼。

此时,一定要确定一边之后,再确定另一边。例如比较每一个孩子的左边,然后再比较右边。

我原本是想,i 一个个遍历,与左边相比较:但是真不好更新,很复杂

  1. 比左边大:左边+1
  2. 和左边一样大:设为1
  3. 比左边小:左边是否大于1——如果大于1,就设为1;如果等于1,就要更新前面所有值。
// 失败解法
class Solution {
    public int candy(int[] ratings) {
        int[] can = new int[ratings.length];
        Arrays.fill(can, 1);
        // 两边相等:取更小的
        // 左大右小:比小的+1即可
        for(int i=1; i<n; i++){ // 一旦不平衡,就更新
            int cur=i;
            if(ratings[cur] > ratings[cur-1]) can[cur] = can[cur-1]+1;
            else if(ratings[cur] == ratings[cur-1]){

            }else if (ratings[cur] < ratings[cur-1]){ // 更新前面
                if(can[cur] < can[cur-1]) 
                // 写不下去了……
            }
        }
        return 

    }
}

随后的解法:时间复杂度比较高

class Solution {
    public int candy(int[] ratings) {
        int[] can = new int[ratings.length];
        Arrays.fill(can, 1);
        // 从左向右遍历
        for(int i=1; i<ratings.length; i++){
            if(ratings[i] > ratings[i-1]) can[i] = Math.max(can[i], can[i-1]+1);
        }
        // 从右向左遍历
        for(int i=ratings.length-2; i>=0; i--){
            if(ratings[i] > ratings[i+1]) can[i] = Math.max(can[i], can[i+1]+1);
        }
        return Arrays.stream(can).sum();
    }
}

代码随想录解法:

class Solution {
    /**
         分两个阶段
         1、起点下标1 从左往右,只要 右边 比 左边 大,右边的糖果=左边 + 1
         2、起点下标 ratings.length - 2 从右往左, 只要左边 比 右边 大,此时 左边的糖果应该 取本身的糖果数(符合比它左边大) 和 右边糖果数 + 1 二者的最大值,这样才符合 它比它左边的大,也比它右边大
    */
    public int candy(int[] ratings) {
        int len = ratings.length;
        int[] candyVec = new int[len];
        candyVec[0] = 1;
        for (int i = 1; i < len; i++) {
            candyVec[i] = (ratings[i] > ratings[i - 1]) ? candyVec[i - 1] + 1 : 1;
        }

        for (int i = len - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) {
                candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);
            }
        }

        int ans = 0;
        for (int num : candyVec) {
            ans += num;
        }
        return ans;
    }
}

860.柠檬水找零

局部最优:遇到账单20,优先消耗美元10,完成本次找零。全局最优:完成全部账单的找零。

class Solution {
    public boolean lemonadeChange(int[] bills) {
        int[] arr = new int[2];

        int temp = 0;
        for(int b:bills){
            switch (b){
                case 5:
                    arr[0]++;
                    break;
                case 10:
                    arr[1]++;
                    temp = --arr[0];
                    break;
                case 20:
                    if(arr[1]>0){
                        arr[1]--;
                        temp = --arr[0];
                    }else{
                        arr[0] -= 3;
                        temp = arr[0];
                    }
                    break;
            }
            if(temp<0) return false;
        }
        return true;
    }
}

406.根据身高重建队列

类似于分发糖果:遇到两个维度权衡的时候,一定要先确定一个维度,再确定另一个维度。

所以在按照身高从大到小排序后:
局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性
全局最优:最后都做完插入操作,整个队列满足题目队列属性

整个插入过程如下:按照身高顺序,依次按照对应下表擦汗如。

排序完的people: [[7,0], [7,1], [6,1], [5,0], [5,2], [4,4]]
插入的过程:
插入[7,0]:[[7,0]]
插入[7,1]:[[7,0],[7,1]]
插入[6,1]:[[7,0],[6,1],[7,1]]
插入[5,0]:[[5,0],[7,0],[6,1],[7,1]]
插入[5,2]:[[5,0],[7,0],[5,2],[6,1],[7,1]]
插入[4,4]:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        // 先按照身高排,再按照……
        Arrays.sort(people, (a, b) -> { // 身高从小到大
            if(a[0]!=b[0]) return b[0]-a[0];
            else return a[1]-b[1];
        });
        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、付费专栏及课程。

余额充值