题目:输入一个正数n,输出所有和为n连续正数序列。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8
最简单,也是最笨的方法,就是两次循环,代码如下:
public void getSeri(int n) {
if (n == 1) {
return;
}
//防止溢出
int length = (n+1) >>> 1;
int sum = 0;
for (int i = 1; i < length; i++) {
sum = i;
for (int j = i +1; j <= length; j++) {
sum += j;
if (sum == n) {
System.out.println(i + "-" + j);
break;
} else if (sum > n) {
break;
}
}
}
}
我们先看,这段代码,首先如果输入的是 1直接返回,因为不会有连续的值相加等于自己。然后看length,这个值是我们for循环的最大值,因为,length的值是输入值的中间值,一单超过了中间值,任意两个值相加都会比n大。比如说,15的中间值是8,8+9=17>15,之后的所有序列都大于15了,所以循环到8就可以终止了,节省下效率。
虽然我们在循环上稍微注意了下效率,但实际上,这个代码的效率还是很低了,因为做了两次嵌套循环。如果n=100的话,就要做50*50=2500次循环,n越大,速度越慢。
所以我又想了,第二种方法,代码如下:
public void getSeriProv(int n) {
if (n == 1) {
return;
}
int length = (n+1) >>> 1;
List queue = new LinkedList<>();
int sum = 0;
for (int i =1; i <= length; i++) {
queue.add(i);
sum += i;
while (sum > n) {
int oldvalue = queue.remove(0);
sum -= oldvalue;
}
if (sum == n) {
System.out.println(queue.get(0) + "-" + queue.get(queue.size()-1));
int oldvalue = queue.remove(0);
sum -= oldvalue;
}
}
}
我先创建了一个队列。每次循环都向队列的列尾加入当前的数值,同时计算sum和,如果sum比n大的话就移除列头的值,直到sum<=n,如果sum=n则,直接打印结果,移除列头,进行下一次的循环。
因为是连续数值的和,这样我就不用每次都从头sum,只需要每次sum队列里面的值即可。