zoukankan      html  css  js  c++  java
  • 最大子数组算法问题的几种解法代码(使用Python描述)

    问题描述

    找出数组中存在的最大子数组(必须相连).(数组有正数与负数).

    示例: arr = [-1,-3,3,5,-4,3,2,-2,3,6].

    还原为实际场景可能是在一些具有相同属性的存在中,找出一段连续且最佳的存在.




    方法一:暴力破解法

    思路解释:使用暴力破解法.

    时间复杂度为O(n^2).

    # 使用暴力破解法.
    def max_violent(arr):
        max_value = arr[0]
        index_for_left =0
        index_for_right =0
    
        for i in range(len(arr)):
            for j in range(i,len(arr)):
    
                temporary_value = 0 # 基于Python的特性,可以将这行代码以及第三层for替换为:temporary_value = sum(arr[i:j])
                for k in range(i,j+1): 
                    temporary_value = temporary_value + arr[k]
                
                if(temporary_value>max_value):
                    max_value = temporary_value
                    index_for_left = i
                    index_for_right = j
        
        return (max_value,index_for_left,index_for_right)
    
    
    
    arr = [-1,-3,3,5,-4,3,2,-2,3,6]
    print(max_violent(arr))
    




    方法二:二分法

    def violence(l = []):
        maxVal = 0
        x,y=0,0
        for i in range(0,len(l)+1):
            for j in range(0,len(l)+1):
                res = sum(l[i:j])
                if res > maxVal:
                    maxVal = res
                    x = i
                    y = j
        return maxVal,x,y
    #分治法 想左扫 向右扫,求出两边的最大值
    def left_or_right(l):
        maxVal = 0
        term = 0
        for i in l:
            term += i
            if maxVal < term:
                maxVal = term
        return maxVal
    
    def Separate(l):
        middle = int(len(l)/2)
        l1 = l[0:middle]
        l2 = l[middle:len(l)]
        #左半部分
        maxVal1,x1,y1 = violence(l1)
        #右半部分
        maxVal2,x2,y2 = violence(l2)
        #跨立在中间
        max_right = left_or_right(l2)
        max_left = left_or_right(l1[::-1]) # 倒着扫描
    
        #print('---')
        #print(max_right)
        #print(l1[::-1])
        #print('---')
    
        maxVal3 = max_right + max_left
        return (maxVal1,maxVal2,maxVal3)
    arr = [-1,-3,3,5,-4,3,2,-2,3,6]
    val = Separate(arr)
    print(val)
    print(max(val))
    




    方法三:使用递归

      使用递归将时间复杂度降低到O(lgn).

      将一个主问题分解为若干子问题,进而将各个子问题的解.
    也就是递归的思想 -> 分而治之:
    - 原问题分解成多个子问题
    - 递归的求解各个子问题
    - 将结果合并为原问题解

    def max_digui(arr,low,high): # 使用递归
    
        if low==high: # 递归结束条件
            return arr[low]
    
        mid=(low+high)//2 # 向下取整
    
        m1=max_digui(arr,low,mid) # 递归
        m2=max_digui(arr,mid+1,high) # 递归
    
        now_left=arr[mid]
        maxleft=now_left
    
        for i in range(mid-1,low-1,-1): # 倒序循环
            now_left=now_left+arr[i]
            if now_left>maxleft:
                maxleft=now_left
    
    
        now_right=arr[mid+1]
        maxright=now_right
    
        for j in range(mid+2,high+1):
            now_right=now_right+arr[j]
            if now_right>maxright:
                maxright=now_right
    
    
        m3=maxleft+maxright
    
        return max(m1,m2,m3)
    
    arr = [-1,-3,3,5,-4,3,2,-2,3,6]
    print(max_digui(arr,0,len(arr)-1)) # 16找出的是最大值
    
    




    方法四:使用动态规划

    • 从数组最后的元素开始计算.
      • list[i]表示当前元素.d[i+1]表示d[i+1]的最优子数组的值.
      • 默认当前元素的最大子数组(list[i])是其本身.
      • 如果d[i+1] > 0.那么就加入后面的元素列表.


    • 使用最优规划的逻辑

      • 是确保每一个子问题都是最优解
      • 自底向上的运算
      • 一直解到所求的答案为止
    • 变量说明

      • alist是数据数组
      • list_dp 是记录当前元素最优值的表.
      • list_rec 是记录当前元素最优值终止的下标.
    
    def max_liat_dp(alist,list_dp,list_rec):
        
        max_num_now = alist[len(alist)-1]# 最后一个元素的的最大值默认是其本身.
        list_dp[len(alist)-1] = max_num_now # 记录进表中
        list_rec[len(alist)-1] = len(alist) - 1 # 最后一个元素的比较结束下标默认是本身
        
        for i in range(len(alist)-2,-1,-1): # 从倒数第二个元素到第0个元素.
            
            max_num_now = alist[i]
            list_rec[i] = i
    
            if list_dp[i+1] > 0: # 如果上一个元素的最优值大于0,那么就执行加入操作.
                max_num_now = max_num_now + list_dp[i+1]
                list_rec[i] = list_rec[i+1]
            
            list_dp[i] = max_num_now
        
        return (list_dp,list_rec)
    
    # 算法结束.
    # ------------------
    # 以下是数据测试类,用于测试算法正确性,非排序算法本身函数.
    # 可以删除TestDate类,手动填入数据测试.
    '''
    import unittest
    import random
    class TestData(unittest.TestCase):
        def create_data(self,num_start,num_end,num_length): # 生成list
    
            return [random.randint(num_start,num_end) for i in range(num_length)]
    
        def test_case1(self):
            '''
            # alist是数据数组
            # list_dp 是记录最优值的表.
            # list_rec 是记录终止位置.
            '''
            alist = [1,-2,4,5,-2,8,3,-2,6,3,7,-1]
            list_dp = [0]*len(alist)
            list_rec = [0]*len(alist)
    
            print(max_liat_dp(alist,list_dp,list_rec))
            print(max(list_dp))
            print('
    '*1)
    
        def test_case2(self):
            alist = self.create_data(-50,50,8)
            list_dp = [0]*len(alist)
            list_rec = [0]*len(alist)
    
            print(max_liat_dp(alist,list_dp,list_rec))
            print(max(list_dp))
            print('
    '*1)
    
        def test_case3(self):
            alist = self.create_data(-10,50,8)
            list_dp = [0]*len(alist)
            list_rec = [0]*len(alist)
    
            print(max_liat_dp(alist,list_dp,list_rec))
            print(max(list_dp))
            print('
    '*1)
    
        def test_case4(self):
            alist = self.create_data(1,50,5)
            list_dp = [0]*len(alist)
            list_rec = [0]*len(alist)
    
            print(max_liat_dp(alist,list_dp,list_rec))
            print(max(list_dp))
            print('
    '*1)
    
    
    
    
    if __name__ == "__main__":
        unittest.main() # 调用测试数据
    
        # alist是数据数组
        # list_dp 是记录最优值的表.
        # list_rec 是记录终止位置.
    
    
    




    参考

  • 相关阅读:
    对我人生影响最大的三位老师
    自我介绍
    转-一般产品的使用过程
    谷歌浏览器开发调试工具中Sources面板 js调试等 完全介绍 --转载
    接口测试--总结
    常见正则表达式
    B/S架构的软件,主要的功能测试点有哪些
    SQL语句大全转
    11.2
    11.1
  • 原文地址:https://www.cnblogs.com/gtscool/p/12461249.html
Copyright © 2011-2022 走看看