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

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

    示例:

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

    方法一:暴力法

    public int MaxsubArray1(int nums[]) {
    		int Sum = 0, MaxSum = 0;
    		int N = nums.length; //获得当前数组个数
    		for(int i = 0; i < N; i++) {
    			Sum = 0;
    			for(int j = i; j < N; j++) { 
    				Sum += nums[j];
    				if(Sum > MaxSum) { //比较子列和,当大于最大项时
    					MaxSum = Sum;
    				}
    			}
    		}
    		return MaxSum;
    }
    

    复杂度分析:

    • 时间复杂度:O(N^2) 遍历两次数组
    • 空间复杂度:O(1) 使用常数空间

    方法二:动态规划法

    
    public int MaxsubArray2(int nums[]) {
    		int Sum = 0, MaxSum = 0;
    		int N = nums.length; //获得当前数组个数
    		for(int i = 0; i < N; i++) {
    			sum += nums[i];
    			if(sum > MaxSum) {
    				MaxSum = sum;
    			}else if(sum < 0) { 
    				sum = 0;
    			}
    		}
    		return MaxSum;
    }
    

    算法分析:

    数组边移动边处理,之前的子序和若为负,继续移动至最右端。
    

    复杂度分析:

    • 时间复杂度:O(N)遍历一次数组
    • 空间复杂度:O(1)使用常数空间

    方法三:分治法

    public static int MaxSubArray3 (int nums[]) {
    	int N = nums.length();
    	if(N < 1) {
    		return 0;
    	}
    	int left = 0;
    	int right = N - 1;
    	return DivideAndConquer(nums, left, right);	
    		
    }
    
    public static int DivideAndConquer(int nums[], int left, int right) {
    	//当子序列个数为1时
    	if(left == right) {
    			if(nums[left] > 0) {
    				return nums[left];
    			}else return 0;
    	}
    	//当子序列个数大于1时, 分别求左右子序列和
    	int mid = (left + right)/2;
    	int MaxLeftSum = DivideAndConquer(nums, left, mid);
    	int MaxRightSum = DivideAndConquer(nums, mid, right);
    	/*求中子序列和(跨分界线)*/
    	//分界线左边
    	int MaxLeftBorderSum = 0, int LeftBoderSum = 0;
    	for(int i = mid; i >= left; i--) {
    			LeftBoderSum += nums[i];
    			if(LeftBoderSum > MaxLeftBorderSum) {
    				MaxLeftBorderSum = LeftBoderSum;
    			}
    	}
    	//分界线右边
    	int MaxRightBorderSum = 0, int RightBoderSum = 0;
    	for(int j = mid; j <= right; j++) {
    			RightBoderSum += nums[j];
    			if(RightBoderSum > MaxRightBorderSum) {
    				MaxRightBorderSum = RightBoderSum;
    			}
    	}
    	//中子序列和
    	int MaxBorderSum = MaxLeftBorderSum + MaxRightBorderSum;
    	return MaxThree(MaxBorderSum, MaxLeftSum, MaxRightSum);
    }
    
    /*找出三数中最大值
    */
    public static int MaxThree(int a, int b, int c) {
    		return a > b ? a > c ? a : c : b > c ? b : c;
    }	
    

    算法分析:

    将问题分解为小问题,再用递归求解。最后合并小问题的解得到问题的解。
    
    假设最大子序列有n个数字,当n==1时,直接返回该数字;当n>1时,分为左子序列和、右子序列和、中子序列和(包括左右子序列的元素)。这里来自leetcode的讨论区的图更好理解:
    

    复杂度分析:

    • 时间复杂度:O(NlogN)最多需要N次递归
    • 空间复杂度:O(logN) 递归树的深度
  • 相关阅读:
    OFDM系统中频域同步技术及FPGA实现
    SystemVerilog的挑战和机遇
    基础知识要牢固..复习复习,再复习
    样式在.net下测试不成功.附解决办法
    学习.net2.0的网站
    08年又快结束了..抱怨下!~
    今天去面试.net开发,感想
    在b/s开发中经常用到的javaScript技术
    淘宝"新版"首页
    Ajax技术简单入门
  • 原文地址:https://www.cnblogs.com/EthanWong/p/12678707.html
Copyright © 2011-2022 走看看