代码随想录第29天|贪心

134.加油站

 代码随想录

索引01234
gas12345
cost34512

计算每个加油站的剩余油量,累计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][]);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值