算法期中练习——1005. 最小和

算法期中练习——1005. 最小和

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

Example:

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

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

1
2
3
4
5
6
class Solution {
public:
int minSum(vector<int>& A) {

}
};

分析:

动态规划的问题:这道题在考试的时候做不出来,动态规划有那么一个痛点,就是明明知道要用动态规划来求解,然而子问题很难分析出来,更别说求解的递归公式了。
考完试后,看了大神的代码,理解了一下,就是最后一个数选不选的问题,如果不选,说明前一个数一定选,而选的话无法确定前一个数是否选,因此需不断比较之前的数是否选,返回最后一个数选和最后一个数不选的比较结果(最小)。

可能说起来比较难懂,我们看看下面两个解法的手工求解过程:

Solution #1

例1:
sum[0]=2, sum[1]=5, sum[2]=min(4, 7)=4
return min(4, 5)=4

例2:
sum[0]=2, sum[1]=5, sum[2]=min(6, 9)=6
return min(6, 5)=5

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
int minSum(vector<int>& A) {
int size = A.size();
vector<int> sum(size, 0);//sum[size-1]表示最后一个被选中时的最小和
sum[0] = A[0];
if (size > 1) sum[1] = A[1];

for (int i = 2; i < size; i++) {
sum[i] = min(sum[i - 2] + A[i], sum[i - 1] + A[i]);
}
if (size == 1) return sum[0];
else return min(sum[size - 1], sum[size - 2]);
}
};

Solution #2:

f[0][i]存储最后一个数不选的结果;
f[1][i]存储最后一个数选的结果。

例1:
f[0][0]=0, f[1][0]=2
f[0][1]=2, f[0][2]=5
f[0][2]=5, f[1][2]=4
return min(f[0][2], f[1][2])=min(5, 4)=4

例2:
f[0][0]=0, f[1][0]=2
f[0][1]=2, f[1][2]=5
f[0][2]=5, f[1][2]=6
return min(f[0][2], f[1][2])=min(5, 6)=5

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
private:
vector<int> f[2];
public:
int minSum(vector<int>& A) {
int n, i;
n = A.size();
if (n == 0) return 0;
f[0].resize(n);
f[1].resize(n);
f[0][0] = 0;
f[1][0] = A[0];
for (i = 1; i < n; i++) {
f[0][i] = f[1][i - 1];
f[1][i] = A[i] + min(f[0][i - 1], f[1][i - 1]);
}
return min(f[0][n - 1], f[1][n - 1]);
}
};
------本文结束感谢阅读------