『Leetcode 5191』K 次串联后最大子数组之和

『题目』:

 给你一个整数数组 arr 和一个整数 k。首先,我们要对该数组进行修改,即把原数组 arr 重复 k 次。举个例子,如果 arr = [1, 2]k = 3,那么修改后的数组就是 [1, 2, 1, 2, 1, 2]。然后,请你返回修改后的数组中的最大的子数组之和。注意,子数组长度可以是 0,在这种情况下它的总和也是 0。由于 结果可能会很大,所以需要 模(mod) 10^9 + 7 后再返回。

『输入输出』

输入:arr = [1,2], k = 3
输出:9

输入:arr = [1,-2,1], k = 5
输出:2

输入:arr = [-1,-2], k = 7
输出:0

『题解』:

这道题目其实是放大版《最大连续子数组之和》,首先最简单的想法复制所有数组,然后做一次最大连续子数组和。但是发现并不需要,其实因为是循环的,假设给的数组长度为n,数据为a[0]...a[n],假设sum=a[0] + a[1] + ...+ a[n],且sum > 0,那么最理想的最大值,肯定是a[start] + ... + a[n] + (k - 2) * sum + (a[0] + a[1] + ... + a[end],所以这道题目就可以转化为找startendend很好找,只要从0开始进行不断累加,找到最大的字串即可。那么start呢,就是跑一遍《最大连续子数组之和》,然后就可以加起来了。当然如果最大值是循环断开的,我的做法是复制一遍a数组,数组长度变成了2 * n,然后先做一次《最大连续子数组之和》,把最大值保留下来进行对比。

『实现』:

import java.util.Arrays;

public class test3 {

    private static final long mod = 1000000007;

    public int kConcatenationMaxSum(int[] arr, int k) {

        long ans = 0;

        if(arr == null || arr.length == 0 || k <= 0) return 0;

        if(k == 1)
        {
            long[] dp = new long[arr.length];
            dp[0] = arr[0];
            ans = Math.max(ans,dp[0]);

            for(int i = 1;i < arr.length;i++)
            {
               dp[i] = (dp[i - 1] + arr[i]) > arr[i] ? dp[i - 1] + arr[i] : arr[i];
               ans = Math.max(ans,dp[i]);
            }

            ans = ans % mod;
        }
        else
        {
            int[] tmp = new int[arr.length * 2];
            int[] bef = new int[arr.length * 2];
            long[] dp = new long[arr.length * 2];

            int bigind = -1; //最大连续串的标号
            long sum = 0;

            for(int i = 0;i < arr.length;i++)
            {
                tmp[i] = arr[i];
                sum = sum + arr[i];
                tmp[arr.length + i] = arr[i];
            }

            dp[0] = arr[0];
            bef[0] = 0;

            if(dp[0] > ans)
            {
                ans = dp[0];
                bigind = 0;
            }

            for(int i = 1;i < tmp.length;i++)
            {
                if(dp[i - 1] + tmp[i] > tmp[i])
                {
                    dp[i] = dp[i - 1] + tmp[i];
                    bef[i] = bef[i - 1];
                }
                else
                {
                    dp[i] = tmp[i];
                    bef[i] = i;
                }

                if(ans <= dp[i])
                {
                    ans = dp[i];
                    bigind = i;
                }
            }

            if(bigind == -1) return 0;
            if(k == 2) return (int) ans;

            if(sum >0)
            {
                long tmpans = (dp[tmp.length - 1] % mod + (sum % mod * (k - 2 - 1) % mod) % mod) % mod ;

                int tmpmax = 0;
                int tmpsum = 0;
                for(int i = 0; i < arr.length;i++)
                {
                    tmpsum += arr[i];
                    tmpmax = Math.max(tmpmax,tmpsum);
                }

                ans = Math.max(ans,(tmpans + tmpmax) % mod);
            }
        }

        return (int)ans;
    }

    public static void main(String[] args) {

        test3 of = new test3();
        int[] arr = {-5,-2,0,0,3,9,-2,-5,4};
        System.out.println(of.kConcatenationMaxSum(arr,5));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值