1. 能否拆分
结论:除了 $2^n$ 之外,其他自然数均可以拆分
所有奇数都能写成 $2i + 1$ 的形式,因此至少可以拆成 $(i, i+1)$,所以奇数可以拆分
偶数里边,奇数倍数的可以拆分,其他的(也就是 $2^n$) 无法拆分
1 boolean ifConsistOfConsecutiveInteger(intn) {2 if (n <= 0) {3 return false;4 }5 boolean result = false;6 if ((n & (n - 1)) != 0) {7 result = true;8 }9
10 returnresult;11 }
2. 输出可以拆分成的各种形式
2.1 数学方法
以 $a$ 表示连续自然数中的第一个,则
$n = a + (a + 1) + (a + 2) + ... + (a + k - 1)$
整理一下
$2n = 2ka + k^2 - k$
整理成关于 $k$ 的一元二次方程
$k^2 + (2a - 1)k - 2n = 0$
解这个方程,$\Delta = (2a -1)^2 + 8n$
$k = (1 - 2a + \sqrt{\Delta})/2$
然后,考虑三个问题
1) 连续自然数序列里的第一个数必然小于等于 $n/2$,如果大于的话,再和后面的数相加肯定大于 $n$
2) $\Delta$ 开方之后必须是整数
3) $1 - 2a + \sqrt{\Delta}$ 必须是偶数,否则除以 $2$ 会出现小数
代码如下($n$ 太大时不适用,会有溢出):
1 void printExpression(intn) {2 longfirst;3 longincr;4 for (int i = 1; i <= n / 2; i++) {5 first =i;6 long delta = (2 * first - 1) * (2 * first - 1) + 8 *n;7 long sqrt_delta = (int) Math.sqrt(delta);8
9 if (sqrt_delta * sqrt_delta == delta && sqrt_delta % 2 != 0) {10 incr = (sqrt_delta - (2 * first - 1)) / 2;11 System.out.println("num of consecutive integer is " +incr);12 for (int j = 1; j <= incr; j++) {13 System.out.print(first + j - 1 + " ");14 }15 System.out.println();16 }17 }18 }
2.2 双指针解法(参考剑指 Offer)
1 void printExpression2(intn) {2 int small = 1;3 int big = 2;4 int sum = small +big;5 while (small <= n / 2) {6 if (sum ==n) {7 for (int i = small; i <= big; i++) {8 System.out.print(i + " ");9 }10 System.out.println();11 }12 while (sum >n) {13 sum -=small;14 small++;15
16 if (sum ==n) {17 for (int i = small; i <= big; i++) {18 System.out.print(i + " ");19 }20 System.out.println();21 }22 }23
24 big++;25 sum +=big;26 }27 }