day28 45. 跳跃游戏 II&&55. 跳跃游戏&& 122. 买卖股票的最佳时机 II&&53. 最大子数组和&&376. 摆动序列&&455. 分发饼干

    1. 跳跃游戏 II
      题目背景
      给定一个非负整数数组 nums,你最初位于数组的第一个位置。每个元素代表你在该位置可以跳跃的最大长度。目标是使用最少的跳跃次数到达数组的最后一个位置。
      实现思路
      预处理:将每个位置的最大可到达位置进行预处理,存储在原数组中。
      贪心策略:从当前位置出发,选择下一个能够到达最远位置的点作为下一个跳跃点。
      终止条件:如果当前位置能够直接到达或越过终点,则返回当前步数。
      代码逻辑
      遍历数组,更新每个位置的最大可到达位置。
      使用 while 循环,每次选择当前范围内能到达最远位置的点。
      如果当前范围覆盖终点,则直接返回步数。
      优化点
      不需要修改原数组,可以在原数组上直接计算最大可到达位置,节省空间。
点击查看代码
//45. 跳跃游戏 II
    public int jump(int[] nums) {
        if (nums.length == 0||nums.length == 1) return 0;
        for (int i = 0; i < nums.length; i++) {//统计每个位置最大能到达的右边界
            nums[i] = i +nums[i] ;
        }
        int count = 0;
        int left = 0;
        while (true) {
            if (nums[left] >= nums.length-1) {//判断右边界是否能够抵达终点,如果可以,就一步到位
                return ++count;
            }
            int max = left;
            for (int i = left+1; i <= nums[left]; i++) {//找到右边界最大的点
                if (nums[max]<nums[i]) max = i;
            }
            left = max;
            count++;
        }
    }

    1. 跳跃游戏
      题目背景
      判断是否能够通过跳跃到达数组的最后一个位置。
      实现思路
      贪心策略:维护一个变量 count,表示当前能到达的最远位置。
      遍历数组:在遍历过程中,更新 count,如果 count 小于当前索引,则无法继续前进,返回 false。
      代码逻辑
      初始化 count 为 nums[0]。
      遍历数组,更新 count 为当前能到达的最远位置。
      如果 count 为 0,则返回 false;如果遍历完成,则返回 true。
      优化点
      代码中已经使用了较优的贪心策略,时间复杂度为 O(n)。
点击查看代码
//55. 跳跃游戏
    public boolean canJump(int[] nums) {
        //3ms
        /*if (nums == null || nums.length == 0||nums.length == 1) return true;
        if (nums[0]==0) return false;
        for (int i = 1; i < nums.length-1; i++) {
            nums[i] = Math.max(nums[i-1]-1,nums[i]);
            if (nums[i] == 0) return false;
        }
        return true;*/
        //2ms
        if (nums == null || nums.length == 0||nums.length == 1) return true;
        if (nums[0]==0) return false;
        int count=nums[0];
        for (int i = 1; i < nums.length-1; i++) {
            count = Math.max(count-1,nums[i]);
            if (count == 0) return false;
        }
        return true;
    }
    1. 买卖股票的最佳时机 II
      题目背景
      给定一个数组 prices,表示每天的股票价格。可以进行多次买卖,但不能同时参与多笔交易。目标是最大化利润。
      实现思路
      贪心策略:只要当前价格高于前一天价格,就进行一次买卖操作。
      累加利润:将所有可能的正利润累加起来。
      代码逻辑
      使用双指针 i 和 j,分别表示前一天和当天。
      如果当天价格高于前一天价格,则累加利润。
      遍历完成后返回总利润。
      优化点
      当前实现已经很高效,时间复杂度为 O(n)。
点击查看代码
//122. 买卖股票的最佳时机 II
    public int maxProfit2(int[] prices) {
        //实现1
        /*int maxProfit = 0;
        int i=0,j=0;
        for (int k = 1; k < prices.length; k++) {
            if (i<j&&prices[k]<prices[j]){//已有可盈利的购入股票日和售出日,当股价开始下降时,提前一天将其售出
                maxProfit+=prices[j]-prices[i];
                i=k;//将降价当天设定为购入日
            }
            if(prices[k] > prices[i]) {//更新售出日
                j=k;
            }else if(prices[k] <= prices[i]) {//找到购入日
                i=k;
            }
        }
        if(i<j) maxProfit+=prices[j]-prices[i];//检验股票是否有可盈利的购入股票日和售出日,如果有,则将其售出
        return maxProfit;*/
        //贪心实现2
        if (prices == null || prices.length == 0) return 0;
        if (prices.length == 1) return prices[0];
        int sum = 0;
        int i=0,j=1;
        while (j < prices.length) {
            if (prices[j]-prices[i]>0) {//处理每一小段,只要有盈利就累加
                sum += prices[j]-prices[i];
            }
            i++;
            j++;
        }
        return sum;
    }
    1. 最大子数组和
      题目背景
      给定一个整数数组 nums,找到一个具有最大和的连续子数组。
      实现思路
      动态规划:使用 Kadane 算法,维护一个变量 currentSum 表示当前子数组的最大和,另一个变量 maxSum 表示全局最大和。
      更新策略:如果 currentSum 小于 0,则丢弃当前子数组,重新开始。
      代码逻辑
      初始化 currentSum 和 maxSum 为数组的第一个元素。
      遍历数组,更新 currentSum 和 maxSum。
      返回 maxSum。
      优化点
      当前实现已经是最优解,时间复杂度为 O(n)。
