可能重复:
Java : Summation ofmultiples of 5
in a group to a given target
嗨,SO人,
我正在努力解决以下问题,没有正确的方法。
编写一个java函数,使得给定一个int数组,是否可以选择一些int的组,以便该组使用这些附加约束求和给定目标:数组中所有的5的倍数必须被列入该组。如果紧跟在5的倍数之后的值是1,则不能选择它。
函数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编辑:你能否为我提供代码修复,因为我已经尝试过这么多,我不知道如何继续
答案 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
建议使用递归。在第一步中,您可以从整数数组中删除:
然后使用start和新的int数组调用方法。
在该方法中,您需要:
示例:{2,5,10,4},目标= 19
5:5 + 10 = 15的倍数之和,1之前的5 =&gt;新数组{2,4}
首先致电:method(15, {2, 4}, 19)
第二次通话(r1):method(15+2, {4}, 19)
第三次通话(r11):method(15+2+4, {}, 19)
第二次通话(r2):method(15+4, {2}, 19)
我们回复了r1 = r11 = false
和r2 = true
=&gt;的第一个电话return false OR true = true
,结束
您可以看到Sets.powerSet
等同于递归调用r(k)