LintCode-连续子数组和

本文介绍了一种寻找数组中最大连续子数组和的有效算法,包括初始的穷举法及优化后的动态规划方法,后者显著提高了查找效率。

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

同样:博客的主要目的在于记录求解时的思路。

题目:给定一个整数数组,请找出一个连续子数组,使得该子数组的和最大。输出答案时,请分别返回第一个数字和最后一个数字的下标。(如果两个相同的答案,请返回其中任意一个)

方法1:穷举法,计算出任意一个数的所有子数组的和,并找出最大的,同时记录起始和结束index.

下面根据样例来说明, 给定 [-3, 1, 3, -3, 4],根据穷举法可以得到如下的表格:
这里写图片描述
第i行j列(j > i ) 表示 数组中i ~j之间数的和。通过表格可以直接找到最大的子数组和并确定起始位置(图中的第二列第五行,对应数组中[1,4])。

该方案代码如下:

class Solution {
public:
    /*
     * @param A: An integer array
     * @return: A list of integers includes the index of the first number and the index of the last number
     */
    vector<int> continuousSubarraySum(vector<int> &A) {
        // write your code here
        // solution 1
        int maxSum = -1000;
        int indexStart = 0;
        int indexEnd = 0;
        for ( int i = 0; i < A.size(); i++ )
        {
            int j = i;
            int tmpSum = 0;
            for ( ; j < A.size(); j++ )
            {
                tmpSum += A[j];
                if ( tmpSum > maxSum )
                {
                    maxSum = tmpSum;
                    indexStart = i;
                    indexEnd = j;
                }
            }
        }
        vector<int> vecRet;
        vecRet.push_back(indexStart);
        vecRet.push_back(indexEnd);
        return vecRet;
    }   
};

时间复杂度 T = n + (n-1) + …1 ⇒ O(N^2) ;空间复杂度 O(1)。

该代码在lintCode上运行之后,会发生超时现象,原因就在于时间复杂度太高。那么可以用什么方案进行优化呢。通过观察上面的表格,很容易发现后面的数据被加了很多次,另外可以看到,每一列最后一个数等于当列第一个数和下一列的最后一个数的和,即以i开始子数组和Sum(i)等于 A[i] + Sum(i+1) ==> Sum(i) = A[i] + Sum(i+1)。
那么,要使Sum(i) 最大该如何做呢,其实就很简单了。
SumMax(i) = A[i] + Sum(i+1) > 0 ? Sum(i+1) : 0;
从动态规划里看,这应该属于此问题的最优子结构了,边界就是 Sum(A.size() -1) = A[A.size()-1]了。计算出每一个数开始的最大子数组和,然后找出最大的就可以得到结果了。根据边界来看,显然从后往前计算,时间上更优,还是上面的例子,从后往前计算,可以得到如下的最大字数和的数组。
这里写图片描述
箭头表示计算方向,找到最大的数所在的index,即为起始index,往后直到子数组和小于0为止,即为终止index.
代码如下:

class Solution {
public:
    /*
     * @param A: An integer array
     * @return: A list of integers includes the index of the first number and the index of the last number
     */
    vector<int> continuousSubarraySum(vector<int> &A) {
        // write your code here
        // solution 2
        vector<int> partSum;
        partSum.resize(A.size(), 0);
        int nLen = A.size();
        int maxSum = -10000;
        int indexStart = 0;
        int indexEnd = nLen - 1;
        int indexTmp = nLen - 1;
        for ( int j = nLen - 1; j >= 0; j-- )
        {
            if ( j == nLen - 1 )
            {
                partSum[j] = A[j];
                if ( partSum[j] > maxSum )
                {
                    indexStart = j;
                    maxSum = partSum[j];
                }
                continue;
            }
            if ( partSum[j+1] >= 0 )
            {
                partSum[j] = partSum[j+1] + A[j];
            }
            else
            {
                partSum[j] = A[j];
                indexTmp = j; //重置临时的终点位置
            }

            if ( partSum[j] > maxSum )
            {
                indexStart = j;
                maxSum = partSum[j];
                indexEnd = indexTmp;  // 临时终点位置生效
            }
        }
        vector<int> ret;
        ret.push_back(indexStart);
        ret.push_back(indexEnd);
        return ret;
    }

};

上述方案,仅需遍历一遍数组即可求得最大的连续子数组和。时间复杂度O(N),空间复杂度O(N)。但也很容易的看出,空间复杂度可以降为O(1)。

总结:此题的关键在于找出子数组和与数组之间的关系。很多时候一眼想不出最佳的方案时,不妨先把暴力解法写出来,然后看看是否能优化。

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、COSO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析模拟,揭示了生物质炉具在实际应用中的优点挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值