点击查看代码
//53. 最大子数组和
    public int maxSubArray(int[] nums) {
        //暴力算法,超时
        /*if (nums == null || nums.length == 0) return 0;
        if (nums.length == 1) return nums[0];
        int maxSum = Integer.MIN_VALUE;
        for (int i = 0; i < nums.length; i++) {
            int sum = nums[i];
            maxSum = Math.max(maxSum, sum);
            for (int j = i + 1; j < nums.length; j++) {
                sum += nums[j];
                maxSum = Math.max(maxSum, sum);
            }
        }
        return maxSum;*/
        if (nums == null || nums.length == 0) return 0;
        if (nums.length == 1) return nums[0];

        int maxSum = nums[0]; // 初始化为数组的第一个元素
        int currentSum = nums[0]; // 当前子数组的最大和

        for (int i = 1; i < nums.length; i++) {
            // 如果当前子数组的和小于0,则重新开始一个新的子数组
            currentSum = Math.max(nums[i], currentSum + nums[i]);
            // 更新全局最大和
            maxSum = Math.max(maxSum, currentSum);
        }

        return maxSum;
    }
    1. 摆动序列
      题目背景
      给定一个整数数组 nums,定义一个摆动序列:相邻两个差值的符号必须相反。目标是找到最长的摆动子序列的长度。
      实现思路
      差值判断:计算相邻两个元素的差值,判断是否满足摆动条件。
      状态更新:维护一个变量 prevDiff 表示前一个差值,用于判断当前差值是否与前一个差值异号。
      代码逻辑
      初始化 maxLength 为 1,prevDiff 为 0。
      遍历数组,计算当前差值。
      如果当前差值不为 0 且与前一个差值异号,则增加序列长度。
      返回 maxLength。
      优化点
      当前实现已经很高效,时间复杂度为 O(n)。
点击查看代码
//376. 摆动序列
    public int wiggleMaxLength(int[] nums) {
        if (nums == null || nums.length == 0) return 0;
        if (nums.length == 1) return 1;

        int maxLength = 1; // 初始化为1,因为单个数字本身是一个摆动序列
        int prevDiff = 0; // 用于记录前一个差值

        for (int i = 1; i < nums.length; i++) {
            int currDiff = nums[i] - nums[i - 1]; // 当前差值
            if (currDiff != 0) { // 如果当前差值不为0
                if (prevDiff == 0 || currDiff * prevDiff < 0) { // 如果前一个差值为0(即i前面都是同一个数字),或者当前差值与前一个差值异号
                    maxLength++; // 增加摆动序列的长度
                    prevDiff = currDiff; // 更新前一个差值
                }
            }
        }

        return maxLength;
    }

    1. 分发饼干
      题目背景
      给定两个数组 g 和 s,分别表示孩子的胃口值和饼干的大小。目标是最大化满足孩子的数量。
      实现思路
      排序:对孩子的胃口值和饼干大小分别排序。
      贪心策略:
      策略一:优先满足胃口大的孩子,跳过因胃口太大而无法满足的孩子。
      策略二:优先满足胃口小的孩子,跳过份量太小的饼干。
      代码逻辑
      对两个数组进行排序。
      使用双指针遍历,根据策略选择匹配方式。
      返回满足孩子的数量。
      优化点
      当前实现已经很高效,时间复杂度为 O(nlogn)(排序的开销)。
点击查看代码
 //455. 分发饼干
    //大的饼干尽量分配给胃口大的孩子,跳过因胃口太大而不能满足的孩子
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int i = g.length-1, j = s.length-1;
        int count = 0;
        while (i >= 0 && j >= 0) {
            if (g[i]>s[j]){
                i--;
            }else {
                i--;
                j--;
                count++;
            }
        }
        return count;
    }
    //先满足胃口小的孩子,跳过份量太小的饼干
    /*public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int i = 0, j = 0;
        int count = 0;
        while (i < g.length && j< s.length) {
            if (g[i]>s[j]){
                j++;
            }else {
                i++;
                j++;
                count++;
            }
        }
        return count;
    }*/
posted @ 2025-02-19 13:21  123木头人-10086  阅读(28)  评论(0)    收藏  举报