获取总和与给定数字匹配的连续数字

时间:2019-02-03 22:12:58

标签: java algorithm

我正在通过一个简单的程序,该程序接受一个数字并查找与给定数字匹配的连续数字的出现次数。

例如:

if input is 15, then the consecutive numbers that sum upto 15 are:

1,2,3,4,5
4,5,6
7,8

So the answer is 3 as we have 3 possibilities here.

当我寻找解决方案时,我发现以下答案:

static long process(long input) {
    long count = 0;
    for (long j = 2; j < input/ 2; j++) {
        long temp = (j * (j + 1)) / 2;
        if (temp > input) {
            break;
        }

        if ((input- temp) % j == 0) {
            count++;
        }
    }
    return count;
}

我无法理解这是如何解决要求的,因为该程序使用的是一些我无法正确理解的公式,以下是我的疑问:

  • for循环从2开始,这是什么原因?
  • long temp = (j * (j + 1)) / 2;此逻辑表示什么?这对解决问题有什么帮助?
  • if ((num - temp) % j == 0)这也表明什么?

请帮助我理解此解决方案。

6 个答案:

答案 0 :(得分:15)

我将尽力解释这一点。

如果输入为15,则总计为15的连续数字为:

{1,2,3,4,5} -> 5 numbers
{4,5,6} -> 3 numbers
{7,8} -> 2 numbers

在最坏的情况下,该值必须小于1st自然数之和=(n *(n + 1)/ 2。

因此,对于数字15,永远不会有6个连续数字的总和,最多等于15,即第一个6个数字的总和= 21,该数字大于15。

计算温度:这是(j *(j + 1))/ 2。

举个例子。令输入=15。令j = 2。

temp = 2 * 3/2 = 3; #含义1 + 2 = 3

对于2对数,将2个项设为'a + 1'和'a + 2'。(因为我们知道数字是连续的。)

现在,根据问题,总和必须等于数字。

这意味着2a+3 =15;

如果(15-3)被2整除,则可以找到'a'。 a=6-> a + 1 = 7和a + 2 = 8

同样,让a+1a+2a+3            a + 1 + a + 2 + a + 3 = 15            3a + 6 = 15            (15-6)必须被3整除。

最后,对于5个连续的数字a+1a+2a+3a+4a+5,我们有            5a + 15 = 15;            (15-15)必须被5整除。

因此,当输入为15时,j = 2,3和5的计数将改变

如果循环从1开始,那么我们也将计算1个数字集-> {15},这是不需要的

总结:

1)for循环从2开始,这是什么原因?

  

我们不担心这里设置的1个数字。

2)long temp = (j * (j + 1)) / 2;此逻辑表示什么?这对解决问题有什么帮助?

  

这是因为我拥有的第n个自然数属性之和   通过将a+1a+2设为2个连续   数字。

3)if ((num - temp) % j == 0)这还表明什么?

  

这表示从第一和中减去输入的逻辑   j个自然数必须可被j整除。

答案 1 :(得分:4)

我们正在寻找可累加给定数字的连续数字。 很明显,最多可以有一个给定长度的序列,所以基本上我们正在寻找那些值可能是这样一个序列的长度。 变量“ j”是测试长度。它从2开始,因为序列必须至少2个长。 变量“ temp”是从1到“ j”的算术级数之和。

如果有适当的级数,则使X为第一个元素。在这种情况下,“输入” = j *(X-1)+温度。 (因此,如果输入temp>,那么我们就完成了)

在最后一行,它检查方程是否存在整数解。如果存在,则增加计数器,因为存在一个带有j元素的序列,这是一个解决方案。

实际上,解决方案是错误的,因为如果输入= 3,则找不到解决方案。(它将立即终止。)循环应为:

for(long j=2;;j++)

其他条件反过来会更快终止循环。

答案 2 :(得分:3)

我们需要找到所有an,对于给定的b,以下条件成立:

a + (a + 1) + (a + 2) + ... (a + (n - 1)) = b

左侧是算术级数,可以写为:

(a + (n - 1) / 2) * n = b         (*)

要找到n的极限值,我们知道a > 0,所以:

(1 + (n - 1) / 2) * n = n(n + 1) / 2 <= b
n(n + 1) <= 2b
n^2 + n + 1/4 <= 2b + 1/4
(n + 1/2)^2 <= 2b + 1/4
n <= sqrt(2b + 1/4) - 1/2

现在我们可以重写(*)以获得a的公式:

a = b / n - (n - 1) / 2

b = 15且n = 3的示例:

15 / 3 - (3 - 1) / 2 = 4 => 4 + 5 + 6 = 15

现在是代码:

double b = 15;
for (double n = 2; n <= Math.ceil(Math.sqrt(2 * b + .25) - .5); n++) {
    double candidate = b / n - (n - 1) / 2;
    if (candidate == (int) candidate) {
        System.out.println("" + candidate + IntStream.range(1, (int) n).mapToObj(i -> " + " + (candidate + i)).reduce((s1, s2) -> s1 + s2).get() + " = " + b);
    }
}

结果是:

7.0 + 8.0 = 15.0
4.0 + 5.0 + 6.0 = 15.0
1.0 + 2.0 + 3.0 + 4.0 + 5.0 = 15.0

答案 3 :(得分:2)

NB:循环从2开始,因为=>(1 *(1 + 1))/ 2 == 1,这没有意义,即,它对进度没有影响;

