Java 将整数表示为连续正整数之和

Java 将整数表示为连续正整数之和,java,math,Java,Math,我正在编写代码,用于计算一个整数可以表示为连续整数之和的方式的数量。比如说 15=(7+8),(1+2+3+4+5),(4+5+6)。所以15条路的数量等于3条。 现在输入大小可以递归函数不适用于像您的案例这样的大输入大小 java调用堆栈的最大深度约为8900个调用,有时仅在7700个调用堆栈溢出后发生,因此它实际上取决于程序输入大小 试试这个算法,我认为它对你的问题有效: 它可以正常工作,直到10^9,然后需要更多的时间来完成程序的运行 long sum = 0; int c

我正在编写代码,用于计算一个整数可以表示为连续整数之和的方式的数量。比如说

15=(7+8),(1+2+3+4+5),(4+5+6)。所以15条路的数量等于3条。
现在输入大小可以递归函数不适用于像您的案例这样的大输入大小

java调用堆栈的最大深度约为8900个调用,有时仅在7700个调用堆栈溢出后发生,因此它实际上取决于程序输入大小

试试这个算法,我认为它对你的问题有效:

它可以正常工作,直到
10^9
,然后需要更多的时间来完成程序的运行

    long sum = 0;
    int count = 0;
    long size;
    Scanner in = new Scanner(System.in);
    System.out.print("Enter a number <=10^12: ");
    long n = in.nextLong();
    if(n % 2 != 0){
        size = n / 2 + 1;
    }
    else{
        size = n / 2;
    }
    for(int i = 1; i <= size; i++){           
       for(int j = i; j <= size; j++){
            sum = sum + j;
            if(sum == n){
                sum = 0;
                count++;
                break;
            }
            else if(sum > n){
                 sum = 0;
                 break;
            }
        }
    }
    System.out.println(count);
长和=0;
整数计数=0;
长尺寸;
扫描仪输入=新扫描仪(系统输入);

System.out.print(“输入一个数字使用一些数学:如果差为1的算术级数以
a0
开始,并包含
n
项,则其总和为

 S = (2 * a0 + (n-1))/2 * n = a0 * n + n * (n-1) / 2
请注意,第二个和作为二次函数上升。因此,我们不必检查范围
S/2
中的所有
a0
,而可以检查范围较小的所有
n

nmax = Ceil((-1 + Sqrt(1 + 8 * S)) / 2)
(我使用了更高的近似值)

只需测试下一个表达式是否给出整数正结果

 a0 = (S - n * (n - 1) / 2) / n

正如@MBo所指出的,如果一个数字
S
可以被划分成
n
连续的部分,那么
S-T(n)
必须可以被
n
整除,其中
T(n)
是第n个,因此你可以在
O(sqrt(S))
时间内计算分区的数量

// number of integer partitions into (at least 2) consecutive parts
static int numberOfTrapezoidalPartitions(final long sum) {
    assert sum > 0: sum;

    int n = 2;
    int numberOfPartitions = 0;
    long triangularNumber = n * (n + 1) / 2;

    while (sum - triangularNumber >= 0) {
        long difference = sum - triangularNumber;

        if (difference == 0 || difference % n == 0)
            numberOfPartitions++;

        n++;
        triangularNumber += n;
    }

    return numberOfPartitions;
}
再多学一点数学,就会得到一种更简单的方法。比如:

正数的礼貌性定义为它可以表示为连续整数之和的方式的数量。对于每个x,x的礼貌性等于x的大于1的奇数因子的数量

另见:OEIS

因此,一个有很大优化空间的简单解决方案是:

// number of odd divisors greater than one
static int politeness(long x) {
    assert x > 0: x;

    int p = 0;

    for (int d = 3; d <= x; d += 2)
        if (x % d == 0)
            p++;

    return p;
}
//大于1的奇数除数的数目
静态int礼貌(长x){
断言x>0:x;
int p=0;

对于(int d=3;d有一个非常好的证明,答案可以通过求解唯一的奇数因子()。基本上,对于目标值的每个奇数因子,存在该因子的奇数序列乘以其平均值以产生目标值,或存在等于该因子的奇数平均值,该因子可乘以双倍偶数序列以达到目标值

public static int countUniqueOddFactors(long n) {
    if (n==1) return 1;
    Map<Long, Integer> countFactors=new HashMap<>();
    while ((n&1)==0) n>>>=1; // Eliminate even factors
    long divisor=3;
    long max=(long) Math.sqrt(n);
    while (divisor <= max) {
        if (n % divisor==0) {
            if (countFactors.containsKey(divisor)) {
                countFactors.put(divisor, countFactors.get(divisor)+1);
            } else {
                countFactors.put(divisor, 1);
            }
            n /= divisor;
        } else {
            divisor+=2;
        }
    }
    int factors=1;
    for (Integer factorCt : countFactors.values()) {
        factors*=(factorCt+1);
    }
    return factors;
}
公共静态int countUniqueOddFactors(长n){
如果(n==1)返回1;
Map countFactors=new HashMap();
而((n&1)==0)n>>>=1;//消除偶数因子
长除数=3;
long max=(long)Math.sqrt(n);

虽然(除数为什么不计算
-3+-2+-1+0+1+2+3+4+5+6
?可能是整数溢出,也可能是由于递归调用过多而导致的溢出。如果您从未听说过动态编程,现在是学习的好时机。有一个数学公式可以计算第一个
n
正整数的和,如下所示:
n*(n+1)/2
@DawoodibnKareem Title表示连续的正整数。@Bubletan Ooh抱歉。我阅读了问题的文本而不是标题。我也为输入“10^9”运行了您的算法,并且我没有使用任何计时器,但这两种方法所用的时间几乎相同。@colt您将在其上进行测试。您应该尝试实现一个解决方案如果您希望提高效率,请根据@plasmacel的评论。@Colt。很抱歉,我已更新了代码。我正在对其进行审阅。运行时错误已得到解决,但所花费的时间几乎与您的相同。@Colt。顺便说一句,您对java调用堆栈大小的看法是正确的。:)
// number of odd divisors greater than one
static int politeness(long x) {
    assert x > 0: x;

    int p = 0;

    for (int d = 3; d <= x; d += 2)
        if (x % d == 0)
            p++;

    return p;
}
public static int countUniqueOddFactors(long n) {
    if (n==1) return 1;
    Map<Long, Integer> countFactors=new HashMap<>();
    while ((n&1)==0) n>>>=1; // Eliminate even factors
    long divisor=3;
    long max=(long) Math.sqrt(n);
    while (divisor <= max) {
        if (n % divisor==0) {
            if (countFactors.containsKey(divisor)) {
                countFactors.put(divisor, countFactors.get(divisor)+1);
            } else {
                countFactors.put(divisor, 1);
            }
            n /= divisor;
        } else {
            divisor+=2;
        }
    }
    int factors=1;
    for (Integer factorCt : countFactors.values()) {
        factors*=(factorCt+1);
    }
    return factors;
}