贪心算法

分发饼干

胃口值必须是最外层循环,因为不管满不满足条件它都需要移动

public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int j=s.length-1;
        int count=0;
        for(int i=g.length-1;i>=0;i--){
            if(j>=0 && s[j]>=g[i]){
                count++;
                j--;
            }
        }
        return count;
    }

 

摆动序列⭐

得到两个值,一个是前一段的差值,一个是后一段的插值,然后进行比较

public int wiggleMaxLength(int[] nums) {
        if(nums.length==1){
            return 1;
        }

        int result=1;
        //在前面增加一个虚节点和开头节点一样 
        int prediff=0;
        for (int i = 0; i < nums.length-1; i++) {
            int curdiff=nums[i+1]-nums[i];
            if (prediff<=0 && curdiff >0 || prediff>=0 && curdiff<0){
                result++;
                prediff=curdiff;
            }
        }
        return result;
    }

最大子数组和

局部思想:当和为负数时,直接重新从下一个开始

重点:只要sum<0就一定会重新开始,不论它与最大值的关系

public int maxSubArray(int[] nums) {
        int sum=0;
        int max=nums[0];
        for (int i=0;i<nums.length;i++){
            sum=sum+nums[i];
            if (sum>max){
                max=sum;
            } 
            if (sum < 0) {
                sum=0;
            }
        }
        return max;
    }

 

买卖股票的最佳时机

思路:每两天的利润值,大于0则相加

public int maxProfit(int[] prices) {
        int result=0;
        for(int i=1;i<prices.length;i++){
        int temp=prices[i]-prices[i-1];
        temp=temp>0?temp:0;
        result=result+temp;
        }
        return result;
    }

 

跳跃游戏

当覆盖范围大于nums.length-1时也是成功。

思路:只看覆盖范围

public boolean canJump(int[] nums) {
        int maxRange=0;
        for (int i = 0; i<= maxRange; i++) {
            int range=i+nums[i];
            maxRange=maxRange>range?maxRange:range;
            if (maxRange>=nums.length-1){
                return true;
            }
        }
        return false;
    }

 

跳跃游戏中返回跳跃的次数

遍历for循环,因为需要判断i==当前覆盖范围最大值时,此时应当count++,把下一步的最大值赋给当前范围。

public int jump(int[] nums) {
        if (nums.length==1){
            return 0;
        }
        //当前覆盖的最远距离下标
        int maxRange=0;
        //下一步覆盖的最远距离下标
        int next=0;

        int count=0;
        for (int i = 0; i <nums.length; i++) {
            next=Math.max(next,i+nums[i]);
            //下一步仔跳异步就会到达末尾
            if (next>=nums.length-1){
                count++;
                break;
            }
            if (i==maxRange){
                count++;
                maxRange=next;
            }

        }
        return count;
    }

 

K次取反后最大化的数组和

先排序 将负数全部取正,如果k不够立即跳出

        若k还有剩且是奇数  将数组重新排序,将最小的正数取反

public int largestSumAfterKNegations(int[] nums, int k) {
        //对数组进行排序 
        Arrays.sort(nums);
        //将最小的负数加上负号
        for (int i = 0; i < nums.length; i++) {
            if (nums[i]>=0){
                break;
            }
            nums[i]=-nums[i];
            k--;
            //如果k为0 直接结束
            if (k==0){
                break;
            }
        }
        
        if (k>0 && k%2==1){
            Arrays.sort(nums);
            nums[0]=-nums[0];
        }
        
        int sum=0;
        for (int i = 0; i < nums.length; i++) {
            sum=sum+nums[i];
        }
        
        return sum;
    }

 

加油站

得到每到一个加油站油的剩余情况,如果和为负数,则无解

  若和>=0,当前面为负数时,肯定不是起始加油站,从下一个加油站开始重新作为起点,直到找到一个从起始到结束为正数的。

public int canCompleteCircuit(int[] gas, int[] cost) {
        int[] res=new int[gas.length];
        int curSum=0;
        for(int i=0;i<gas.length;i++){
            res[i]=gas[i]-cost[i];
            curSum+=res[i];
        }

        if(curSum<0){
            return -1;
        }
        
        curSum=0;
        int th=0;
        for(int i=0;i<res.length;i++){
            curSum=curSum+res[i];
            if(curSum<0){
                curSum=0;
                th=i+1;
            }

        }
        return th;
        
    }

 

分发糖果

必须要两次遍历,从前往后遍历,拿右孩子和左孩子比较

再从后往前遍历,拿左孩子和右孩子比较,最终给的糖果数取两次最高的值

 public int candy(int[] ratings) {
        int[] candy=new int[ratings.length];
       Arrays.fill(candy,1);
       //从前往后 右孩子比左孩子得分高的情况
        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i]>ratings[i-1]){
                candy[i]=candy[i-1]+1;
            }
        }
        
        //从后往前 左孩子比右孩子得分高的情况
        for (int i = ratings.length-1; i >0; i--) {
            if (ratings[i-1]>ratings[i]){
                //比较两次结果candy的最大值 
                candy[i-1]=Math.max(candy[i-1],candy[i]+1);
            }
            
        }
        int sum=0;
        for (int i = 0; i < candy.length; i++) {
            sum+=candy[i];
        }
        return sum;
    }

 

posted @ 2025-03-20 16:04  Dyj07  阅读(9)  评论(0)    收藏  举报