leetcode907:子数组的最小值之和

本文介绍了一种计算整数数组所有连续子数组最小值之和的方法,并使用动态规划解决该问题。给出的状态转移方程能有效求解,但实际运行中对于大数据量仍存在优化空间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述:

给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。

由于答案可能很大,因此返回答案模 10^9 + 7

 

提示:

  1. 1 <= A <= 30000
  2. 1 <= A[i] <= 30000

 

思路:采用从底向上的动态规划解题

 

设数组A[N],f(n)为sum(min(B)),

f(n)=f(n-1)+sum(min(A[i~n]))  (1<=i<=n)

 

可以理解为将A[N~N]加入后,往前扫描计算包含A[N~N]子数组的和,加上不包含A[N~N]子数组的和即为f(n)

 

在测试的时候10^4的量级是可以在1s内计算的,但是实际上只过了94%的测试用例,不知道有没有大神知道是咋回事不?

 

代码:

package com.cgg.leetcode;

import java.util.Arrays;

/**
 * @Author cgg 891842749@qq.com
 * @Date 2018-09-16 21:07:54
 * @Description gitee:www.gitee.com/cgggitee/
 * github:https://github.com/love390/
 */
public class Problem907 {
    private static Double MOD = Math.pow(10, 9) + 7;

    /**
     * 给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。
     * <p>
     * 由于答案可能很大,因此返回答案模 10^9 + 7。
     * <p>
     * 状态转移方程f[n]=f[n-1]+sum(min(A[i~n]))   (1<=i<=n)
     * <p>
     * 测试通过94%的用例,正常情况下O(N^2)应该是可以计算10^4的,但是有个超大数据来的时候结果超时
     * 1 <= A <= 30000
     * 1 <= A[i] <= 30000
     *
     * @param A
     * @return
     */
    public int sumSubarrayMins(int[] A) {
        if (A.length == 1) return A[0];
        int len = A.length;
        int[] flag = Arrays.copyOf(A, A.length);
        for (int i = 1; i < len; i++) {
            int tmp = 0;
            int minFlag = A[i];
            for (int j = i; j >= 0; j--) {//往前扫描计算包含A[N~N]子数组的和
                minFlag = Math.min(minFlag, A[j]);
                tmp = tmp + minFlag;
            }
            int a = flag[i - 1] + tmp;
            flag[i] = (int) (a % MOD);
        }
        return (flag[len - 1]);
    }

    public static void main(String[] args) {
//        int[] A = new int[]{3, 2, 1, 4};
        int len = 30000;
        int[] A = new int[len];
        for (int i = 0; i < len; i++) A[i] = (int) (Math.random() * len);
        Problem907 problem907 = new Problem907();
        long start = System.currentTimeMillis();
        System.out.println(problem907.sumSubarrayMins(A));
        System.out.println((System.currentTimeMillis() - start) * 1.000 / 1000 + "s");//结果0.4左右
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值