题目描述
给出一个正整数N和长度L,找出一段长度大于等于L的连续非负整数,他们的和恰好为N。答案可能有多个,我们需要找出长度最小的那个。
例如 N = 18 L = 2:
5 + 6 + 7 = 18
3 + 4 + 5 + 6 = 18
都是满足要求的,但是我们输出更短的 5 6 7 。
Me
主要使用了队列的思想,绕了一大圈还运行超时……
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a = in.nextInt();
int b = in.nextInt();
printList(a, b);
}
public static int printList(int N, int L) {
int pivot=(N+1)/2, sum=pivot, len=1;
Node begin=new Node(pivot), now=begin, t;
// 逆序确保获得最短的连续非负整数(从中值开始)
for (int i=pivot-1; i>=0; i--) {
t = new Node(i);
now.next = t;
// prior指针确保输出时正序
t.prior = now;
sum += i;
len ++;
if (sum == N && len >= L) {
if (len <= 100) {
t.printValues();
return 0;
}
System.out.println("No");
return 0;
} else if ((sum > N || sum == N) && i!=1) {
sum -= begin.value;
begin = begin.next;
begin.prior = null;
len --;
}
now = now.next;
}
System.out.println("No");
return 0;
}
}
class Node {
Node prior;
Node next;
int value;
public Node(int value) {
this.value = value;
}
public Node() {
}
public void printValues() {
Node p = this;
while (true) {
System.out.print(p.value);
p = p.prior;
if (p != null) {
System.out.print(" ");
} else {
break;
}
}
}
}
此思路的主要缺陷:
- printValues方法中需要再次扫描队列,并且没啥好的方法可以避免该冗余;
- 主循环for (int i=pivot-1; i>=0; i–) 除非中途遇到(sum == N && len >= L),否则必须从头扫到尾,当输入的N很大且无连续非负整数组合时,耗时长。
总之,这是一个很笨还有点暴力的方法……
等差数列
只要!把这道题看作求解等差数列!一个至多(L-100)的循环就可以解决这个问题。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int a = in.nextInt();
int b = in.nextInt();
display(a, b);
}
public static int display(int N,int L) {
for (int c=L; c<101; c++) {
if (2*N%c == 0 && (2*N/c-c+1)%2 == 0) {
int a = (2*N/c-c+1)/2;
for (int j=0; j<c; j++) {
System.out.print(j+a);
if (j < c-1) System.out.print(" ");
}
return 0;
}
}
System.out.print("No");
return 0;
}
}
总结
做题的时候除了用好各种工具(栈、队列、树……),最重要的是动脑子,从算法角度得到突破。思考比工具更重要,也更有效。