乐趣区

关于leetcode:LeetCode-从滑动窗口到初级动态规划解决一类题

原文链接:何晓东 博客

剑指 Offer 57 – II. 和为 s 的间断负数序列

输出一个正整数 target,输入所有和为 target 的间断正整数序列(至多含有两个数)。

序列内的数字由小到大排列,不同序列依照首个数字从小到大排列。

示例 1:

 输出:target = 9
输入:[[2,3,4],[4,5]]

示例 2:

 输出:target = 15
输入:[[1,2,3,4,5],[4,5,6],[7,8]]

限度:

1 <= target <= 10^5

起源:力扣(LeetCode)
链接:https://leetcode-cn.com/probl…

解题思路

经典滑动窗口,间接限度最多滑到一半,能省很多计算。
 
代码实现:

class Solution {

    /**
     * @param Integer $target
     * @return Integer[][]
     */
    function findContinuousSequence($target) {
        $i = 1;
        $j = 2;
        $result = [];

        # 滑动窗口的右边界不能超过 target 的中值

        while ($j <= $target / 2 + 1) {
            # 计算以后窗口内数字之和

            $curSum = array_sum(range($i, $j + 1));

            # 若和小于指标,右指针向右挪动,扩充窗口

            if ($curSum < $target) {
                $j++;
                # 若和大于指标,左指针向右挪动,减小窗口

            } elseif ($curSum > $target) {$i++;}
            # 相等就把指针造成的窗口增加进输入列表中
            # 别忘了,这里还要持续扩充寻找下一个可能的窗口

            else {$result[] = range($i, $j + 1);
                # 这里用 j +=1,i+=1,i+= 2 都能够的

                $j++;
            }
        }

        return $result;
    }
}
剑指 Offer 42. 间断子数组的最大和

输出一个整型数组,数组中的一个或间断多个整数组成一个子数组。求所有子数组的和的最大值。

要求工夫复杂度为 O(n)。

示例 1:

 输出: nums = [-2,1,-3,4,-1,2,1,-5,4]
输入: 6
解释: 间断子数组 [4,-1,2,1] 的和最大,为 6。

起源:力扣(LeetCode)
链接:https://leetcode-cn.com/probl…

解题思路 1 滑动窗口

持续滑动窗口,比以后最大值大则右移指针,比以后最大值小则左指针开始膨胀。

代码实现:

class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function maxSubArray($nums) {
        //sum 用于记录滑动窗口中所有数的和

        $sum = 0; $left = 0; $result = PHP_INT_MIN;
        $count = count($nums);
        for ($right = 0; $right < $count; $right++) {$sum += $nums[$right];
            // 每次右指针挪动一格,就须要比拟一次

            $result = max($result, $sum);
            // 留神这里当 left==right 时,left 指针也要移

            while ($left <= $right && $sum <= 0) {$sum -= $nums[$left];
                $left++;
            }
        }

        return $result;
    }
}
解题思路 2 动静布局

动静布局解法:
首先定义看给出的大问题是否能拆分成小问题,最间接的就是一些数组中求性质,能够看成一个个更小的数组所形成的小问题。这些小问题形成了了一个个小状态,要想分明怎么从这些小状态走到大状态,进而解决大问题(这就是状态转移方程)。外围是:

○ 如何形象,定义状态 dp[i]
○ 状态转移方程的确定 dp[i] 如何从之前的状态失去
○ 初始的一些状态是能够看进去的比方 dp[0],dp[1]

代码实现:

class Solution {

    /**
     * @param Integer[] $nums
     * @return Integer
     */
    function maxSubArray($nums) {$count = count($nums);
        if ($count === 0) {return 0;}
        
        $dp = $nums[0];
        $max = $nums[0];
        for ($i = 1;$i < $count; $i++) {$dp = max($dp + $nums[$i], $nums[$i]);
            $max = max($max, $dp);
        }

        return $max;
    }
}

上题能够引申出:交易股票的最佳时机 Ⅰ:https://leetcode-cn.com/probl… 和下面的相似,股价变动 [7,1,5,3,6,4] 能够转化成 [-6, 4, -2, 3, -2],买入和卖出一次,能够转换成求间断子数组的最大和 **

代入一个 多个子序列最大和 的问题,例如 给定一个整数数组 nums,找到一个或多个具备最大和的间断子数组(子数组起码蕴含一个元素),返回其最大和,若最大和小于 0,则返回 0

○ 示例:[-2,1,-3,4,-1,2,1,-5,4]
○ 输入:12
○ 解释:间断子数组 [1],[4],[2,1],[4] 的和最大,为 12。

实际上是这道题是从数组中取所有的负数,累加的后果就是最大和

持续引申出另一个相似问题:

122. 交易股票的最佳时机 II

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你能够尽可能地实现更多的交易(屡次交易一支股票)。

留神:你不能同时参加多笔交易(你必须在再次购买前发售掉之前的股票)。

示例 1:

 输出: [7,1,5,3,6,4]
输入: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能取得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能取得利润 = 6-3 = 3。

示例 2:

 输出: [1,2,3,4,5]
输入: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 5)的时候卖出, 这笔交易所能取得利润 = 5-1 = 4。留神你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参加了多笔交易,你必须在再次购买前发售掉之前的股票。

示例 3:

 输出: [7,6,4,3,1]
输入: 0
解释: 在这种状况下, 没有交易实现, 所以最大利润为 0。

起源:力扣(LeetCode)
链接:https://leetcode-cn.com/probl…

代码实现:

class Solution {

    /**
     * @param Integer[] $prices
     * @return Integer
     */
    function maxProfit($prices) {
        $ans = 0;
        $count = count($prices);
        for ($i = 1; $i < $count; $i++) {if ($prices[$i] - $prices[$i-1] > 0) {$ans += $prices[$i] - $prices[$i - 1];
            }
        }

        return $ans;
    }
}

参考链接:

  1. 极客工夫 算法面试通关 40 讲

最初恰饭 阿里云全系列产品 / 短信包特惠购买 中小企业上云最佳抉择 阿里云外部优惠券

退出移动版