贪心问题java

本文探讨了贪心算法在解决区间问题中的应用,如选取最大面额的钞票和寻找非重叠区间。通过示例代码展示了如何利用贪心策略求解LeetCode上的435题和452题。同时,也提到贪心算法并不适用于所有问题,例如在打斗地主等博弈场景下,需要使用动态规划来解决。文章还介绍了动态规划在解决1288题删除被覆盖区间的问题,并提供了跳跃问题的自顶向下动态规划解法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是贪心选择性质呢,简单说就是:每一步都做出一个局部最优的选择,最终的结果就是全局最优。注意哦,这是一种特殊性质,其实只有一小部分问题拥有这个性质。

比如你面前放着 100 张人民币,你只能拿十张,怎么才能拿最多的面额?显然每次选择剩下钞票中面值最大的一张,最后你的选择一定是最优的。

然而,大部分问题都明显不具有贪心选择性质。比如打斗地主,对手出对儿三,按照贪心策略,你应该出尽可能小的牌刚好压制住对方,但现实情况我们甚至可能会出王炸。这种情况就不能用贪心算法,而得使用动态规划解决,参见前文 动态规划解决博弈问题。

https://leetcode-cn.com/problems/non-overlapping-intervals/submissions/

leetcode435

贪心问题 ,先排顺序,按照终止时间排序
再统计不相交的时间,
再做差
在这里插入图片描述

class Solution {
    // 贪心策略,先计算最多能组成的不重叠区间个数,然后用区间总个数减去不重叠区间的个数。

    public int eraseOverlapIntervals(int[][] intervals) {
        if(intervals==null || intervals.length<=0)return 0;
        int n = intervals.length;
        //返回的是 该去除的区间数
        return n-count_no_jiaoji(intervals);
    }
    //统计几个区间 时间是不相交
    int count_no_jiaoji(int[][] intervals){
         if(intervals==null || intervals[0].length<=0)return 0;
        //按照stop 时间重新排序
        Arrays.sort(intervals,new Comparator<int []>(){
            @Override
            public int compare(int []a1,int a2[]){
                return a1[1]-a2[1];
            }
        });
        int count = 1;// 至少有一个 区间不相交
        int x_end = intervals[0+0][0+1];
        for(int []inter:intervals){
            //每个区间进行计算 ,每个区间 的起始时间
            int start = inter[0];
            if(x_end<=start){
                count++;
                x_end = inter[1];
            }
        }
        //返回的是不相交的区间数目 。
        return count;
    }
}

打气球问题

leetcode452
在这里插入图片描述

class Solution {
    public int findMinArrowShots(int[][] points) {
        if(points==null || points.length<=0)return 0;
        int len = points.length;
        return findNochongdie(points);
    }
    int findNochongdie(int[][] points){
        Arrays.sort(points,new Comparator<int[]>(){
             //按照stop 时间重新排序
            @Override
            public int compare(int []a1,int a2[]){
                // [[-2147483646,-2147483645],[2147483646,2147483647]]
                // return Integer.compare(a1[1],a2[1]);
                return  a1[1]>a2[1]?1:-1;
            }
        });
        int count = 1;// 至少有一个 区间不相交
        int x_end = points[0+0][0+1];
        for(int []inter:points){
            //每个区间进行计算 ,每个区间 的起始时间
            int start = inter[0];
            if(x_end< start){
                count++;
                x_end = inter[1];
            }
        }
        //返回的是不相交的区间数目 。
        return count;
    }
}

经典贪心问题

跳格子

leetcode 55
在这里插入图片描述

class Solution {
    public boolean canJump(int[] nums) {
        int len = nums.length;
        int max = nums[0];
        if(len<=1)return true;
        for(int i=1;i<len-1;i++){
            // if(max)
            //不断更新
            if(i<=max){
                max  =  Math.max(max,nums[i]+i);
            }
        }
        return max>=(len-1) ? true : false ;
    }
}

删除被覆盖的区间

leetcode 1288
在这里插入图片描述
排序
在这里插入图片描述

public int removeCoveredIntervals(int[][] intervals) {
        Arrays.sort(intervals,(a,b)->{
            if(a[0]==b[0]) {return b[1] - a[1];}
            return a[0] - b[0];
        });
        int left = intervals[0][0];
        int right = intervals[0][1];
        int res = 0;
        for (int i = 1+0; i < intervals.length; i++) {
            int[] intv = intervals[i];
            // 情况一,找到覆盖区间
            if (left <= intv[0] && right >= intv[1]) {
                res++;
            }
            // 情况二,找到相交区间,合并
            if (right >= intv[0] && right <= intv[1]) {
                right = intv[1];
            }
            // 情况三,完全不相交,更新起点和终点 ,left right 都更新
            if (right < intv[0]) {
                left = intv[0];
                right = intv[1];
            }

        }
        return intervals.length - res;
    }

跳跃问题

自顶向下的方法。

在这里插入图片描述

class Solution {
    
    public int jump(int[] nums) {
        int len =nums.length;
        int memo[] = new int[len];
        for(int i=0;i<len;i++){
            memo[i] = len;//至多跳跃 n -1 步
        }
        return dp( nums,0,memo);

    }
    //从 index 处跳到 结尾 len-1 的所用的步数
    int dp(int []nums,int index,int[]memo){
        //终止条件达到 了索引 的最后
        int len  = nums.length;
        if(index>=len-1){
            return 0;
        }
        //该位置已经计算过了
        if(memo[index]!=len){return memo[index];}

        int step = nums[index];
        for(int i=1;i<=step;i++ ){
            //穷举所有的跳跃
           int sub= dp(nums,index+i,memo);
            memo[index] = Math.min(sub+1,memo[index])
;        }
return memo[index];
    }
}
好的,背包问题是一个经典的动态规划问题,但也可以使用贪心算法来解决。下面是使用贪心算法解决背包问题JAVA代码: ```java import java.util.Arrays; public class KnapsackProblem { public static void main(String[] args) { int[] weight = {10, 20, 30}; // 物品重量 int[] value = {60, 100, 120}; // 物品价值 int capacity = 50; // 背包容量 double maxValue = getMaxValue(weight, value, capacity); System.out.println("背包能装的最大价值为:" + maxValue); } /** * 获取背包能装的最大价值 * @param weight 物品重量 * @param value 物品价值 * @param capacity 背包容量 * @return 背包能装的最大价值 */ public static double getMaxValue(int[] weight, int[] value, int capacity) { int n = weight.length; double[] unitValue = new double[n]; // 单位价值 for (int i = 0; i < n; i++) { unitValue[i] = (double) value[i] / weight[i]; } int[] index = new int[n]; // 物品索引 for (int i = 0; i < n; i++) { index[i] = i; } Arrays.sort(index, (i, j) -> Double.compare(unitValue[j], unitValue[i])); // 按单位价值从大到小排序 double maxValue = 0; // 背包能装的最大价值 for (int i = 0; i < n && capacity > 0; i++) { int j = index[i]; double w = Math.min(weight[j], capacity); // 能装下的重量 maxValue += w * unitValue[j]; // 能装下的最大价值 capacity -= w; } return maxValue; } } ``` 在这个代码中,我们计算每个物品的单位价值,并按照单位价值从大到小排序,然后依次选择单位价值最大的物品放入背包中,直到背包无法再装下物品为止。 这里使用了lambda表达式来简化排序过程,如果不理解可以使用传统的Comparator或Comparable来进行排序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值