代码之家  ›  专栏  ›  技术社区  ›  learner

求和与给定数匹配的连续数

  •  11
  • learner  · 技术社区  · 7 年前

    例如:

    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 回复  |  直到 6 年前
        1
  •  17
  •   Phenomenal One    7 年前

    我将尽可能简单地解释这一点。

    如果输入为15,则累加到15的连续数字为:

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

    在最坏的情况下,这必须小于前n个自然数的和=(n*(n+1)/2。

    所以对于一个数字15,不可能有6个连续的数字的组合加起来等于15,因为前6个数字的和等于21,大于15。

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

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

    温度=2*3/2=3;#表示1+2=3

    对于两个数字对,让这两个项分别为“a+1”和“a+2”。(因为我们知道数字是连续的。)

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

    2a+3 =15;

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

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

    a+1级 a+2级 a+3级 a+4 a+5 ,我们有 (15-15)必须能被5整除。

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

    总结一下:

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

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

    long temp = (j * (j + 1)) / 2;

    这是因为第一个n个自然数的和的性质 通过采取行动来解释上述情况 连续两次 数字。

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

    这表示从1的和中减去输入的逻辑 j .

        2
  •  4
  •   Selindek    7 年前

    很明显,一个给定长度的数列最多只能有一个,所以我们基本上是在寻找这些值,这些值可以是这样一个数列的长度。 变量“j”是测试长度。它从2开始,因为序列必须至少有2长。

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

    在最后一行,它检查方程是否有整数解。如果有,那么增加计数器,因为有一个带有j元素的级数是一个解。

    实际上这个解是错误的,因为如果input=3它就找不到解。(它将立即终止。)循环应为:

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

        3
  •  4
  •   Andronicus    7 年前

    我们需要找到所有的 a s和 n s、 那是给你的 b 以下是正确的:

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

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

    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 = 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
    
        4
  •  2
  •   Papai from BEKOAIL    7 年前

    注意:循环从2开始,因为=>(1*(1+1))/2==1,这没有意义,也就是说,它不影响进度;

    设,k=21;

    1. 所以循环将迭代到(k/2)=>10次;

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

    3. temp>k=>将中断循环,因为当得到大于“k”的“sum”时,我们不需要迭代循环

    4. ((k-temp)%j)==0=>当从第一个j个自然数的和中减去的输入可以被j整除时,这基本上是正确的,如果是这样,则增加计数以得到此类方程的总数!

        5
  •  2
  •   MissingNumber    7 年前
    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

    partial_sum=从1到长度的数字之和(对于1到a的数字是a*(a+1)/2)假设这是一个部分序列

    如果sum的剩余部分是长度的倍数,则意味着我们可以将(sum的剩余部分/长度)加到部分序列中

    让我们调用(sum/length的剩余部分)作为k

    这只意味着我们可以在这里建立一个序列,求和到我们的输入数

    现在可以验证了 (k+1)+(k+2)+。。。(k+长度)

    我们可以把它简化为k+k+k+。。长度乘以+(1+2+3..长度)

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

        6
  •  2
  •   JGFMK    7 年前
    • 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的和。



    =======

    如我在下面的代码中所示-使用 System.out.println(); 输出调试信息。

    代码:

    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]]