zoukankan      html  css  js  c++  java
  • [LeetCode] 53. Maximum Subarray(最大子数组)

    Description

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

    给定一个整数数组 nums,找一个连续子数组(至少包含一个数),这个子数组的元素和最大并返回这个和。

    Follow up

    If you have figured out the O(n) solution, try coding another solution using the divide and conqur approach, which is more subtle.

    如果你已经用 (O(N)) 的方法解决了,尝试用更微妙的分治法解决它。

    Examples

    Example 1

    Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
    Output: 6
    Explanation: [4,-1,2,1] has the largest sum = 6.
    

    Example 2

    Input: nums = [1]
    Output: 1
    

    Example 3

    Input: nums = [0]
    Output: 0
    

    Example 4

    Input: nums = [-1]
    Output: -1
    

    Example 5

    Input: nums = [-2147483647]
    Output: -2147483647
    

    Constraints

    • 1 <= nums.length <= 2*10^4

    • -2^31 <= nums[i] <= 2^31-1

    Solution

    动态规划法:

    假设有数组 nums,我们需要求以下标 i 结尾的子数组的最大值,那么有以下两种情况:

    1. 包括下标 i 之前的元素,这样只要求以 i - 1 下标为结尾的子数组的最大值,加上 i 即可

    2. 不包括下标 i 之前的元素,即单纯只有 nums[i](因为之前元素的子数组和的最大值可能为负数)

    以上两种情况取最大值,得到状态转移方程:

    [result[i] = max(result[i - 1] + nums[i], nums[i]) ]

    由于当前状态只与前一个状态有关,所以本来需要开一个数组的空间,现在可以压缩到一个变量

    localMax = max(nums[i], localMax + nums[i])
    

    最后的代码如下:

    import kotlin.math.max
    
    class Solution {
        fun maxSubArray(nums: IntArray): Int {
            if (nums.isEmpty()) {
                return 0
            }
            if (nums.size == 1) {
                return nums[0]
            }
            var result = nums[0]
            var currentMax = nums[0]
            for (i in 1..nums.lastIndex) {
                currentMax = max(nums[i], currentMax + nums[i])
                result = max(currentMax, result)
            }
            return result
        }
    }
    

    分治法:

    对于分治法,需要考虑以下问题:这个最大子数组位于哪里?有三种情况:

    1. 完全位于左半边

    2. 完全位于右半边

    3. 跨越左半边和右半边

    于是可以将数组分成两半,对左右两边的求解可以得到情况 1 和情况 2,对于情况 3 也只需要以 (O(N)) 时间从中间位置扫描一遍数组即可,代码如下:

    import kotlin.math.max
    
    class Solution {
        fun maxSubArray(nums: IntArray): Int {
            return if (nums.isEmpty()) {
                0
            } else {
                maxSubArray(nums, 0, nums.lastIndex)
            }
        }
    
        private fun maxSubArray(nums: IntArray, left: Int, rightInclusive: Int): Int {
            if (left > rightInclusive) {
                return Int.MIN_VALUE
            }
            val mid = left + (rightInclusive - left) / 2
            val leftMax = maxSubArray(nums, left, mid - 1)
            val rightMax = maxSubArray(nums, mid + 1, rightInclusive)
            val crossSum = maxCrossSum(nums, left, mid, rightInclusive)
    
            return maxOf(leftMax, crossSum, rightMax)
        }
    
        private fun maxCrossSum(nums: IntArray, left: Int, mid: Int, rightInclusive: Int): Int {
            var sum = 0
            var leftSum = 0
            for (i in mid - 1 downTo left) {
                sum += nums[i]
                leftSum = max(leftSum, sum)
            }
    
            sum = 0
            var rightSum = 0
            for (i in mid + 1..rightInclusive) {
                sum += nums[i]
                rightSum = max(rightSum, sum)
            }
            return leftSum + rightSum + nums[mid]
        }
    }
    
  • 相关阅读:
    一个bug案例分析
    《需求工程》阅读随笔-1.做什么和怎么做
    连贯接口(fluent interface)的Java实现及应用。
    代码覆盖率检测工具大全
    腾讯的一个移动端测试小工具GT
    用复制mysql/data 文件夹 下面的数据库的形式来复制数据库出现的问题
    淘客API升级后的解决方案,怎么采集淘宝的商品数据
    方维团购系统,给供货商添加省市地址
    支付宝担保交易收款接口使用
    方维分享系统首页,插入新品,用来做优化
  • 原文地址:https://www.cnblogs.com/zhongju/p/13830128.html
Copyright © 2011-2022 走看看