最小总和,使得每三个连续元素中的一个被采用

时间:2017-08-02 13:44:56

标签: algorithm recursion dynamic-programming

给定n个非负整数的数组(arr []),我们必须找到元素的最小总和,以便挑选每3个连续元素中的至少一个元素。

Input : arr[] = {1, 2, 3}
Output : 1

Input : arr[] = {1, 2, 3, 6, 7, 1}
Output : 4
We pick 3 and 1  (3 + 1 = 4)
Note that there are following subarrays
of three consecutive elements
{1, 2, 3}, {2, 3, 6}, {3, 6, 7} and {6, 7, 1}
We have picked one element from every subarray.

Input : arr[] = {1, 2, 3, 6, 7, 1, 8, 6, 2,
                 7, 7, 1}
Output : 7
The result is obtained as sum of 3 + 1 + 2 + 1

这个的递归方程如下:

sum[i]= arr[i] + min(sum[i-1],sum[i-2],sum[i-3])
where the base condition is: 
if i==3, then sum(3)= arr[3] + min(sum(0),sum(1),sum(2)) where 
    sum(0)=arr[0]
    sum(1)=arr[1]
    sum(2)=arr[2]
result=min(sum(n-1), sum(n-2), sum(n-3))

请解释形成的递归方程背后的直觉。为什么添加当前的i th 数组元素和最后三次递归调用的结果的min给出了大小为i的数组的正确答案?

2 个答案:

答案 0 :(得分:2)

递归公式确实是正确的,但只有在扩展时具有以下内容:

output = min(sum(n-1), sum(n-2), sum(n-3))

...其中 n 的大小为arr。在n < 3的情况下,当然输出是所有arr值中的最小值。

递归公式满足要求&#34;每3个连续元素中至少有一个元素被选中&#34; ,这与索引距离<两个相邻选择(或数组末尾)之间的/ em>最多为3:

  • 对于 i &gt; = 3,sum(i)将包含 i 的值,以及中的至少一个值i-1 i-2 i-3 ,因为每个的sum定义也包括该索引处的值。显然,指数差异最多为i - (i-3),即3。

  • i &lt; 3,确实如此,因为它们之前的值少于3个。

递归公式(包括最终输出的必要公式)也满足&#34;输出元素&#34; 的最小总和的要求。这是因为最佳解决方案必须包含索引 n-1 n-2 n-3 ,否则不符合其他条件。

  • 由于sum(i)在必须包含 i 时最小化总和,因此sum(n-1), sum(n-2), sum(n-3)中的最小值将找到最佳解决方案。

答案 1 :(得分:0)

基于我与@trincot的对话。我对为什么有一个函数sum()和列表sum[]感到有点困惑。我做了一点搜索,我认为这是因为解决方案涉及使用动态编程生成列表sum并使用它将答案存储为sum[i]如果我们使用输入的第一个i项阵列。

如果您阅读了trincot的答案并感到困惑,并想知道代码看起来如下所示(在Java中):

import java.lang.Math;
import java.util.Arrays;


public class MinSumThreeConsec{

    public static int minSumThreeConsec(int[] arr){
        int n = arr.length;

        if(n == 0){
            return 0;
        }

        //if the length of the array lenght is 3 or less
        if(n <= 3){ 
            Arrays.sort(arr);
            return arr[0];  
        }

        //if array size is larger than 3 than we need to use DP to pupulate the list sum
        int[] sum = new int[n];

        //fill out the base cases
        sum[0] = arr[0];
        sum[1] = arr[1];
        sum[2] = arr[2];


        for(int i = 3; i<n; i++){
            sum[i] =  arr[i] + min(sum[i-1], sum[i-2], sum[i-3]); //include value at index i in arr. and the mimum value from sum[i-1], sum[i-2], sum[i-3]
        }


        return min(sum[n-1], sum[n-2], sum[n-3]); //refer to trincot's answer above
    }

    public static int min(final int a, final int b, final int c){
        return Math.min(a, Math.min(b, c));
    }

    public static void main(String[] args){

        int[] arr = {};
        System.out.print(minSumThreeConsec(arr)); //empty case print 0

        int[] arr1 = {3,2,1};
        System.out.print(minSumThreeConsec(arr1)); //print 1

        int[] arr2 = {1, 2, 3, 6, 7, 1};
        System.out.print(minSumThreeConsec(arr2)); //print 4

        int[] arr3 = {1, 2, 3, 6, 7, 1, 8, 6, 2, 7, 7, 1}; //print 7
        System.out.print(minSumThreeConsec(arr3));

        int[] arr4 = {1, 2, 3, 6, 7, 1, -8, 6, 2, 7, 7, 1}; //print -1
        System.out.print(minSumThreeConsec(arr4));
    }

}

我认为这甚至适用于列表中的负数。