我想创建一个程序,可以生成一系列连续的数字,使它们相加等于给定的数值。例如,如果输入的数值为15,应该得到以下结果 -
7, 8
4, 5, 6
1, 2, 3, 4, 5
有一些公式/算法/循环可以完成某些任务,例如生成数组或打印它。这可能看起来像是一个数学问题或愚蠢的问题,但我实际上无法想象如何在Java中以编程方式完成。
请尝试给出确切的代码来完成这件事。
我想创建一个程序,可以生成一系列连续的数字,使它们相加等于给定的数值。例如,如果输入的数值为15,应该得到以下结果 -
7, 8
4, 5, 6
1, 2, 3, 4, 5
有一些公式/算法/循环可以完成某些任务,例如生成数组或打印它。这可能看起来像是一个数学问题或愚蠢的问题,但我实际上无法想象如何在Java中以编程方式完成。
请尝试给出确切的代码来完成这件事。
假设你的输入为N,你知道每组k个连续数字将围绕N/k居中。如果N/k以0.5结尾,则偶数k存在解决方案,如果N/k是整数,则奇数k存在解决方案。如果有解决方案,则解决方案是围绕N/k居中的k个整数。
k=1: 15/1 = 15, so 15 (trivial; may want to omit)
k=2: 15/2 = 7.5, so 7,8
k=3: 15/3 = 5, so 4,5,6
k=4: 15/4 = 3.75, so no solution
k=5: 15/5 = 3, so 1,2,3,4,5
k=6: 15/6 = 2.5, so 0,1,2,3,4,5
etc...
k=15: 15/15 = 1, so -6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8
您可以轻松修改此代码以限制为正数或非负数解。
从数字a
开始且包含n
个连续数字的序列总和:
S=(n/2)*[2*a+(n-1)*d]
对于连续的数字,步骤d
为1。
S=(n/2)*[2*a+(n-1)]
这里我们可以转到@MBo的帖子。
P=2*S=n*[2*a+(n-1)]
我们可以迭代所有可能的连续数字n
的计数,并检查结果的a
是否有效(即a
是整数)。
让我们分解出a
。
假设P = n * q => q=2*a+(n-1)=>2*a=q-n+1=>a=(q-n+1)/2
1)我们提到可以迭代所有可能的连续数字n
的计数,但是给定p=n*q
,可以安全地说n
需要是p
的除数。
p % n == 0
nMax = (int)Math.sqrt(p)
2)a
是整数且a=(q-n+1)/2
=>(q-n+1)
是偶数=>q-n
是奇数。
((q - n) & 1) == 1
import java.util.*;
import java.lang.Math;
import java.util.stream.IntStream;
import static java.util.stream.Collectors.toList;
public class Progressions
{
public static void main(String[] args)
{
List<List<Integer>> list = Calculate(15);
System.out.print(list);
}
public static List<List<Integer>> Calculate(int s)
{
List<List<Integer>> list = new ArrayList<>();
int p = 2*s;
int nMax = (int)Math.sqrt(p);
for (int n=2; n<=nMax; n++) {
if(p % n == 0) {
int q = p / n;
if(((q - n) & 1) == 1) {
int a = (q - n + 1) / 2;
list.add(range(a,n));
}
}
}
return list;
}
public static List<Integer> range(int a, int n) {
return IntStream.range(a, a+n)
.boxed()
.collect(toList());
}
}
a
开始并有 n
个成员,它们的和为
S = n * (2 * b + (n-1)) / 2
so
P = 2 * S = n * (2 * b + (n-1))
对于给定的输入S,我们可以将2*S
分解为所有可能的整数因子对P = n * q
,其中n<=q
,然后得到起始数字
a = (q - n + 1) / 2
30 = 2 * 15 => n = 2, a = 7 => (7,8)
30 = 3 * 10 => n = 3, a = 4 => (4,5,6)
30 = 5 * 6 => n = 5, a = 1 => (1,2,3,4,5)
简单的Python示例:
import math
def getseqs(s):
print(s)
p = 2 * s
for n in range(2, math.ceil(math.sqrt(p))):
if (p % n == 0):
q = p // n
if (((q - n) & 1) == 1): #compare parity
a = (q - n + 1) // 2
seq = list(range(a, a+n))
print(seq, sum(seq))
getseqs(17)
getseqs(15)
getseqs(72)
17
[8, 9] 17
15
[7, 8] 15
[4, 5, 6] 15
[1, 2, 3, 4, 5] 15
72
[23, 24, 25] 72
[4, 5, 6, 7, 8, 9, 10, 11, 12] 72
假设 int input
是您的输入数字(例如15
),List<int[]> list
是结果连续数字的存储,以下是:
List<int[]> list = new ArrayList<>();
int lower = 1; // Start searching from 1
int upper = (int) Math.floor(input + 1 / 2); // Up to the half of input (8+9 > 15)
while (lower < upper) { // Iterate between the bounds
int sum = 0;
for (int i = lower; i <= upper; i++) { // Iterate and sum the numbers
sum += i;
if (sum == input) { // If it matches the input
// Add the range to the List
// You have to loop them by one and add to the
// List before version Java-8
list.add(IntStream
.range(lower, i + 1)
.toArray());
break; // Found, no reason to continue
}
if (sum > input) { // Terminate the loop if the sum overlaps
break;
}
lower++; // Increment and try the sums from
// a higher starting number
sum = 0; // Reset the sum
}
输入 15
的结果是这些数组的 List
:
[1, 2, 3, 4, 5]
[4, 5, 6]
[7, 8]
sum += i
。由于它是一系列连续的数字,因此它形成了一个等差数列。因此,我们只需要找出在该等差数列中有多少个项以获得总和。因此,在 lower
和 upper
之间进行二分查找即可。 - nice_dev这里有一个建议:
对于输入的数字N:
对于输入的15,以下是区间如何随时间变化:
Interval Sum
[1] 1
[1,2] 3
[1,2,3] 6
[1,2,3,4] 10
[1,2,3,4,5] 15 -> output [1,2,3,4,5]
[2,3,4,5] 14
[2,3,4,5,6] 20
[3,4,5,6] 18
[4,5,6] 15 -> output [4,5,6]
[5,6] 11
[5,6,7] 18
[6,7] 13
[6,7,8] 21
[7,8] 15 -> output [7,8]
[8] 8
[8,9] 17
[9] 9
[9,10] 19
[10]
...
[15] 15 -> output 15
当连续两个数字的和大于目标值时,您可以进行一些优化,此时可以终止循环,并仅添加最终集合(其中仅包含目标值)。
我正在编写 @Dave 解决方案的实现。 在询问之前尝试解决问题……这就是我们学习的方式。(仅当我们无法解决时才会询问)
Scanner s = new Scanner(System.in);
int inputNumber = s.nextInt();
int k = 1;
while(inputNumber/k >= .5){
Float sequenceMid = (float) inputNumber/k;
if( k%2 == 0 && (sequenceMid *2 == Math.ceil(sequenceMid *2)) ){
for(int i = ((int)Math.floor(sequenceMid) - (k/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}else if( (k%2 == 1) && (sequenceMid == Math.ceil(sequenceMid))){
for(int i = (Math.round(sequenceMid) - ((k-1)/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}
k++;
}
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
differences:
15 - 0 = 15 -> [1, 2, 3, 4]
21 - 6 = 15 -> [4, 5, 6]
36 - 21 = 15 -> [7, 8]
15-0
的减法运算。包含在解决方案中的数字将被左侧排除,右侧包括。这意味着将左索引加1(索引从0开始)。希望模式非常清晰。<= K
时,我们希望增加窗口的右侧,扩大窗口和差异。number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (] -> 0 - 0 = 0
2nd: (---] -> 3 - 0 = 3
3rd: (------] -> 6 - 0 = 0
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (-----------------] -> 15 - 0 = 15 <print>
2nd: (---------------------] -> 21 - 0 = 21
3rd: (-----------------] -> 21 - 1 = 20
< K/2
,因为K//2 + (K//2 + 1) >= K
(其中等式可能是由于整数除法表示为//
)。因此,当左侧达到K//2
时(由于左侧是排除的),我们可以提前停止循环。public static int cumsum(int index) {
return index * (index + 1) / 2;
}
public static String printRange(int left, int right) {
StringBuilder buffer = new StringBuilder();
buffer.append('[');
for (int i=left+1;i<=right;i++) {
buffer.append(i);
buffer.append(',');
}
buffer.deleteCharAt(buffer.length()-1);
buffer.append(']');
return buffer.toString();
}
public static void main(String[] args) {
int K = 15;
int K_ov_2 = K/2;
int left_index = 0;
int right_index = 0;
int diff;
while (left_index < K_ov_2) {
diff = cumsum(right_index) - cumsum(left_index);
System.out.println("diff = " + diff + ", left = " + left_index + ", right = " + right_index);
if (diff == K) {
System.out.println(printRange(left_index,right_index));
}
if (diff <= K) {
right_index++;
} else {
left_index++;
}
}
}
diff = 0, left = 0, right = 0
diff = 1, left = 0, right = 1
diff = 3, left = 0, right = 2
diff = 6, left = 0, right = 3
diff = 10, left = 0, right = 4
diff = 15, left = 0, right = 5
[1,2,3,4,5]
diff = 21, left = 0, right = 6
diff = 20, left = 1, right = 6
diff = 18, left = 2, right = 6
diff = 15, left = 3, right = 6
[4,5,6]
diff = 22, left = 3, right = 7
diff = 18, left = 4, right = 7
diff = 13, left = 5, right = 7
diff = 21, left = 5, right = 8
diff = 15, left = 6, right = 8
[7,8]
diff = 24, left = 6, right = 9