求和替n的连续正整数序列

求和为n的连续正整数序列

题目:输入一个正数n,输出所有和为n连续正整数序列。

 

例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。

 

 

解法1

 

因为整数序列是有序的,可以设立两个游标begin和end,通过判区间[begin,end]的和是否为N来得到这个序列。如果区间和大于n,begin往前移动,如果小于n,end往前移动,等于就输出这个区间。时间复杂度是0(n)。

 

public void find(int n) {
    if (n > 0 && ((n & n-1) == 0)) {
        System.out.println("no way");
	return;
    }
		
    int begin = 1; 
    int end = 2;
    int sum = begin + end;
		
    while (begin < end && begin < (n+1)/2) {
        if (sum < n) {
	    end++;
	    sum += end;
	} else if (sum > n) {
	    sum -= begin;
	    begin++;
	} else {
	    System.out.println(n + " can be divided from " + begin + " to " + end);
	    sum -= begin;
	    begin++;
	}
    }
}

 

 

解法2

 

假设自然数n可以拆分成:m, m+1, …, m+k-1 (m >= 1, k >= 2),则 n = (m + m+k-1)*k/2 即 2*n = (2*m+k-1)*k。

由于(2*m+k-1)与k的奇偶性是相反的,因此,可以先将n的所有质因子2提取出来,得到:2 * n = 2^t * a * b,由于(2*m+k-1)与k的奇偶性相反,且(2*m+k-1) > k,当确定了a,b时,可得到2*n的两组拆分(2^t * a, b) 和 (a, 2^t * b)(当a等于b时,这两组拆分是一样的),对每组拆分,k是较小的数。

 

public void find2(int n) {
    if (n <= 0)
        return;
		
    int count = 1;
    int i;
    int j;
    while(n % 2 == 0) {
        n /= 2;
	count++;
    }
		
    for (i = 1; ; i += 2) {
        if (n % i != 0)
            continue;
        j = n / i;
        if (i > j)
            break;
			
        if ((i << count) < j)
            print(j, i << count);
        else 
            print(i << count, j);
			
        if (i == j) break;
        if (i == 1) continue;
			
        if ((j << count) < i)
            print(i, j << count);
        else
            print(j << count, i);
    }
}
	
private void print(int i, int j) {
    int k = j;
    int m = (i-j+1) / 2;
    System.out.println("from " + m + " to " + (m+k-1));
}