我在Java中遇到了一个递归面试问题,需要你的帮助。
写一个**Java function**
,使得::给定一个整数数组,是否可以将整数分成两组,这样两组的总和是相同的,具有这些约束:所有的值5的倍数必须在一个组中,并且所有3的倍数(而不是5的倍数)必须在另一个组中。 (不需要循环。)
split53({1,1}) → true
split53({1, 1, 1}) → false
split53({2, 4, 2}) → true
PS:这是hewlett packard的采访问题
答案 0 :(得分:4)
这个问题很容易简化为:给定一组整数numbers
和一个整数target
,是否有可能找到numbers
的子集,其总和等于{{ 1}}?
如果过渡需要澄清,请告诉我。
可以在target
时间内使用DP来解决。我的想法是
O(numbers.size * target)
为numbers.size
时,唯一可达的总和为0
。0
,在这种情况下,总和numbers == {1, 3}
可用。如果我们向{0, 1, 3, 4}
,numbers
添加其他元素会怎样?现在,仍然可以达到所有旧的金额,也可以达到一些新的金额:4
。因此,对于{0 + 4, 1 + 4, 3 + 4, 4 + 4}
,可用的总和为numbers == {1, 3, 4}
。一个工作示例(它不处理负数,但你可以轻松解决这个问题)
{0, 1, 3, 4, 5, 7, 8}
运行它
boolean splittable(int[] numbers, int target) {
boolean[] reached = new boolean[target + 1];
reached[0] = true;
for (int number : numbers) {
for (int sum = target - 1; sum >= 0; --sum) {
if (reached[sum] && sum + number <= target) {
reached[sum + number] = true;
}
}
}
return reached[target];
}
修改强>
我刚刚注意到要求的“递归”部分。好吧,如果这是硬性要求,DP可以用memoization重写为递归。这将保留运行时的复杂性。
编辑2
在团体。在继续算法之前,必须将可被3或5整除的元素分配给各个组。假设所有元素的总和为System.out.println(splittable(new int[]{3, 1, 4}, 7)); // => true
System.out.println(splittable(new int[]{3, 1, 4}, 6)); // => false
,可被3整除的元素之和为s
,可被5整除但不是3的元素之和为s3
。在这种情况下,在您分配了这些“特殊”元素后,您必须将其余部分拆分为一个组中的总和为s5
,另一组s/2 - s3
。
答案 1 :(得分:1)
非常慢,但工作解决方案:
static boolean canSplit(int[] arr, int lvl, int sum1, int sum2) {
if (arr.length == lvl) {
if (sum1 == sum2) {
return true;
} else {
return false;
}
}
if (arr[lvl] % 5 == 0) {
return canSplit(arr, lvl + 1, sum1 + arr[lvl], sum2);
} else if (arr[lvl] % 3 == 0) {
return canSplit(arr, lvl + 1, sum1, sum2 + arr[lvl]);
}
return canSplit(arr, lvl + 1, sum1 + arr[lvl], sum2) ||
canSplit(arr, lvl + 1, sum1, sum2 + arr[lvl]);
}
调用该函数:
canSplit(arr, 0, 0, 0);
答案 2 :(得分:1)
这是真正的递归解决方案。
private boolean split2(int index, int[] nums, int sum1, int sum2) {
if (index >= nums.length) {
return sum1 == sum2;
}
if (split2(index + 1, nums, sum1 + nums[index], sum2)) {
return true;
}
if (split2(index + 1, nums, sum1, sum2 + nums[index])) {
return true;
}
return false;
}
此代码将每个元素放入组中。如果在任何组合中两个组相等,则返回true。没有使用循环,只有一个函数。
最适合所有人
编辑:你的函数需要4个参数作为输入,而问题仅作为数组输入。您必须指定使用您的呼叫split2(0,nums,0,0);
答案 3 :(得分:1)
可能让我被解雇的代码。但是会起作用:D
完全递归,同样致命。
public boolean split53(int[] nums) {
return split_fn(0, nums, 0, 0, false, false);
}
public boolean split_fn(int start, int[] nums, int left, int right, boolean fiveLeft, boolean chosen) {
if (start >= nums.length) {
if (left == right) return true;
return false;
}
if (nums[start] % 5 == 0) {
if (!chosen) {
return split_fn(start + 1, nums, left + nums[start], right, true, true) || split_fn(start + 1, nums, left, right + nums[start], false, true);
} else {
return split_fn(start + 1, nums, left + ((fiveLeft) ? nums[start] : 0), right + ((!fiveLeft) ? nums[start] : 0), fiveLeft, chosen);
}
}
if (nums[start] % 3 == 0 && nums[start] % 5 != 0) {
if (!chosen) {
return split_fn(start + 1, nums, left + nums[start], right, false, true) || split_fn(start + 1, nums, left, right + nums[start], true, true);
} else {
return split_fn(start + 1, nums, left + ((!fiveLeft) ? nums[start] : 0), right + ((fiveLeft) ? nums[start] : 0), fiveLeft, chosen);
}
}
//standard case
return split_fn(start + 1, nums, left + nums[start], right, fiveLeft, chosen) || split_fn(start + 1, nums, left, right + nums[start], fiveLeft, chosen);
}
答案 4 :(得分:0)
我不知道以下解决方案有多快或多慢。但正是它是一种递归回溯解决方案,它没有使用问题中提到的循环。
以下是代码段:
public boolean split53(int[] nums) {
int start = 0, firstPart = 0, secondPart = 0;
if (split(start, nums, firstPart, secondPart)) {
return true;
}
return false;
}
public boolean split(int start, int[] nums, int firstPart, int secondPart) {
if (start >= nums.length) {
return (firstPart == secondPart);
}
if ((start + 1) < nums.length
&& (nums[start] % 3 != 0)
&& (nums[start + 1] % 5 != 0)
&& split(start + 2, nums, firstPart + nums[start], secondPart
+ nums[start + 1])) {
return true;
}
if ((start + 1) < nums.length
&& (nums[start + 1] % 3 != 0)
&& (nums[start] % 5 != 0)
&& split(start + 2, nums, firstPart + nums[start + 1],
secondPart + nums[start])) {
return true;
}
if ((nums[start] % 3 != 0)
&& split(start + 1, nums, firstPart + nums[start], secondPart)) {
return true;
}
if ((nums[start] % 5 != 0)
&& split(start + 1, nums, firstPart, secondPart + nums[start])) {
return true;
}
return false;
}
希望它有所帮助。