1 package cn.temptation;
2
3 import java.util.Scanner;
4
5 public class Sample01 {
6 public static void main(String[] args) {
7 // 需求:编写程序打印如下效果:(杨辉三角变体)
8 // 1
9 // 1 1
10 // 1 2 1
11 // 1 3 3 1
12 // 1 4 6 4 1
13 // 1 5 10 10 5 1
14
15 // 思路:使用二维数组存储杨辉三角的数据,再遍历数组打印(每行打印缩进 和 数值)
16
17 // 思路:(找规律)
18 // 1、第n行有n个数(n从1开始)
19 // 2、第1行和第2行均为1,从第3行开始,每行的首尾均为1
20 // 3、从第3行的第2列开始到该行的倒数第二个数结束,该位置上的数等于上一行同列的数 + 上一行前一列的数
21 // 从第4行的第2列开始到该行的倒数第二个数结束,该位置上的数等于上一行同列的数 + 上一行前一列的数
22 // ......以此类推
23
24 System.out.println("键盘录入杨辉三角的行数:");
25 Scanner input = new Scanner(System.in);
26 int row = input.nextInt();
27 input.close();
28
29 // 考虑存储杨辉三角中的数进行计算,都是数字(具有相同意义),考虑使用数组;
30 // 因为涉及到行列,考虑使用二维数组;
31 // 因为行中的列数不同,所以声明及初始化数组时使用只有一级元素长度没有二级元素长度的定义方式
32 int[][] arr = new int[row][];
33
34 // 根据规律1
35 // arr[0] = new int[1];
36 // arr[1] = new int[2];
37 // arr[2] = new int[3];
38 // ...
39 // arr[n] = new int[n+1];
40
41 for (int i = 0; i < row; i++) {
42 // 二维数组中的每个一级元素依据规律1创建相应长度的一维数组
43 arr[i] = new int[i + 1];
44
45 // 依据规律2:第1行和第2行均为1,从第3行开始,每行的首尾均为1
46 arr[i][0] = 1;
47 arr[i][i] = 1;
48 }
49
50 // 依据规律3:从第3行的第2列开始到该行的倒数第二个数结束,该位置上的数等于上一行同列的数 + 上一行前一列的数
51 // 从第4行的第2列开始到该行的倒数第二个数结束,该位置上的数等于上一行同列的数 + 上一行前一列的数
52 // ......以此类推
53 for (int i = 2; i < arr.length; i++) { // 外层循环的i表示行
54 for (int j = 1; j < arr[i].length - 1; j++) { // 内层循环的j表示列
55 arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
56 }
57 }
58
59 // 调用方法打印数组
60 printArray(arr);
61 }
62
63 /**
64 * 打印数组
65 * @param arr:二维数组
66 */
67 public static void printArray(int[][] arr) {
68 // 遍历数组
69 for (int i = 0; i < arr.length; i++) {
70 // 1、打印缩进
71 for (int j = 0; j < arr.length - i - 1; j++) {
72 System.out.print("\t");
73 }
74
75 // 2、打印杨辉三角数据
76 for (int j = 0; j < arr[i].length; j++) {
77 System.out.print(arr[i][j] + "\t");
78 }
79
80 // 换行
81 System.out.println();
82 }
83 }
84 }
1 package cn.temptation;
2
3 public class Sample02 {
4 public static void main(String[] args) {
5 // 需求:一个小球从100米的高度自由落下,每次落地后弹起至原高度的一半后再落下,求它在第10次落地时,共运行了多少米?第10次反弹多高?
6
7 // 思路: 100 -----> 50 -----> 50 -----> 25 -----> 25 -----> 12.5 -----> ....
8 // 落下: 1 2 3
9 // 反弹: 1 2 3
10
11 // 初始化高度
12 double height = 100;
13 // 小球行走的距离
14 double distance = 0;
15
16 // 思路1:分别计算 反弹 和 落下
17 // 1、每次反弹的高度都是前一次的一半,第1次反弹按100米的一半来计算
18 // 2、行走距离 = 落下的总距离 + 反弹的总距离
19 // 3、每次落下的高度也是前一次的一半
20
21 // // 计算反弹
22 // for (int i = 1; i <= 10; i++) {
23 // // 反弹高度
24 // height = height / 2;
25 //
26 // if (i < 10) {
27 // distance += height;
28 // }
29 //
30 // if (i == 10) {
31 // System.out.println("第" + i + "次反弹的高度为:" + height + "米");
32 // }
33 // }
34 //
35 // // 因为分别计算反弹和落下,所以需要重置初始高度
36 // height = 100;
37 //
38 // // 计算落下
39 // for (int i = 1; i <= 10; i++) {
40 // distance += height;
41 // height = height / 2;
42 // }
43
44 // 思路2:第n次落下 和 第n-1次反弹的高度是一样的,即第n-1次反弹的高度*2 + 初始高度就是第n次落下共行走的距离
45
46 // 初始高度
47 double defaultHeight = height;
48 distance += defaultHeight;
49
50 for (int i = 1; i <= 10; i++) { // i表示反弹的次数
51 // 反弹的高度
52 height = height / 2;
53
54 if (i < 10) {
55 distance += height * 2;
56 }
57
58 if (i == 10) {
59 System.out.println("第" + i + "次反弹的高度为:" + height + "米");
60 }
61 }
62
63 System.out.println("在第10次落地时,共运行了" + distance + "米");
64 }
65 }
1 package cn.temptation;
2
3 public class Sample03 {
4 public static void main(String[] args) {
5 // 需求:有一对兔子,从出生后第3个月开始每个月都生一对兔子,小兔子出生后第3个月后每个月又生一对兔子,假设兔子都不死,计算第20个月兔子的总数有多少只?
6
7 // 规律:
8 // 月份 当月出生 原有数量 总和
9 // 第1个月 0 1 1
10 // 第2个月 0 1 1
11 // 第3个月 1 1 2
12 // 第4个月 1 2 3
13 // 第5个月 2 3 5
14 // 第6个月 3 5 8
15 // ...
16
17 // 其实就是Fibonacci数列,规律:1、1、2、3、5、8、13、... 从第3项开始,值为前两项的和
18
19 // 写法1、使用数组
20 int month = 20;
21 int[] arrNumber = new int[20];
22
23 for (int i = 1; i <= arrNumber.length; i++) {
24 if (i == 1 || i == 2) {
25 arrNumber[i - 1] = 1;
26 } else {
27 arrNumber[i - 1] = arrNumber[i - 3] + arrNumber[i - 2];
28 }
29
30 if (i == month) {
31 System.out.println("第" + i + "个月兔子的总数为:" + arrNumber[i - 1] * 2 + "只");
32 }
33 }
34
35 // 写法2、使用递归方法(方法内调用方法自身)
36 System.out.println("第" + month + "个月兔子的总数为:" + count(month) * 2 + "只");
37 }
38
39 /**
40 * 统计方法
41 * @param i
42 * @return
43 */
44 public static int count(int i) {
45 if (i == 1 || i == 2) {
46 return 1;
47 } else {
48 return count(i - 2) + count(i - 1);
49 }
50 }
51 }
1 package cn.temptation;
2
3 import java.util.Scanner;
4
5 public class Sample04 {
6 public static void main(String[] args) {
7 // 需求:一条长廊里依次装有n(1 ≤ n ≤ 65535)盏电灯,从头到尾编号1、2、3、...、n-1、n。每盏电灯由一个拉线开关控制。开始电灯全部关闭。
8 // 有n个学生从长廊穿过。第一个学生把号码凡是1的倍数的电灯的开关拉一下;接着第二个学生把号码凡是2的倍数的电灯的开关拉一下;
9 // 接着第三个学生把号码凡是3的倍数的电灯的开关拉一下;...
10 // 如此继续下去,最后第n个学生把号码凡是n的倍数的电灯的开关拉一下。
11 // 计算n个学生按此规定走完后,长廊里电灯有几盏亮着。(注意:电灯数 和 学生数一致)
12
13 // 思路:取反操作,切换电灯状态(开/关)
14
15 System.out.println("长廊里的电灯数量(也就是学生数量):");
16 Scanner input = new Scanner(System.in);
17 int number = input.nextInt();
18 input.close();
19
20 // 定义剩余亮着的灯的数量
21 int stillOnNumber = 0;
22
23 if (number < 1 || number > 65535) {
24 System.out.println("输入的范围不在1 ≤ n ≤ 65535内");
25 } else {
26 // 因为灯的状态只有开和关,所以考虑创建一个boolean类型的数组
27 boolean[] arrLight = new boolean[number];
28
29 // 开始电灯全部关闭(这步可以省略,因为boolean类型数组元素的默认值就是false)
30 // for (boolean item : arrLight) {
31 // item = false;
32 // }
33
34 // 所谓的拉一下灯,都是对灯当前的状态进行取反的操作
35 // 第n个学生把号码凡是n的倍数的电灯的开关拉一下,感觉需要使用循环
36 for (int i = 1; i <= number; i++) { // i表示学生号
37 // 下句可以进行改进,因为倍数至少是和自身一样大的数,也就是比自己小的数字不用再去浪费循环比较了
38 // for (int j = 1; j <= number; j++) { // j表示灯号
39 // 优化写法1、
40 // for (int j = i; j <= number; j++) { // j表示灯号
41 // // 第n个学生寻找n的倍数
42 // if (j % i == 0) {
43 // // 取反操作
44 // arrLight[j - 1] = !arrLight[j - 1];
45 // }
46 // }
47
48 // 优化写法2、考虑到j从i的值开始算起,统计的是倍数,所以直接在循环时加若干倍
49 for (int j = i; j <= number; j += i) { // j表示灯号
50 // 取反操作
51 arrLight[j - 1] = !arrLight[j - 1];
52 }
53 }
54
55 // 统计一下亮着的灯(状态为true)的数量
56 for (boolean item : arrLight) {
57 // 写法1
58 // if (item == true) {
59 // stillOnNumber++;
60 // }
61
62 // 写法2
63 if (item) {
64 stillOnNumber++;
65 }
66 }
67
68 System.out.println("n个学生按此规定走完后,长廊里电灯有" + stillOnNumber + "盏亮着");
69 }
70 }
71 }
1 package cn.temptation;
2
3 public class Sample05 {
4 // 成员变量
5 // 注意:因为静态的成员方法只能访问静态的成员变量
6 // 初始的酒的数量
7 static int number = 10 / 2;
8
9 public static void main(String[] args) {
10 // 需求:某啤酒2元一瓶,现在做活动,2个空瓶或4个瓶盖可以换1瓶啤酒。现有10元,最多可以喝多少瓶啤酒?(注意:不可以赊欠)
11
12 // 思路:兑换的操作终止的条件时,剩下的酒瓶数量没有2个 或 剩下的瓶盖数量没有4个
13
14 // 因为初始的酒的数量会在不同的成员方法中使用,所以就不应该再定义为局部变量了,考虑使用成员变量
15 // 初始的酒的数量
16 // int defaultNumber = 10 / 2;
17
18 // 兑换
19 exchange(number, number);
20 }
21
22 /**
23 * 兑换方法
24 * @param bottle 酒瓶
25 * @param cap 瓶盖
26 * @return
27 */
28 public static void exchange(int bottle, int cap) {
29 if (bottle >= 2 || cap >= 4) {
30 // 兑换后剩余的酒瓶数量 = 当次酒瓶兑换的酒瓶数量 + 当次酒瓶未能兑换的酒瓶数量 + 当次瓶盖兑换的酒瓶数量
31 int x = bottle / 2 + bottle % 2 + cap / 4;
32 // 兑换后剩余的瓶盖数量 = 当次瓶盖兑换的酒瓶数量(也就是瓶盖数量) + 当次瓶盖未能兑换的瓶盖数量 + 当次酒瓶兑换的酒瓶数量
33 int y = cap / 4 + cap % 4 + bottle / 2;
34
35 // 每次兑换,兑换来的酒的数量应该加在初始数量之上
36 number += (bottle / 2 + cap / 4);
37
38 // 再次调用兑换方法
39 exchange(x, y);
40 } else { // 不再进行兑换的条件
41 System.out.println("剩余的酒瓶数量为:" + bottle);
42 System.out.println("剩余的瓶盖数量为:" + cap);
43 System.out.println("最多可以喝" + Sample05.number + "瓶啤酒");
44 }
45 }
46 }