算法期中 : 1005. 最小和

来源:互联网 发布:自制漫画软件下载 编辑:程序博客网 时间:2024/06/05 21:05

Description

从数列A[0], A[1], A[2], …, A[N-1]中选若干个数,要求对于每个i(0<=i< N-1),A[i]和A[i+1]至少选一个数,求能选出的最小和.

1 <= N <= 100000, 1 <= A[i] <= 1000

请为下面的Solution类实现解决上述问题的函数minSum,函数参数A是给出的数列,返回值为所求的最小和.

class Solution {public:    int minSum(vector<int>& A) {    }};

例1:A = {2, 5, 2},答案为4.

例2:A = {2, 5, 4},答案为5.

分析与设计

这是一道动态规划问题。

设d(i)表示从A[i]开始往后找到的最小和(这个最小和中包含A[i])。那么d(N-1)=A[N-1],d(N-2)=A[N-2];拿例1做比方,d(2)=2,d(1)=5,可以很容易得出结论。

对于任意的0 <= i < N - 2,存在如下状态转移方程:
d(i) = A[i] + min(d(i+1), d(i+2))
这是因为对于j=i+1来说,A[j]和A[j+1]至少需要选择一个数,所以只要选择两者中较小的一个就行了。

递推计算到A[0],就可以求出问题的解了:比较A[0]和A[1],较小者就是问题的解。因为A[0]和A[1]都满足最小和在选数上的要求,所以需要进行比较后才能确定最终的最小和。

计算N个数的d(i)的时间复杂度是O(n),所以整个算法的时间复杂度是O(n)。

代码

class Solution {    public:        int minSum(vector<int>& A) {            setUp(A);            calculateMinSumFromEveryIndex(A);            return minSumOfSequence();        }    private:        int *minSumFromIndex;        void setUp(vector<int>& A) {            if (minSumFromIndex != NULL)                delete []minSumFromIndex;            minSumFromIndex = new int[A.size()];        }        void calculateMinSumFromEveryIndex(vector<int>& A) {            for (int i = A.size() - 1; i >= 0; i--)                calculateMinSumFromIndex(A, i);        }        void calculateMinSumFromIndex(vector<int>& A, int index) {            int lastIndex = A.size() - 1;            if (index == lastIndex || index == lastIndex - 1)                minSumFromIndex[index] = A[index];            else                minSumFromIndex[index] =                     minSumFromIndex[index + 1] < minSumFromIndex[index + 2] ?                    A[index] + minSumFromIndex[index + 1] :                    A[index] + minSumFromIndex[index + 2];        }        int minSumOfSequence() {            return minSumFromIndex[0] < minSumFromIndex[1] ?                minSumFromIndex[0] : minSumFromIndex[1];        }};