文件组合.待传输文件被切分成多个部分,按照原排列顺序,每部分文件编号均为一个 正整数(至少含有两个文件)。传输要求为:连续文件编号总和为接收方指定数字 target 的所有文件。请返回所有符合该要求的文件传输组合列表。
注意,返回时需遵循以下规则:
每种组合按照文件编号 升序 排列;
不同组合按照第一个文件编号 升序 排列。
示例 1:
输入:target = 12
输出:[[3, 4, 5]]
解释:在上述示例中,存在一个连续正整数序列的和为 12,为 [3, 4, 5]。
示例 2:
输入:target = 18
输出:[[3,4,5,6],[5,6,7]]
解释:在上述示例中,存在两个连续正整数序列的和分别为 18,分别为 [3, 4, 5, 6] 和 [5, 6, 7]。
(-1 + 根号xx) / 2
就可以了 public int[][] fileCombination(int target) {
int i = 1;
double j = 2.0;
List<int[]> list = new ArrayList<>();
while(i < j){
j = (-1 + Math.sqrt(1 + 4 * (2 * target + (long) i * i - i))) / 2;
// j 为整数
if (j == (int)j){
int[] ans = new int[(int)j-i+1];
for(int k=i;k<=j;k++){
ans[k-i] = k;
}
list.add(ans);
}
i++;
}
return list.toArray(new int[0][]);
}
i == j
,此时退出循环即可,而比如 i~j 为 4~5 时,此时是一种可行组合, s == target
,其实缩到这种只有两个数的地步,不可能再有其他组合了,虽然可以选择扩充和缩小,不过选择缩小就能直接结束循环了,扩充还得多判断几轮无意义的循环,所以我们在 s == target
时选择缩小 public int[][] fileCombination(int target) {
int i = 1,j = 2, s = 3;
List<int[]> list = new ArrayList<>();
while(i < j){
if (s == target){
int[] ans = new int[(int)j-i+1];
for(int k=i;k<=j;k++){
ans[k-i] = k;
}
list.add(ans);
}
if(s >= target){
// 比如原本 i,j 为 2,4,s = 2+3+4 = 9,此时减掉 i 就相当于 s 成了 3+4 = 7
s-=i;
i++;
}else{
j++;
s+=j;
}
}
return list.toArray(new int[0][]);
}