连续子数组的最大和,子矩阵的最大和,最大m子段和(m=1时候,就是连续子数组和)

21 篇文章 0 订阅

连续子数组的最大和 

在线编程地址之一https://www.nowcoder.com/question/next?pid=17095741&qid=501563&tid=26279803

 

题目描述:给定一个数组arr,数组中的元素有整数也有负数,数组中的一个或者连续多个数组成一个子数组。

求所有子数组里面的最大和。例如现在有数组 {1 , -2 , 3 , 10 , -4 , 7 , 2 , -5 }。

输入:[1, -2, 3, 10, -4, 7, 2, -5]
 
输出:18

注意:测试用例注意全为负数的情况

解法1:暴力求解,三层循环,sum=array[i...j]其中的任意连续子数组和

public int FindGreatestSumOfSubArray(int[] array) {
        int len=array.length;
        if(len<1)return 0;
        if(len==1)return array[0];
        int res=array[0];
        for(int i=0;i<len;i++){
            for(int j=i;j<len;j++){
                int curSum=0;
                for(int k=i;k<=j;k++){
                    curSum+=array[k];
                }
                res=Math.max(res,curSum);
            }
        }
        return res;
    }

解法1-1,暴力的改进,使得为O(n*n),

x[i..j]之和 = x[i..j-1]之和 + x[j]

public int FindGreatestSumOfSubArray(int[] array) {
        int len=array.length;
        if(len<1)return 0;
        if(len==1)return array[0];
        int res=array[0];
        for(int i=0;i<len;i++){
            int curSum=0;
            for(int j=i;j<len;j++){
                curSum+=array[j];
                res=Math.max(res,curSum);
            }
        }
        return res;
    }

解法2:分支法O(nlogn),每次从数组的的中间节点,求以此点为核心,向左右扩展,得到最大和,然后再比较最大和在左边,在右边这两种情况比较

伪代码:maxSum3(0,arr.length-1)

float maxsum3(l, u)
    if (l > u) /* zero elements */
        return 0
        
    if (l == u) /* one element */
        return max(0, x[l])
    
    m = (l + u) / 2
    /* find max crossing to left */
    lmax = sum = 0
    for (i = m; i >= l; i--)
        sum += x[i]
        lmax = max(lmax, sum)
    
    /* find max crossing to right */
    rmax = sum = 0
    for i = (m, u]
        sum += x[i]
        rmax = max(rmax, sum)

    return max(lmax+rmax,
                maxsum3(l, m),
                maxsum3(m+1, u));

解法3:动态规划

dp[i]记录当前以i结尾的连续数组的最大值

(1)如果 dp[i]= dp[i-1]+nums[i] 比 num[i] 则dp[i] 小,就不是连续数组的最大值,另起炉灶,dp[i]=nums[i],状态从【i】重新开始,并把这个状态记录下来

(2)如果 dp[i]= dp[i-1]+nums[i] 比 num[i] 则dp[i] 小,是连续数组的最大值,把这个状态记录下来

(3)考虑特殊情况,比如数组为空或者为1

  public int FindGreatestSumOfSubArray(int[] array) {
        int len=array.length;
        if(len<1)return 0;
        if(len==1)return array[0];
        int dp[]=new int[len];
        dp[0]=array[0];
        int res=dp[0];
        for(int i=1;i<len;i++){
            dp[i]=Math.max(dp[i-1]+array[i],array[i]);
            res=Math.max(res,dp[i]);
        }
        return res;
    }


//不用数组,空间优化

public  int FindGreatestSumOfSubArray(int[] array) {
        int res = array[0]; //记录当前所有子数组的和的最大值
        int max=array[0];   //包含array[i]的连续数组最大值
        for (int i = 1; i < array.length; i++) {
            max=Math.max(max+array[i], array[i]);
            res=Math.max(max, res);
        }
        return res;
}
//另外一种写法

public int FindGreatestSumOfSubArray(int[] array) {
        int len=array.length;
        if(len<1)return 0;
        if(len==1)return array[0];
        int res=array[0];
        int presum=res;
        for(int i=1;i<len;i++){
            if(presum<0){
                presum=array[i];
            }
            else{
                presum=Math.max(presum+array[i],array[i]);
            }
            res=Math.max(res,presum);
        }
        return res;
    }

 

最大子矩阵的和

在线编程https://www.nowcoder.com/questionTerminal/a5a0b05f0505406ca837a3a76a5419b3

题目:

求一个M*N的矩阵的最大子矩阵和。
比如在如下这个矩阵中:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2 
拥有最大和的子矩阵为:
9 2
-4 1
-1 8
其和为15。
思路:行相加得到一个数组,对数组求最大子数组和。

最大子矩阵的和计算方式可以是这样,从第i行到第j行是满足条件的子矩阵的上下分界,现在需要求出列的分界。所以

可以把第i行到第j行,整行相加到一个数组中就是 

a[i][1....n]

+a[i+1][1......n]

+......

+a[j][1....n]

=b[1.............n];

然后对b求其最大连接子数组的和,得到的结果就是矩阵的最大和。

import java.util.Scanner;
public class Main{
    public static int Sum(int[] arr){
        int res = Integer.MIN_VALUE;
        int cur = 0;
        for(int i = 0;i < arr.length;i++){
            cur += arr[i];
            res = Math.max(res,cur);
            if(cur < 0)
                cur = 0;
        }
        return res;
    }
    public static int MaxRect(int[][] arr){
        int max = Integer.MIN_VALUE;
        int m = arr.length;
        int n = arr[0].length;
        for(int i = 0 ;i < m ;i++){
            int[] temp = new int[n];
            for(int j = i;j < m;j++){
               for(int k = 0;k < n;k++){
                   temp[k] += arr[j][k];
               }
               max = Math.max(max,Sum(temp));
            }
        }
        return max;
    }
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int[][] rec = new int[N][N];
        for(int i = 0 ;i < N;i++)
            for(int j = 0;j < N;j++)
                rec[i][j] = sc.nextInt();
                     System.out.println(MaxRect(rec));
    }
}

最大m子段和(m=1时候,就是连续子数组和)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值