LeetCode之MaxSubArray

题目:
在这里插入图片描述
自己写了一种方法,方法很浅显易懂,可是时间复杂度比较高
思路:要想得到largest sum的情况肯定是 子数列的第一个数是正数,最后一个数也是正数。
所以要把数组中所有的正数都找出来,然后把所有从正数开始加到正数结束的情况都计算出sum,返回最大的sum即可。
如果数组中没有正数,则把数组中最大的数返回即可。

public static int maxSubArray(int[] nums) {
	  
	   List<Integer> list=new ArrayList<>();
	   int res=0;
	   int max=0;
	   //把数组里面所有的正数找出来,存存放到一个列表里面   
        for(int i=0;i<nums.length;i++) {
        	if(nums[i]>0) {
        		list.add(i);	
        	}
        }
        //如果数组中没有正数
        if(list.size()==0) {
        	max=nums[0];
        	for(int i=1;i<nums.length;i++) {
        		if(nums[i]>max) {
        			max=nums[i];
        		}
        	}
        	return max;
        }
  
        //把列表中的每一个数作为子数列的第一个数
        for(int i=0;i<list.size();i++) {
        	int sum=0;
        //从当前位置一直往后加
        	for(int j=list.get(i);j<nums.length;j++) {
        		 sum+=nums[j];
        //只有遇到另一个正数 才需要考虑结果是不是最大的
        		if(nums[j]>0) {
        			res=sum;
        			if(res>max) {
        				max=res;
        			}
        		}
        	}
    }
		return max;
	
}

Discuss里面说到分治的方法,没怎么看懂,最后只理解了另一种比较简单的方法

public int maxSubArray(int[] nums) {
	//如果数组为空 直接返回0
    if (nums == null || nums.length == 0) { return 0; }
    //把数组的第一个数赋给max 和sum
	int max = nums[0], sum = nums[0];
	
	for (int i = 1; i < nums.length; i++) {
	/*如果sum是一个负数 再加上其他的数(无论这个数是正的 还是负的)都不可能是最大的sum
      可以想象 就算我加上一个数可以得到最大的sum 那我把前面的负数去掉 sum岂不是更大  所以就直接把这个数赋给 sum
      其实这里的思想和我的方法有点类似,就是要sum最大,不可能是“负数” 开头的叠加       
  */
		if (sum < 0) { sum = nums[i]; }
		
    //如果 sum大于等于0 在此基础上再继续往后加 得到sum 再与max比较 
		else {sum += nums[i]; }
		max = Math.max(max, sum);
	}
	return max;
    }

在这里插入图片描述

### 关于 LeetCode 上使用分治法求解最大子数组和问题 #### 分治法的核心思想 分治法是一种通过将原问题分解成若干个小规模的相同子问题来解决的方法。对于最大子数组和问题,可以将其划分为三个部分:左半边的最大子数组和、右半边的最大子数组和以及跨越中间的最大子数组和[^3]。 --- #### 分治法的具体实现步骤 以下是基于分治法的思想设计的一个具体方案: 1. **定义递归函数** 定义一个辅助函数 `cross_sum(nums, left, mid, right)` 来计算跨越中间位置的最大子数组和;另一个函数 `max_subarray_sum(nums, left, right)` 则用于返回整个区间 `[left, right]` 的最大子数组和。 2. **划分左右两部分** 将当前数组分成两个子数组,分别位于索引范围 `[left, mid]` 和 `[mid+1, right]` 中,并递归调用上述函数处理这两部分。 3. **计算跨中点的最大子数组和** 计算从中间向两侧扩展所能得到的最大子数组和,这一步骤的时间复杂度为 \(O(n)\),因为每次只需遍历一次左侧和右侧即可找到最优解。 4. **合并结果** 返回三者中的最大值作为最终的结果:即左边区间的最大子数组和、右边区间的最大子数组和以及跨越中间的最大子数组和。 --- #### Python 实现代码 下面是完整的 Python 代码实现: ```python def maxSubArray(nums): def cross_sum(nums, left, mid, right): """计算跨越中间的最大子数组和""" if left == right: # 如果只有一个元素,则直接返回该元素 return nums[left] # 向左扩展找最大前缀和 left_max = float('-inf') total = 0 for i in range(mid, left - 1, -1): # 注意是从 mid 开始往左走 total += nums[i] if total > left_max: left_max = total # 向右扩展找最大后缀和 right_max = float('-inf') total = 0 for i in range(mid + 1, right + 1): # 注意是从 mid+1 开始往右走 total += nums[i] if total > right_max: right_max = total return left_max + right_max def max_subarray_sum(nums, left, right): """递归计算最大子数组和""" if left == right: # 基本情况:单个元素 return nums[left] mid = (left + right) // 2 # 左侧最大子数组和 left_sum = max_subarray_sum(nums, left, mid) # 右侧最大子数组和 right_sum = max_subarray_sum(nums, mid + 1, right) # 跨越中间的最大子数组和 cross_sum_value = cross_sum(nums, left, mid, right) return max(left_sum, right_sum, cross_sum_value) return max_subarray_sum(nums, 0, len(nums) - 1) ``` --- #### 示例分析 考虑输入 `nums = [-2,1,-3,4,-1,2,1,-5,4]`: - 当我们递归到某个阶段时,假设当前分割点为 `mid=3`(对应数值为 `4`),则: - 左侧最大子数组和为 `-2 + 1 - 3 = -4`; - 右侧最大子数组和为 `4 - 1 + 2 + 1 = 6`; - 跨越中间的最大子数组和为 `(1) + (4 - 1 + 2 + 1) = 7`。 - 最终取三者的最大值,因此答案为 `7`。 注意,在实际运行过程中,由于进一步细分,最终得出全局最大值仍为 `6`[^5]。 --- #### 时间与空间复杂度分析 - **时间复杂度**: 每次都将数组一分为二并线性扫描一遍,总共有 \(\log n\) 层递归树,每层操作量为 \(n\),故总体时间为 \(O(n\log n)\)。 - **空间复杂度**: 主要由递归栈决定,最坏情况下深度为 \(\log n\),所以空间复杂度为 \(O(\log n)\)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值