知乎上有一篇总结的还不错, 如果觉得不够详细,或者想要参考题目以及其他答案的同学,可以在 这里 找到。
练习
1. 表达式的值
a. 7
b. 200.0000002
c. true
2. 类型和值
a. double, 1.618
b. double, 10.0
c. boolean, true
d. String, 33
3. equal 判断
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
if (a == b && b == c) {
System.out.println("equal");
} else {
System.out.println("not equal");
}
}
}
4. 语句修正
if (a > b) c = 0; else b = 0;
5. 范围判断
import java.util.Scanner;
public class Test {
public static boolean right(double d) {
if (d >= 0.0 && d <= 1.0) {
return true;
} else {
return false;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double x = sc.nextDouble();
double y = sc.nextDouble();
if (right(x) && right(y)) {
System.out.println("true");
} else {
System.out.println("false");
}
}
}
6. Fibnonacci 数列
// 斐波那契数列的非递归算法
int f = 0;
int g = 1;
for (int i = 0; i <= 15; i++) {
System.out.println(f);
f = f + g;
g = f - g;
}
- 结果
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
7. 打印的值
a. 3.00009
b. 499500
c. 10000
8. 打印结果
a. b
b. 197
c. e
9. 正整数二进制
- Java 中有内置方法
Integer.toBinaryString();
// 一个简洁的实现方法
String s = "";
for (int n = N; n > 0; n /= 2) {
s = (n % 2) + s;
}
10. 代码存在的问题
没有用 new 为 a[] 分配内存,会产生一个 variable a might not have been initialized 的编译错误。
int[] a;
for (int i = 0; i < 10; i++) {
a[i] = i * i;
}
11. 打印二维布尔数组
// 已初始化 boolean 类型二维数组 b
for (boolean[] booleans : b) {
System.out.print(lineNumber++ + "| ");
for (boolean aBoolean : booleans) {
if (aBoolean) {
System.out.print("*");
} else {
System.out.print(" ");
}
}
System.out.println();
}
12. 打印结果
此处书中有误,代码段应为:
int[] a = new int[10];
for (int i = 0; i < 10; i++)
a[i] = 9 - i;
for (int i = 0; i < 10; i++)
a[i] = a[a[i]];
for (int i = 0; i < 10; i++)
System.out.println(i);
- 结果
0
1
2
3
4
4
3
2
1
0
13. 二维数组的转置
// 使用 int 类型数组举例,已初始化数组 a[M][N]
int[][] temp = new int[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
temp[i][j] = a[j][i];
System.out.print(temp[i][j] + " ");
}
System.out.println();
}
14. 返回不大于 log₂N 的最大整数
public static int lg(int N) {
int result = 0;
int temp = 2;
while (temp < N) {
temp *= 2;
result++;
}
return result;
}
15. 返回长度为 M 的数组
public static int[] histogram(int[] a, int M) {
int[] temp = new int[M];
for (int i = 0; i < M; i++) {
for (int value : a) {
if (i == value) temp[i]++;
}
}
return temp;
}
16. exR1(6) 的返回值
311361142246
17. 递归函数的问题
这段代码中的基础情况永远不会被访问。调用 exR2(3) 会产生调用 exR2(0)、exR2(-3) 和 exR2(-6),循环往复直到发生 StackOverflowError。
18. 考察乘法与乘方的递归实现
- 修改前:
public static int mystery(int a, int b) {
if (b == 0) return 0;
if (b % 2) return mystery(a + a, b / 2);
return mystery(a + a, b / 2) + a;
}
- 返回值
mystery(2, 25) = 50
mystery(3, 11) = 33
mystery(a, b) = a * b
核心思想: x * y = (x * 2 * 2 * ...) * (y / 2 / 2 / ...)
PS: 此处的 x 可能为偶数,但 y 必为奇数。
- 修改后:
public static int mystery(int a, int b) {
if (b == 0) return 0;
if (b % 2) return mystery(a * a, b / 2);
return mystery(a * a, b / 2) * a;
}
- 返回值
mystery(2, 25) = 33554432
mystery(3, 11) = 177147
mystery(a, b) = aᵇ
核心思想: x ^ y = (x ^ 2) ^ (y / 2)
19. 改进 F(N) 的实现
书上的递归方法探究一小时之内能够得到 F(N) 结果最大的 N 值因为耗时比较长这里就不做尝试了。改进的方法可以参考 6 中的 斐波那契数列的非递归算法 ,下面的是按书上要求利用数组保存值的改进方法:
public static long F(int N) {
int[] a = new int[N];
a[0] = 0;
a[1] = 1;
for (int i = 2; i < N; i++) {
a[i] = a[i - 1] + a[i - 2];
}
return a[N - 1];
}
20. ln(N!) 的递归求解
public static double ln(int N) {
if (N == 0 || N == 1) {
return;
} else {
return ln(N - 1) + Math.log(N);
}
}
21. 输入数据打印表格
这里用到了 printf() 的格式化输出,不懂的同学请自行参考 菜鸟教程 。
System.out.print("Please input data count: ");
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
String[] nameArray = new String[n];
int[] integerArray1 = new int[n];
int[] integerArray2 = new int[n];
for (int i = 0; i < n; i++) {
nameArray[i] = scanner.next();
integerArray1[i] = scanner.nextInt();
integerArray2[i] = scanner.nextInt();
}
System.out.println("|----------|-----|-----|-----|");
for (int i = 0; i < n; i++) {
System.out.printf("|%-10s|%-5d|%-5d|%.3f|\n", nameArray[i], integerArray1[i], integerArray2[i], ((double) integerArray1[i] / integerArray2[i]));
System.out.println("|----------|-----|-----|-----|");
}
- 看到有一个比较有意思的解题方法,思路是用
split()方法将得到的两行数据进行拆分。缺点是如果输入的数据不是以单个空格为间隔就会报NumberFormatException的异常。
Scanner sc = new Scanner(System.in);
String[] a = new String[2];
int index = 0;
while (index < a.length) {
a[index] = sc.nextLine();
index++;
}
for (String s : a) {
String[] stringArr = s.split(" ");
int num1 = Integer.parseInt(stringArr[1]);
int num2 = Integer.parseInt(stringArr[2]);
System.out.printf("%-10s%-5d%-5d%.3f\n", stringArr[0], num1, num2, ((double) num1 / num2));
}
22. BinarySearch-按递归深度缩进
如果你忘记了之前的 rank() 方法,可以在 这里 找到它。下面来对它进行改写:
public static int rank(int key, int[] a) {
return rank(key, a, 0, a.length - 1, 1);
}
// 如果是在某一限定范围内进行查找,则需要手动传入参数 `deep` 的值
// `deep` 的值需要设定在大于等于 1 的整数群中,否则在第 3 - deep 行中才会出现缩进效果
public static int rank(int key, int[] a, int lo, int hi, int deep) {
// 实现缩进
for (int i = 1; i < deep; i++) {
System.out.print(" ");
}
System.out.printf("%d. lo: %d hi: %d\n", deep, lo, hi);
// 如果 key 存在于 a[] 中,它的索引不会小于 lo 且不会大于 hi
if (lo > hi) return -1;
int mid = lo + (hi - lo) / 2;
if (key < a[mid]) {
return rank(key, a, lo, mid - 1, deep + 1);
} else if (key > a[mid]) {
return rank(key, a, mid + 1, hi, deep + 1);
} else {
return mid;
}
}
23. BinarySearch 的测试用例
public static void main(String[] args) {
int[] whiteList = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
System.out.print("Please input \"+\" or \"-\": ");
// 为避免读入多余字符使用了 edu.princeton.cs.algs4 包中 StdIn 类里的 readChar() 方法
char flag = StdIn.readChar();
// 读入第一个字符以外的其余字符(不作用途)
StdIn.readLine();
System.out.print("Please input keys(Split with space): ");
String[] keyList = StdIn.readLine().split(" ");
for (String s : keyList) {
if (flag == '+') {
if (rank(Integer.parseInt(s), whiteList) == -1) {
System.out.printf("%s ", s);
}
} else if (flag == '-') {
if (rank(Integer.parseInt(s), whiteList) != -1) {
System.out.printf("%s ", s);
}
}
}
System.out.println("\nDone!");
}
24. 欧几里得算法计算最大公约数
public class Euclid {
public static int euclid(int p, int q) {
if (q == 0) {
return p;
}
System.out.printf("p = %d, q = %d\n", p, q);
// 交换值的目的是为了减小递归的运算次数
if (p < q) {
int temp = p;
p = q;
q = temp;
}
return euclid(q, p % q);
}
public static void main(String[] args) {
int p = StdIn.readInt();
int q = StdIn.readInt();
System.out.println("\nresult = " + euclid(p, q));
}
}
25. 数学归纳法证明欧几里得算法
参考:
简书 - 欧几里得算法心得(辗转相除法)
百度文库 - 辗转相除法的证明