zoukankan      html  css  js  c++  java
  • Leetcode——53.最大子序和


    @author: ZZQ
    @software: PyCharm
    @file: leetcode53_最大子序和.py
    @time: 2018/11/26 12:39

    要求:给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    示例:

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

    方法如下:

    方法一:暴力遍历法——O(n2)

    class Solution():
      def maxSubArray(self, nums):
            """
            :type nums: List[int]
            :rtype: int
            """
            nums_len = len(nums)
            if nums_len == 0:
                return 0
            if nums_len == 1:
                return nums[0]
            max_value = nums[0]
            for i in range(nums_len):
                temp_max = 0
                for j in range(i, nums_len):
                    temp_max += nums[j]  # 大量的重复运算,拖慢速度
                    max_value = max(max_value, temp_max)
            return max_value
    

    方法二:基于方法一避免大量的重复运算 ——O(n2)

    class Solution():
      def maxSubArray(self, nums): 
            """
            :type nums: List[int]
            :rtype: int
            """
            nums_len = len(nums)
            temp_sum = [0]*(nums_len+1)
            if nums_len == 0:
                return 0
            if nums_len == 1:
                return nums[0]
            max_value = nums[0]
            for i in range(nums_len):   # 基于方法一,避免大量的重复运算
                temp_sum[i] = temp_sum[i-1] + nums[i]
            for i in range(nums_len):
                for j in range(i, nums_len):
                    temp_max = temp_sum[j] - temp_sum[i-1]
                    max_value = max(max_value, temp_max)
            return max_value
    

    方法三:分治法——O(nlogn)

            将求长度为n的序列中的最大子序和华为分求两个长度为n/2的序列的最大子序和
            将当前需要计算最大子串的序列分为两半,
            前半段从后往前遍历求最大子串lmax,
            后半段从前往后遍历求最大子串rmax,
            lmax+rmax就是当前长度为n的序列的最大子串,
            然后递归去找长度为n/2的序列的最大子串和,不断求小的序列的子串和。
            最后进行比较,得出最大值就是所求结果。
    
    class Solution():
      def maxSubArray3(self, nums):  
            """
            :type nums: List[int]
            :rtype: int
            """
            nums_len = len(nums)
            if nums_len == 0:
                return 0
            left = 0
            right = nums_len - 1
            ans = self.maxSubArrayCompute(nums, left, right)
            return ans
    
        def maxSubArrayCompute(self, nums, left, right):
            """
            :type nums: List[int]
            :type left: int
            :type right: int
            :rtype: int
            """
            if left > right:
                return 0
            if left == right:
                return nums[left]
            middle = (left + right)/2
            left_max = self.maxSubArrayCompute(nums, left, middle)
            right_max = self.maxSubArrayCompute(nums, middle+1, right)
            lmax = nums[middle]
            left_sum = nums[middle]
            # 保证求得到子序列是连续的(也就是lmax + rmax是一个连续子序列的和)
            for i in range(middle-1, left-1, -1):  # 前半段逆序加(range(left,right,-1)表示逆序遍历)
                left_sum += nums[i]
                lmax = max(lmax, left_sum)
            rmax = nums[middle+1]
            right_sum = nums[middle+1]
            for i in range(middle+2, right+1):  # 后半段顺序加
                right_sum += nums[i]
                rmax = max(rmax, right_sum)
            return max(rmax+lmax, max(left_max, right_max))
    

    方法四:扫描法——O(n)

            当我们加上一个正数时,和会增加;
            当我们加上一个负数时,和会减少。
            如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。
    
    class Solution():
        def maxSubArray(self, nums):
            """
            :type nums: List[int]
            :rtype: int
            """
            nums_len = len(nums)
            current = nums[0]
            nums_sum = nums[0]
            # 我们考虑如果全是负数,那么返回最大的负数,如果最后的和为正,那么就使用扫描法
            for i in range(1, nums_len):
                if current < 0:
                    current = nums[i]  # 当前数小于0 肯定会舍去(否则将会影响接下来的和),换为下一个数
                else:
                    current += nums[i]  # 如果当前数不小于0,那么他会对接下来的和有积极影响
                if current > nums_sum:
                    nums_sum = current  # 这里既实现了负数返回最大也实现了扫描法
                #这里其实已经隐式的列举了所有可能,保留了所有可能的最大值
            return nums_sum
    

    方法五:动态规划——O(n)

            假设sum[i]为以i结尾的连续子串的和. 假设对于元素i,所有以它前面的元素结尾的子串和都已经求得,
            那么以第i个元素结尾且和最大的连续子串实际上,
               1)要么是以第i-1个元素结尾且和最大的连续子数组加上这个元素,
               2)要么只是第i个元素,即sum[i]
            所以当前的最大连续子串和的计算方法是max(sum[i-1]+nums[i], nums[i])
            这就是需要我们判断sum[i-1]是否大于0。
            由于每次运算只需要前一次的结果,因此算法的时间和空间复杂度都很小。
    
    class Solution():
        def maxSubArray5(self, nums):  # 动态规划
            """
            :type nums: List[int]
            :rtype: int
            """
            nums_len = len(nums)
            if nums_len == 0:
                return 0
            if nums_len == 1:
                return nums[0]
            nums_sum = nums[0]
            pre = nums[0]
            for i in range(1, nums_len):
                if pre > 0:
                    pre += nums[i]
                else:
                    pre = nums[i]
                nums_sum = max(nums_sum, pre)
    
            return nums_sum
    
  • 相关阅读:
    MD5 带salt 加密
    生成包含数字和大小写字母的随机码
    多读好代码助于提高
    Winform程序窗体间的跳转
    Sql Server 存储过程
    GDI+的学习
    管理人生的8个危机
    马云语录
    无边框窗体的拖动和拉伸
    安装oracle时遇到 环境变量path的值超过1023字符,无法设置该值
  • 原文地址:https://www.cnblogs.com/zzq-123456/p/10020587.html
Copyright © 2011-2022 走看看