我正在为android制作一个数学应用程序。在其中一个字段中,用户可以输入int(无数字且高于0)。这个想法是获得所有可能的和,使得这个int,没有双打(在这种情况下4 + 1 == 1 + 4)。唯一知道的就是这一个。
例如:
假设用户输入4,我希望该应用返回:
显然4 == 4所以也应该添加。关于我应该如何做这个的任何建议?
答案 0 :(得分:17)
这是一个声称可以做到这一点的简单算法
来自:http://introcs.cs.princeton.edu/java/23recursion/Partition.java.html
public class Partition { public static void partition(int n) { partition(n, n, ""); } public static void partition(int n, int max, String prefix) { if (n == 0) { StdOut.println(prefix); return; } for (int i = Math.min(max, n); i >= 1; i--) { partition(n-i, i, prefix + " " + i); } } public static void main(String[] args) { int N = Integer.parseInt(args[0]); partition(N); } }
答案 1 :(得分:6)
有一个简短而优雅的递归解决方案来生成它们,但以下内容可能更容易在现有代码中使用和实现:
import java.util.*;
public class SumIterator implements Iterator<List<Integer>>, Iterable<List<Integer>> {
// keeps track of all sums that have been generated already
private Set<List<Integer>> generated;
// holds all sums that haven't been returned by `next()`
private Stack<List<Integer>> sums;
public SumIterator(int n) {
// first a sanity check...
if(n < 1) {
throw new RuntimeException("'n' must be >= 1");
}
generated = new HashSet<List<Integer>>();
sums = new Stack<List<Integer>>();
// create and add the "last" sum of size `n`: [1, 1, 1, ... , 1]
List<Integer> last = new ArrayList<Integer>();
for(int i = 0; i < n; i++) {
last.add(1);
}
add(last);
// add the first sum of size 1: [n]
add(Arrays.asList(n));
}
private void add(List<Integer> sum) {
if(generated.add(sum)) {
// only push the sum on the stack if it hasn't been generated before
sums.push(sum);
}
}
@Override
public boolean hasNext() {
return !sums.isEmpty();
}
@Override
public Iterator<List<Integer>> iterator() {
return this;
}
@Override
public List<Integer> next() {
List<Integer> sum = sums.pop(); // get the next sum from the stack
for(int i = sum.size() - 1; i >= 0; i--) { // loop from right to left
int n = sum.get(i); // get the i-th number
if(n > 1) { // if the i-th number is more than 1
for(int j = n-1; j > n/2; j--) { // if the i-th number is 10, loop from 9 to 5
List<Integer> copy = new ArrayList<Integer>(sum); // create a copy of the current sum
copy.remove(i); // remove the i-th number
copy.add(i, j); // insert `j` where the i-th number was
copy.add(i + 1, n-j); // insert `n-j` next to `j`
add(copy); // add this new sum to the stack
} //
break; // stop looping any further
}
}
return sum;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
你可以像这样使用它:
int n = 10;
for(List<Integer> sum : new SumIterator(n)) {
System.out.println(n + " = " + sum);
}
会打印:
10 = [10] 10 = [6, 4] 10 = [6, 3, 1] 10 = [6, 2, 1, 1] 10 = [7, 3] 10 = [7, 2, 1] 10 = [8, 2] 10 = [9, 1] 10 = [5, 4, 1] 10 = [5, 3, 1, 1] 10 = [5, 2, 1, 1, 1] 10 = [8, 1, 1] 10 = [7, 1, 1, 1] 10 = [4, 3, 1, 1, 1] 10 = [4, 2, 1, 1, 1, 1] 10 = [6, 1, 1, 1, 1] 10 = [5, 1, 1, 1, 1, 1] 10 = [3, 2, 1, 1, 1, 1, 1] 10 = [4, 1, 1, 1, 1, 1, 1] 10 = [3, 1, 1, 1, 1, 1, 1, 1] 10 = [2, 1, 1, 1, 1, 1, 1, 1, 1] 10 = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
答案 2 :(得分:2)
这是称为partitions的数学概念。一般来说,这很难......但是有一些小技术。从维基页面链接的大量有用的东西。
答案 3 :(得分:1)
对于数字N,您知道最大术语数是N.所以,您将首先列举所有这些可能性。
对于每个可能的术语数量,有许多可能性。这个公式现在没有我,但基本上,这个想法是从(N + 1-i + 1 + ... + 1)开始,其中i是术语数,并且从左到右移动1,第二种情况是是(Ni + 2 + ... + 1) 直到你不能做出另一个动作而不会导致未组合的组合。
(另外,为什么你再次标记这个机器人?)
答案 4 :(得分:1)
这与subset sum problem算法有关。
N = {N * 1,(N-1)+1,(N-2)+ 2,(N-3)+3 .., N-1 = {(N-1),((N-1)-1)+ 2,((N-1)-1)+3 ..}
等。
所以它是一个涉及替换的递归函数;然而,在处理大数字时是否有意义是你必须自己决定的事情。
答案 5 :(得分:0)
所有这些解决方案看起来都有点复杂。这可以通过简单的&#34;递增&#34;来实现。初始化为包含1&#39; s = N的列表。
如果人们不介意从c ++转换,则以下算法会产生所需的输出。
bool next(vector<unsigned>& counts) {
if(counts.size() == 1)
return false;
//increment one before the back
++counts[counts.size() - 2];
//spread the back into all ones
if(counts.back() == 1)
counts.pop_back();
else {
//reset this to 1's
unsigned ones = counts.back() - 1;
counts.pop_back();
counts.resize(counts.size() + ones, 1);
}
return true;
}
void print_list(vector<unsigned>& list) {
cout << "[";
for(unsigned i = 0; i < list.size(); ++i) {
cout << list[i];
if(i < list.size() - 1)
cout << ", ";
}
cout << "]\n";
}
int main() {
unsigned N = 5;
vector<unsigned> counts(N, 1);
do {
print_list(counts);
} while(next(counts));
return 0;
}
对于N = 5,算法给出以下
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3]
[1, 2, 1, 1]
[1, 2, 2]
[1, 3, 1]
[1, 4]
[2, 1, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 3]
[3, 1, 1]
[3, 2]
[4, 1]
[5]