zl程序教程

您现在的位置是:首页 >  其它

当前栏目

贪心专题01

01 专题 贪心
2023-09-14 09:16:17 时间

第一题:力扣455题

解题思路:

使用贪心算法,只要满足局部最优解,最后就可以得到全局最优的解!
从数组的后边往前边依次遍历,满足大饼干给胃口大的孩子吃,最后就是尽可能地满足所有孩子的需求!

代码如下:

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int sIndex = s.length - 1;
        int res = 0;

        for(int i = g.length - 1; i >= 0; i--) {
            if(sIndex >= 0 && s[sIndex] >= g[i]) {
                res++;
                sIndex--;
            }
        }
        return res;
    }
}

第二题:力扣376题

解题思路:

摆动序列相当于单调递增或单调递减交错进行,把中间的数省略掉即可。

代码如下:

class Solution {
    public int wiggleMaxLength(int[] nums) {
        if(nums.length <= 1) {
            return nums.length;
        }
        int curDiff = 0;
        int preDiff = 0;
        int res = 1;//默认最右边有个峰值
        for(int i = 0; i < nums.length - 1; i++) {
            curDiff = nums[i + 1] - nums[i];
            //只要满足摆动数列,res就加加
            if(curDiff > 0 && preDiff <= 0 || curDiff < 0 && preDiff >= 0) {
                res++;
                preDiff = curDiff;
            }
        }
        return res;
    }
}

第三题:力扣53题

解题思路:

参见代码详解

代码如下:

class Solution {
    //贪心算法
    public int maxSubArray(int[] nums) {
        if(nums.length == 1) {
            return nums[0];
        }
        int res = Integer.MIN_VALUE;
        int count = 0;
        for(int i = 0; i < nums.length; i++) {
            //开始累加
            count += nums[i];
            //找连续和最大值
            if(count > res) {
                res = count;
            }
            //只要count出现负值了,就从下一个数重新计算
            if(count < 0) {
                count = 0;
            }
        }
        return res;
    }
}

当时没有学习动态规划解题,现在爬楼回来补上之前落下的,记2022.3.8

动态规划解题思路:

dp[i]:包括下标i之前的最大连续子序列和为dp[i]。
dp[i]怎么推导过来的呢???
无非就两条路:其一就是 dp[i-1] + nums[i] ,也就是前i-1个数再加上第i个数; 其二就是nums[i]本身 ,从这里重新开始。二者取最大即可。

代码如下:

//动态规划
class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
            if(res < dp[i]) {
                res = dp[i];
            }
        }
        return res;
    }
}

第四题:力扣122题

解题思路:

详见代码详解,贪心算法的思路我感觉有点说不清,哈哈哈,总之找出局部最优解就是最后的全局最优解,就要用贪心算法。

代码如下:

class Solution {
    public int maxProfit(int[] prices) {
        //贪心解决该问题:
        int res = 0;
        //把i天的股票价格中 抽取出 i-1 天的股票差价,我们只要把差价 为正 的数加起来就是最大利润
        for(int i = 1; i < prices.length; i++) {
            res += Math.max(prices[i] - prices[i - 1], 0);
        }
        
        return res; 
    }
}

第五题:力扣55题

解题思路:

将移动问题转换成炮弹射程问题比较好理解,哈哈!
详解见代码注释!!!

代码如下:

class Solution {
    public boolean canJump(int[] nums) {
        if(nums.length == 1) {
            return true;
        }
        int step = 0;
        //在当前能达到的范围内一步一步地移动
        for(int i = 0; i <= step; i++) {
            //每移动一步,更新一次step
            step = Math.max(step, i + nums[i]);
            //只要是step能够达到数组的最后一个下标位置,就返回true
            if(step >= nums.length - 1) {
                return true;
            }
        }
        return false;
    }
}

该题的升级版:力扣45题

解题思路:

类似与上一个题,只不过这次需要求出最小次数,详解见代码注释。

代码如下:

class Solution {
    public int jump(int[] nums) {
        if(nums.length == 1) {
            return 0;
        }
        int maxDistance = 0;//整体覆盖最大距离
        int curDistance = 0;//当前覆盖最大距离
        int res = 0;//结果
        //在当前能达到的范围内一步一步地移动
        for(int i = 0; i < nums.length; i++) {
            //更新最大距离
            maxDistance = Math.max(maxDistance, i + nums[i]);
            //只要覆盖到了最后,res++,之后跳出循环
            if(maxDistance >= nums.length - 1) {
                res++;
                break;
            }
            //如果到了当前最大范围还没有到达数组最后一个元素,那就更新当前最大距离
            if(curDistance == i) {
                curDistance = maxDistance;
                res++;
            }
        }
        return res;
    }
}

第六题:力扣1005题

解题思路:

第一步:将数组按照大小从大到小排序
第二步:从前向后遍历,遇到负数将其变为正数,同时K–
第三步:求和
第四步:如果此时K用完了,那就直接返回res;如果K还大于0,K为偶数,不用变了,直接返回res;K为奇数,用res减去2倍的最小正数,返回。

代码如下:

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        // 排序,把可能有的负数排到前面
        Arrays.sort(nums);
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            // 贪心:如果是负数,而k还有剩余,就把负数反过来
            if (nums[i] < 0 && k > 0) {
                nums[i] *= -1;
                k--;
            }
            //绝对值全加起来
            sum += nums[i];
        }
        Arrays.sort(nums);
        // 如果k没剩,那说明能转的负数都转正了,已经是最大和,返回sum
        // 如果k有剩,说明负数已经全部转正,所以如果k还剩偶数个就自己抵消掉,不用删减,如果k还剩奇数个就减掉2倍最小正数。
        return sum - (k % 2 == 0 ? 0 : 2 * nums[0]); 
    }
}

第七题:力扣134题

解题思路:

实在是想不到,参考人家这个自己写了一下Java代码!!!

代码如下:

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        //贪心解决
        int curSum = 0;
        int totalSum = 0;
        int res = 0;
        for(int i = 0; i < gas.length; i++) {
            int rest = gas[i] - cost[i];
            curSum += rest;
            totalSum += rest;
            //只要出现前几个和为0,说明车是跑不到这个加油站的,那就以下个加油站为起点跑
            if(curSum < 0) {
                res = i + 1;
                curSum = 0;
            }
        }
        //总的剩余油量rest小于0,根本不可能跑完一圈
        if(totalSum < 0) {
            return -1;
        }
        return res;
    }
}

今天不行了,肝不动了,休战,哇哈哈哈哈!明日大战三百回合===>