day29 135. 分发糖果&&134. 加油站&&1005. K 次取反后最大化的数组和

    1. 分发糖果
      问题描述
      根据孩子们的评分分发糖果,要求:
      每个孩子至少得到一颗糖果。
      如果一个孩子的评分比相邻孩子高,则他必须比相邻孩子得到更多糖果。
      解题思路
      两次遍历:
      从左到右:如果右边孩子的评分比左边高,则右边孩子至少比左边孩子多一颗糖果。
      从右到左:如果左边孩子的评分比右边高,则左边孩子的糖果数需要更新为右边孩子的糖果数加一(取最大值,避免覆盖)。
      计算总糖果数:将所有孩子的糖果数相加。
点击查看代码
//135. 分发糖果
    public int candy(int[] ratings) {
        int[] nums = new int[ratings.length];
        for (int i = 0; i < ratings.length-1; i++) {
            if (ratings[i] < ratings[i+1]) {
                nums[i+1] = nums[i] + 1;
            }
        }
        for (int i = ratings.length - 1; i > 0; i--) {
            if (ratings[i-1]> ratings[i]) {
                nums[i-1] = Math.max(nums[i] + 1,nums[i-1]);//不能把原来的值改小了
            }
        }
        int sum = ratings.length;
        for (int num : nums) {
            sum += num;
        }
        return sum;
    }
    1. 加油站
      问题描述
      给定两个数组 gas 和 cost,分别表示每个加油站的油量和从当前加油站到下一个加油站所需的油量。目标是找到一个起点,使得汽车可以绕一圈回到起点。
      解题思路
      贪心算法:
      如果从某个加油站出发,油量在中途变为负数,则说明从这个加油站到当前加油站之间的所有加油站都无法作为起点。
      更新起点为下一个加油站,并重置当前油量。
      总油量判断:
      如果总油量小于总消耗量,则无法完成一圈。
点击查看代码
//134. 加油站
    public int canCompleteCircuit(int[] gas, int[] cost) {
        //暴力算法,超时
        /*for (int i = 0; i < gas.length; i++) {
            int sum=0;
            int j =i;
            while (true){
                sum+=gas[j];
                sum-=cost[j];
                if (sum<0) break;
                j=++j%gas.length;
                if (j==i) return i;
            }
        }
        return -1;*/
        int curSum = 0;//记录临时的差值和
        int totalSum = 0;//记录总的差值和
        int index = 0;
        for (int i = 0; i < gas.length; i++) {
            curSum += gas[i]-cost[i];
            totalSum+=gas[i]-cost[i];
            if (curSum<0){//意味着前面的加油站都不能抵达i+1号加油站
                index=i+1;
                curSum=0;
            }
        }
        if (totalSum<0){//总的差值和小于0,不可能有解
            return -1;
        }
        return index;
    }

    1. K 次取反后最大化的数组和
      问题描述
      给定一个数组和一个整数 k,可以对数组中的任意元素取反 k 次,目标是使数组的和最大。
      解题思路
      优先处理负数:
      先对数组排序,从最小的负数开始取反,直到 k 用完或没有负数。
      处理剩余的 k:
      如果 k 为奇数,说明还需要取反一次,此时取反数组中绝对值最小的元素。
      如果 k 为偶数,取反偶数次对数组和无影响。
点击查看代码
//1005. K 次取反后最大化的数组和
    public int largestSumAfterKNegations(int[] nums, int k) {
        //每次找到最小值取反 6ms
        /*while (k>0) {
            int min = 0;
            for (int i = 1; i < nums.length; i++) {
                if (nums[i]<nums[min]) min=i;
            }
            nums[min] = -nums[min];
            k--;
        }
        int sum = 0;
        for (int num : nums) {
            sum+=num;
        }
        return sum;*/
        //2ms
        Arrays.sort(nums);
        for (int i = 0; i < nums.length&&k>0; i++) {//先处理所有负数,从小到大处理
            if (nums[i]<0) {
                nums[i] = -nums[i];
                k--;
            }
        }
        if (k%2==1){//如果k为奇数,则继续处理最小值(k为偶数的时候对整体没影响)1次
            Arrays.sort(nums);
            nums[0] = -nums[0];
        }
        int sum = 0;
        for (int num : nums) {
            sum+=num;
        }
        return sum;
    }
posted @ 2025-02-21 18:38  123木头人-10086  阅读(19)  评论(0)    收藏  举报