let,k = 21;

  1. so循环最多迭代(k / 2)=> 10次;

  2. temp =(j *(j + 1))/ 2 =>,当j = 2时为3,当j = 3时为6,依此类推(计算出N个自然数之和)

  3. temp> k =>将中断循环,因为当我们得到的'sum'大于'K'时我们不需要重复循环

  4. (((k-temp)%j)== 0 =>当从第j个自然数之和减去的输入可被j整除时,这基本上是正确的,如果是,则递增计数以获得等式的总数!

答案 4 :(得分:2)

public static long process(long input) {
    long count = 0, rest_of_sum;
    for (long length = 2; length < input / 2; length++) {
        long partial_sum = (length * (length + 1)) / 2;
        if (partial_sum > input) {
            break;
        }
        rest_of_sum = input - partial_sum
        if (rest_of_sum % length == 0)
            count++;
    }
    return count;
}

输入-给定的输入数字是15

length-连续的数字长度,最大输入/ 2时至少为2

partial_sum =从1到长度的数字总和(假设a等于a的a *(a + 1)/ 2到一个数字)

rest_of_sum =表示输入中剩余的余额

如果余数是长度的倍数,则意味着我们可以在部分序列中加上(rest_of_sum / length)

让呼叫(rest_of_sum / length)为k

这仅意味着我们可以在此处构建一个序列,该序列求和为我们的输入数字 以(k + 1),(k + 2),...(k + length)开头

这可以立即验证 (k + 1)+(k + 2)+ ...(k +长度)

我们可以将其减少为k + k + k + ..长度乘以+(1 + 2 + 3..length)

可以减少为=> k *长度+ part_sum

可以减少为=>输入(因为我们现在验证了这一点)

所以这里的想法是每次我们找到一个满足这种情况的长度时都增加计数

答案 5 :(得分:2)

  • 如果进行此调整,则可能会修复代码。我还没有对其进行广泛的测试。这很奇怪,但是它会使代码经过额外的迭代,以解决早期的错误计算。甚至1/20000都可以!如果用四舍五入的浮点数完成此操作,并向其添加1,我认为也可以这样做:

    for (long j = 2; j < input+ (1/2); j++) {

本质上,您只需要知道一个公式:

  • 数字m..n(或m到n)(以及代码中n> m)的总和
  • 这是((n-m+1)*(n+m))/2

正如我已经评论的那样,原始问题中的代码已被窃听。

  • 请参阅here

    • 尝试进给它3.连续数字1,2出现1次。产生0。
    • 或5。有2,3-应该也产生1-给出0。
    • 或6。这也有1,2,3-应该也产生1-给出0。
    • 在您的原始代码中,temp(j * (j + 1)) / 2代表数字1到j的总和。

1 2 3 4 5
5 4 3 2 1
=======
6 6 6 6 6 =>(5 x 6)/ 2 => 30/2 => 15

如下面的代码所示,请使用System.out.println();发出调试信息。

  • 如果要完善它,请确保m和n的上限分别为i和i + 1的一半,如果为奇数,则四舍五入。例如:(i = 15-> m = 7&n = 8)

代码:

class Playground {
    private static class CountRes {
        String ranges;
        long count;
        CountRes(String ranges, long count) {
            this.ranges = ranges;
            this.count = count;
        }
        String getRanges() {
            return this.ranges;
        }
        long getCount() {
            return this.count;
        }
    }
    static long sumMtoN(long m, long n) {
        return ((n-m+1)* (n+m))/2;
    }
    static Playground.CountRes countConsecutiveSums(long i, boolean d) {
        long count = 0;
        StringBuilder res = new StringBuilder("[");
        for (long m = 1; m< 10; m++) {
            for (long n = m+1; n<=10; n++) {
                long r = Playground.sumMtoN(m,n);
                if (d) {
                        System.out.println(String.format("%d..%d %d",m,n, r));  
                } 
                if (i == r) {
                    count++;
                    StringBuilder s = new StringBuilder(String.format("[%d..%d], ",m,n));
                    res.append(s);
                }
            }
        }
        if (res.length() > 2) {
            res = new StringBuilder(res.substring(0,res.length()-2));
        }
        res.append("]");
        return new CountRes(res.toString(), count);
    }
    public static void main(String[ ] args) {
        Playground.CountRes o = countConsecutiveSums(3, true);
        for (long i=3; i<=15; i++) {
            o = Playground.countConsecutiveSums(i,false);
            System.out.println(String.format("i: %d Count: %d Instances: %s", i, o.getCount(), o.getRanges()));
        }
    }
}

您可以尝试运行here

输出:

1..2 3
1..3 6
1..4 10
1..5 15
1..6 21
1..7 28
1..8 36
1..9 45
1..10 55
2..3 5
2..4 9
2..5 14
2..6 20
2..7 27
2..8 35
2..9 44
2..10 54
3..4 7
3..5 12
3..6 18
3..7 25
3..8 33
3..9 42
3..10 52
4..5 9
4..6 15
4..7 22
4..8 30
4..9 39
4..10 49
5..6 11
5..7 18
5..8 26
5..9 35
5..10 45
6..7 13
6..8 21
6..9 30
6..10 40
7..8 15
7..9 24
7..10 34
8..9 17
8..10 27
9..10 19
i: 3 Count: 1 Instances: [[1..2]]
i: 4 Count: 0 Instances: []
i: 5 Count: 1 Instances: [[2..3]]
i: 6 Count: 1 Instances: [[1..3]]
i: 7 Count: 1 Instances: [[3..4]]
i: 8 Count: 0 Instances: []
i: 9 Count: 2 Instances: [[2..4], [4..5]]
i: 10 Count: 1 Instances: [[1..4]]
i: 11 Count: 1 Instances: [[5..6]]
i: 12 Count: 1 Instances: [[3..5]]
i: 13 Count: 1 Instances: [[6..7]]
i: 14 Count: 1 Instances: [[2..5]]
i: 15 Count: 3 Instances: [[1..5], [4..6], [7..8]]