5的倍数与给定目标的总和

时间:2011-05-13 04:13:36

标签: java algorithm

  

可能重复:
  Java : Summation of multiples of 5 in a group to a given target

嗨,SO人,

我正在努力解决以下问题,没有正确的方法。

编写一个java函数,使得给定一个int数组,是否可以选择一些int的组,以便该组使用这些附加约束求和给定目标:数组中所有的5的倍数必须被列入该组。如果紧跟在5的倍数之后的值是1,则不能选择它。

  • groupSum5(0,{2,5,10,4},19)→true
  • groupSum5(0,{2,5,10,4},17)→true
  • groupSum5(0,{2,5,10,4},12)→false
  • groupSum5(0,{3,5,1},5)→true
  • groupSum5(0,{3,5,1},4)→false

函数siganture是public boolean groupSum5(int start,int [] nums,int target)

我已编写了部分代码,但同样存在失败的测试用例。

     public boolean groupSum5(int start, int[] nums, int target) {     
           start = 0;     
           boolean flag = false;     
           for(int i=0;i<nums.length;i++){     
             if(nums[i]%5==0){     
                  start+=nums[i];                   
             }else if((start != target) && (start%5==0)){     
                  start+=nums[i];       
             }else if(start == target){      
                  flag = true;      
                  return flag;     
             }else if((nums[i]%5==0) && (nums[i+1]==1)){      
                  continue;                
             }    
           }
            return flag;      
     }     

即使在编写此代码之后,所有测试用例都会失败。 我很难在这场仪式上挣扎很长时间。

为DIANTE编辑:你能否为我提供代码修复,因为我已经尝试过这么多,我不知道如何继续

1 个答案:

答案 0 :(得分:2)

这是一个解决方案,但在之后看到讨论:

package so5987154;

import java.util.Collection;
import java.util.List;
import java.util.Set;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class Summation {
    /**
     * Sum of start and every element of the collection.
     * 
     * @param start
     *            starting value for the sum
     * @param list
     *            Collection to sum.
     * @return the sum.
     */
    private int sum(final Integer start, final Collection<Integer> list) {
        int sum = start;

        for (final int i : list) {
            sum += i;
        }

        return sum;
    }

    /**
     * Given an array of ints, is it possible to choose a group of some of the ints, such that the group sums to the given target
     * with these additional constraints: all multiples of 5 in the array must be included in the group. If the value immediately
     * following a multiple of 5 is 1, it must not be chosen.
     * 
     * @param start
     *            not used
     * @param nums
     *            array of int (input)
     * @param target
     *            target value for the summation
     * @return true if we found a group that meet the criteria.
     */
    public boolean groupSum5(final int start, final int[] nums, final int target) {
        // list of values that need to be included (multiple of 5)
        final List<Integer> fixed = Lists.newArrayList();

        // list of value that can be included (anything but 1 preceded by a multiple of 5)
        final List<Integer> candidates = Lists.newArrayList();

        // fills candidates and fixed
        for (int i = 0; i < nums.length; i++) {
            final int cand = nums[i];

            if (cand == 1 && i > 0) {
                final int prev = nums[i - 1];
                if (prev % 5 != 0) {
                    candidates.add(cand);
                }
            } else if (cand % 5 == 0) {
                fixed.add(cand);
            } else if (cand <= target) {
                candidates.add(cand);
            }
        }

        // compute the sum of fixed
        final int sumFixed = sum(0, fixed);

        // if the sum of fixed is equals to target we don't need to do anything because
        // we already know we need to return true.
        if (sumFixed == target) {
            return true; // NOPMD
        }

        // if the sum of fixed is greater than target we don't need to do anything because
        // we already know we need to return false (all multiple of 5 must be included)
        // If candidates is empty there's no way we can achieve the desired goal.
        if (sumFixed <= target && !candidates.isEmpty()) {
            // generates all subsets of candidates:
            // { 1, 2 } => {}, {1}, {2}, {1, 2}
            final Set<Set<Integer>> powerSet = Sets.powerSet(Sets.newHashSet(candidates));

            // for each found subset, computes the sum of the subset and add it to the sum of
            // multiples of 5 then compare it to target. If equals => return true.
            for (final Set<Integer> set : powerSet) {
                if (sumFixed + sum(0, set) == target) {
                    return true; // NOPMD
                }
            }
        }

        return false;
    }
}

相关测试:

package so5987154.tests;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

import so5987154.Summation;

@SuppressWarnings("PMD")
public class SummationTest {
    private final Summation s = new Summation();

    @Test
    public void testGroupSum5() {
        assertTrue(s.groupSum5(0, new int[] { 2, 5, 10, 4 }, 19));
        assertTrue(s.groupSum5(0, new int[] { 2, 5, 10, 4 }, 17));
        assertFalse(s.groupSum5(0, new int[] { 2, 5, 10, 4 }, 12));
        assertTrue(s.groupSum5(0, new int[] { 2, 5, 10, 4 }, 19));
        assertTrue(s.groupSum5(0, new int[] { 3, 5, 1 }, 5));
        assertFalse(s.groupSum5(0, new int[] { 3, 5, 1 }, 4));
        assertTrue(s.groupSum5(0, new int[] { 3, 1 }, 4));
        assertFalse(s.groupSum5(0, new int[] { 3, 1 }, 2));
        assertTrue(s.groupSum5(0, new int[] { 1 }, 1));
    }
}

但是,您的签名参数start建议使用递归。在第一步中,您可以从整数数组中删除:

  • 5的所有倍数,并将它们加入到开始
  • 所有1前面都有5的倍数

然后使用start和新的int数组调用方法。

在该方法中,您需要:

  • 测试start是否等于target =&gt;返回true
  • 测试开始是否超过目标=&gt; return false
  • 测试数组是否为空=&gt; return false
  • 使用start + x调用方法,其中x是数组的元素,x已删除数组=&gt;返回所有结果的OR

示例:{2,5,10,4},目标= 19

5:5 + 10 = 15的倍数之和,1之前的5 =&gt;新数组{2,4}

首先致电method(15, {2, 4}, 19)

  • start == target =&gt; NO
  • 开始&gt; target =&gt; NO
  • array empty =&gt; NO
  • r1 =方法(15 + 2,{4},19)和r2 =方法(15 + 4,{2},19)

第二次通话(r1)method(15+2, {4}, 19)

  • start == target =&gt; NO
  • 开始&gt; target =&gt; NO
  • array empty =&gt; NO
  • r11 =方法(15 + 2 + 4,{},19)

第三次通话(r11)method(15+2+4, {}, 19)

  • start == target =&gt; NO
  • 开始&gt; target =&gt;是=&gt;的

第二次通话(r2)method(15+4, {2}, 19)

  • start == target =&gt;是=&gt;的

我们回复了r1 = r11 = falser2 = true =&gt;的第一个电话return false OR true = true,结束

您可以看到Sets.powerSet等同于递归调用r(k)