1. 求一个整数的各个位数的和,例如235的各个数位的和是10。
解析:该问题的关键是要分解整数。思考:一个数和10求余将会得到其个位数字,如:123%10 = 3,那么如果12 % 10 = 2,1 % 10 = 1,这样就实现了整数的分解。具体步骤是:
一、 将一个数与0进行比较,如果该数等于0,则各位数字的和就是0;
二、 如果该数不是0,则将该数对10取余数(该余数就是分解的各个数位的数字);
三、 将该数字减小为原来的十分之一,继续执行步骤二。
下面是java代码的实现:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入一个整数:");
Scanner scanner = new Scanner(System.in);
int number = scanner.nextInt();
int sum = SumOfAllNumbers(number);
System.out.println("整数" + number + "的各个数字的和是:" + sum);
}
/* 该方法返回一个整数的各个数位的数字之和,如999则返回27 */
private static int SumOfAllNumbers(int number) {
int sum = 0;
number = number < 0 ? -number : number; // 判断正负
while (number != 0) {
sum += number % 10;
number /= 10;
}
return sum;
}
}
将以上的while循环改造成do-while循环可以进一步简化代码:
do {
sum += number % 10;
} while ((number /= 10) != 0);
2.
使用System.currentTimeMillis()函数取得一个随机的大写字母(不能使用随机函数)
分析:这个题目的关键就是如何产生一个范围在[65,90]的随机数。我们知道System.currentTimeMillis()返回系统距离1970-1-1 00:00:00分的毫秒数。把它对26取余数就可以得到一个0~25的随机数,这样就产生了一个字母的相对索引。这个随机数再加上65就可以得到一个[65,90]的随机数了:
实现如下:
(char) (System.currentTimeMillis() % 26 + 65)
3. 编写一个算法实现4个整数的升序排序。
思路:从第一个数开始依次比较相邻的两个数,一遍结束以后,最大的数就到了末尾【冒泡排序的基本实现】,然后再从第一个数开始比较,这次只需要到第二个数,重复这个过程直到最后比较的两个数是第一个数和第二个数。
实现如下:
System.out.println("请输入4个整数:");
Scanner scanner = new Scanner(System.in);
int num1 = scanner.nextInt();
int num2 = scanner.nextInt();
int num3 = scanner.nextInt();
int num4 = scanner.nextInt();
// 这个是冒泡排序的基本思想,后面的排序可能扰乱前面的顺序,最后的两个数是最先排好序的
/* 第一遍(3次) */
if (num1 > num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
if (num2 > num3) {
int temp = num2;
num2 = num3;
num3 = temp;
}
if (num3 > num4) {
int temp = num3;
num3 = num4;
num4 = temp;
}
/* 第二遍(2次) */
if (num1 > num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
if (num2 > num3) {
int temp = num2;
num2 = num3;
num3 = temp;
}
/* 第三遍(1次) */
if (num1 > num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
System.out.println("升序排列:" + num1 + "," + num2 + "," + num3 + ","
+ num4);
以上是一个典型的冒泡排序,假如有n个数需要比较,一共需要比较n-1遍,第一遍比较n-1次,第二遍比较n-2次,……第n-1遍比较1次,总共需要比较的次数是1+2+……+(n-1)=n*(n-1)/2次,时间复杂度为Q(n^2)。
也可以采用以下的思想进行排序:
先找出所有数中最小的一个,并将该数赋值给第一个数;然后从剩下的数中再找出一个最小的数,赋值给第二个数,重复这个过程,直到倒数第二个数成功赋值。
实现如下:
System.out.println("请输入4个整数:");
Scanner scanner = new Scanner(System.in);
int num1 = scanner.nextInt();
int num2 = scanner.nextInt();
int num3 = scanner.nextInt();
int num4 = scanner.nextInt();
/* 选出最小的数(3次) */
if (num1 > num2) {
int temp = num1;
num1 = num2;
num2 = temp;
}
if (num1 > num3) {
int temp = num1;
num1 = num3;
num3 = temp;
}
if (num1 > num4) {
int temp = num1;
num1 = num4;
num4 = temp;
}
/* 找出第二小的数(2次) */
if (num2 > num3) {
int temp = num2;
num2 = num3;
num3 = temp;
}
if (num2 > num4) {
int temp = num2;
num2 = num4;
num4 = temp;
}
/* 找出第三小的数(1次) */
if (num3 > num4) {
int temp = num3;
num3 = num4;
num4 = temp;
}
System.out.println("升序排列:" + num1 + "," + num2 + "," + num3 + ","
+ num4);
以上算法是先求出小的数放在第一个位置,然后求出第二小的数放入第二个位置,依次类推直到倒数第二个数确定。算法的时间复杂度也和冒泡的差不多,确定第一个数需要比较n-1次,确定第二个数需要比较n-2次,确定n-1(倒数第二个数)需要比较1次,总共执行比较的次数是(n-1)+(n-2)+……+1 = n*(n-1)/2次,算法的时间复杂度为O(n^2)。
4. 编写一个程序该程序能够从52张牌中随机取出一张(大小和花色)。
思路一:产生两个随机数,随机数1是[1,13]之间的,用于表示牌的大小;随机数2是[0,3]之间的用于表示花色。实现如下:
int size = (int) (Math.random() * 13 + 1); // 牌的大小
int color = (int) (Math.random() * 4); // 牌的花色
String big = null;
if (1 == size) {
big = "Ace";
} else if (11 == size) {
big = "Jack";
} else if (12 == size) {
big = "Queen";
} else if (13 == size) {
big = "King";
} else {
big = size + "";
}
String type = null;
switch (color) {
case 0:
type = "黑梅花";
break;
case 1:
type = "红方块";
break;
case 2:
type = "红心";
break;
case 3:
type = "黑桃";
break;
default:
break;
}
System.out.println("你的牌大小是" + big + ",你的牌花色是" + type);
思路二:52张牌有4种花色,每种花色有13张牌,我们可以产生一个[0,51]之间的一个随机数,把这个随机数对13求余数,得到13种状态,表示大小;把该随机数对13做商得到4种状态,表示4种花色。
private static final int NUM_OF_CARDS = 52;
public static void main(String[] args) {
int number = (int) (Math.random() * 52);
int size = number % 13 + 1; // 大小
String big = null;
if (1 == size) {
big = "Ace";
} else if (11 == size) {
big = "Jack";
} else if (12 == size) {
big = "Queen";
} else if (13 == size) {
big = "King";
} else {
big = size + "";
}
int color = number / 13;
String type = null;
switch (color) {
case 0:
type = "方块";
break;
case 1:
type = "梅花";
break;
case 2:
type = "红桃";
break;
case 3:
type = "黑桃";
default:
break;
}
System.out.println("牌的大小是" + big + ",牌的花色是" + type);
}
从代码的行数来看,两种思路并不存在明显的差别,但是思路二更值得我们去学习,因为它只产生了一个随机数,在资源受限的情况下更有效率。
5. 蒙特卡罗模拟:蒙特卡罗模拟使用随机数和概率来解决问题。这个方法在计算数学、物理、化学和财经方面有非常广泛的应用。下面的例子给出使用蒙塔卡罗来模拟π的值。为了使用蒙特卡罗方法计算π,画出圆的一个外界正方形:
假设这个圆的半径是1,那么圆的面积就是π而其外接正方形的面积就是4.随机产生正方形中的一个点,这个点落在圆内的概率就是circleArea/squareArea(圆面积/正方形面积)=π/4。
编写程序在正方形内随机产生1000000个点,用numberOfHits表示落在圆内的点。因此numberOfHits大约是1000000*(π/4)——可以近似认为π = 4*numberOfHits/1000000。程序清单如下:
public class MonteCarloSimulation {
public static void main(String[] args) {
final int NUMBER_OF_TRIALS = 10000000;
int numberOfHits = 0;
for (int i = 0; i < NUMBER_OF_TRIALS; i++) {
double x = Math.random() * 2.0 - 1;
double y = Math.random() * 2.0 - 1;
if (x * x + y * y <= 1) {
++numberOfHits;
}
}
double pi = 4.0 * numberOfHits / NUMBER_OF_TRIALS;
System.out.println("PI = " + pi);
}
}
运行结果:
PI = 3.14154564
6. 显示素数。在5行中显示前50个素数,每行10个数。该问题可以分解为以下的任务:
-判定一个给定的数是否是素数;
-针对number = 2,3,4,5,6,……,测试它是否是素数。
-统计素数的个数。
-打印每个素数每行10个。
显然需要编写循环,反复检测新的number是否是素数。如果number是素数,则计数器加1.计数器count的值被初始化为0.当它等于50的时候循环终止。该算法的伪码实现如下:
设置打印出来的素数的个数为常量NUMBER_OF_PRIMERS;
使用count来对素数个数进行计数并将其初值设为0;
设置number的初始值为2;
while( count < NUMBER_OF_PRIMES ){
测试该数是否是素数;
if ( 该数是素数 ) {
打印该素数并将count增加1;
}
number++;
}
为了测试某个数是否是素数,就需要检测它是否能够被2,3,4,一直到number/2的数整除(如果能够整除就说明它不是素数),这个算法的伪码描述如下:
使用布尔变量isPrime表示number是否是素数;
设置isPrime的初始值为true;
for ( int divisor = 2; divisor <= number / 2 ; divisor++ ) {
if ( number % divisor == 0 ) {
isPrime = false;
break;
}
}
该算法的完整实现如下:
public class PrimeNumber {
public static void main(String[] args) {
final int NUMBER_OF_PRIMES = 50;
final int NUMBER_OF_PRIMES_PER_LINE = 10;
int count = 0;// 素数个数的计数器
int number = 2;// 用来测试是否是素数
System.out.println("开始的50个素数");
while (count < NUMBER_OF_PRIMES) {
boolean isPrime = true; // 先假设是素数
// 测试该数字是否是素数
for (int i = 2; i <= number / 2; i++) {
if (number % i == 0) {
isPrime = false;
break;// 已经知道该数不是素数,退出本次测试
}
}
if (isPrime) {
if (++count % NUMBER_OF_PRIMES_PER_LINE == 0) {
System.out.println(number);
} else {
System.out.print(number + "\t");
}
}
++number;
}
}
}
运行结果:
以上的代码可以进一步模块化:
public class PrimeNumberMethod {
public static void main(String[] args) {
System.out.println("开头的50个素数是:");
printPrimeNumbers(50);
}
/*
* 打印指定个数的素数(从2开始)
*/
private static void printPrimeNumbers(int numberOfPrimes) {
final int NUMBER_OF_PRIME_PER_LINE = 10;
int count = 0;// 素数的个数
int number = 2;// 从2开始测试
while (count < numberOfPrimes) {
if (isPrime(number)) {
System.out.print(number + "\t");
if (++count % NUMBER_OF_PRIME_PER_LINE == 0) {
System.out.println();
}
}
number++;
}
}
/*
* 判断是否是素数
*/
private static boolean isPrime(int number) {
for (int divisor = 2; divisor <= number / 2; divisor++) {
if (0 == number % divisor) {
return false;
}
}
return true;
}
}
7. (找出2个最高分)编写程序,提示用户输入学生的个数、每个学生的名字以及分数,最后显示获得最高分的学生姓名和分数以及获得第二高分的学生姓名及其分数。
思路一:创建一个学生类,重写hashCode()方法和equals()方法并且实现Compareable接口使学生类拥有排序的功能;创建一个ArrayList将学生对象加入到ArrayList集合中;调用集合工具类Collections的sort()方法对ArrayList集合中的元素进行排序操作,最后依次取出前面的两个元素。实现如下:
学生类:
/**
* 学生类,该类重写了hashCode()和equals()方法并实现了Comparable接口用于排序
*
*/
public class Student implements Comparable {
private String name;
private float score;
public Student(String name, float score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getScore() {
return score;
}
public void setScore(float score) {
this.score = score;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + Float.floatToIntBits(score);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Student))
return false;
Student other = (Student) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Float.floatToIntBits(score) != Float.floatToIntBits(other.score))
return false;
return true;
}
@Override
public int compareTo(Student o) {
if (o.score > this.score) {
return 1;
} else if (o.score == this.score) {
return 0;
} else {
return -1;
}
}
@Override
public String toString() {
return "Student [name=" + name + ", score=" + score + "]";
}
}
测试类:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
System.out.println("请输入学生的个数:");
Scanner scanner = new Scanner(System.in);
int numberOfStudent = scanner.nextInt();
String name = null;
float score = 0;
for (int i = 0; i < numberOfStudent; i++) {
scanner = new Scanner(System.in);
System.out.println("请输入学生姓名:");
name = scanner.nextLine();
System.out.println("请输入学生成绩:");
score = scanner.nextFloat();
arrayList.add(new Student(name, score));
}
Collections.sort(arrayList);//用集合工具类Collections进行排序
System.out.println("最高分是" + arrayList.get(0).getName() + ",分数是"
+ arrayList.get(0).getScore());
System.out.println("第二高分是" + arrayList.get(1).getName() + ",分数是"
+ arrayList.get(1).getScore());
}
}
思路一采用了面向对象的设计,本身是很值得提倡的,但是发现其到处在调用API,没有一点算法精神在里面,并且代码很容易就到了100行,其实这100行我们真正用得到的代码并不多。
import java.util.Scanner;
public class getMaxAndSecondScore {
public static void main(String[] args) {
System.out.println("输入学生的个数:");
Scanner scanner = new Scanner(System.in);
int number = scanner.nextInt();
float maxScore = 0;
float secondScore = 0;
String maxName = "";
String secondName = "";
for (int i = 0; i < number; i++) {
scanner = new Scanner(System.in);
System.out.println("请输入学生姓名:");
String name = scanner.nextLine();
System.out.println("请输入学生分数:");
float score = scanner.nextFloat();
if (score > maxScore) {
maxScore = score;
maxName = name;
}
if (score < maxScore && score > secondScore) {
secondScore = score;
secondName = name;
}
}
System.out.println("最高分是:" + maxName + "分数是:" + maxScore + "\n第二高分是:"
+ secondName + "分数是" + secondScore);
}
}
实现二短短30行代码搞定问题,体现了算法的精髓。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入两个数:");
Scanner scanner = new Scanner(System.in);
int num1 = scanner.nextInt();
int num2 = scanner.nextInt();
int gcd = getGcd(num1, num2);
System.out.println(num1 + "和" + num2 + "的最大公约数是" + gcd);
}
private static int getGcd(int num1, int num2) {
int temp = num1 < num2 ? num1 : num2;
int gcd = 1;
for (int i = temp; i > 0; i--) {
if (num1 % i == 0 && num2 % i == 0) {
gcd = i;
break; // 第一个符合条件的数就是最大公约数
}
}
return gcd;
}
}
分析:从2开始进行测试,如果该数能够被被2,整除,则输出其因子2,将原来的数除以该因子赋值给num;否则将测试条件加1再进行测试,重复以上两个步骤直到测试条件大于需要测试的整数。实现如下:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入正整数:");
Scanner scanner = new Scanner(System.in);
int num = scanner.nextInt();
printFactor(num);
}
private static void printFactor(int num) {
System.out.println("数" + num + "的最小公因子有:");
int i = 2;
while (i <= num) {
if (num % i == 0) {
System.out.print(i + "\t");// 输出因子
num /= i;// 除以该因子,再进行测试
} else {
i++;
}
}
}
}
10.
(显示金字塔)编写程序,提示用户输入一个在1~15之间的数,然后显示一个金字塔形状的图案,如图所示:
分析:此问题可以分解为以下2个方面,从行的角度来看需要确定每行打印的数字以及每一行打印完成之后要打印一个换行;从列的角度来看每一行需要确定开头的空白数目,以及每一行的升序和降序排列。具体实现如下:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.print("请输入金字塔的层数:");
Scanner scanner = new Scanner(System.in);
int numberOfLine = scanner.nextInt();
printPyramidr(numberOfLine);
}
private static void printPyramidr(int numberOfLine) {
if (numberOfLine < 1 || numberOfLine > 15) {
System.out.println("输入的范围是1~15");
} else {
System.out.println("==========================================");
for (int row = 1; row <= numberOfLine; row++) {
/* 控制每一行前面的空格 */
for (int col = 1; col <= numberOfLine - row; col++) {
System.out.print("\t");// 第n行前面有有numberOfLine-n个空白
}
/* 从大到小输出 */
for (int num = row; num > 0; num--) {
System.out.print(num + "\t");// 从大到小打印行的序号
}
/* 从小到大输出 */
for (int num = 2; num <= row; num++) {
System.out.print(num + "\t");// 从第二行开始顺序输出到行值
}
System.out.println();// 每执行一个最外层循环换行
}
System.out.println("==========================================");
}
}
}
在以上基础上进行改进:如何打印下述的金字塔?
分析:每行的空格数 = 最大行数-当前行数;每行的*数目 = 2*该行行数 - 1,实现如下:
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.print("请输入金字塔的层数:");
Scanner scanner = new Scanner(System.in);
int numberOfLine = scanner.nextInt();
printPyramidr(numberOfLine);
}
private static void printPyramidr(int numberOfLine) {
if (numberOfLine < 1 || numberOfLine > 15) {
System.out.println("输入的范围是1~15");
} else {
System.out.println("==========================================");
for (int row = 1; row <= numberOfLine; row++) {
/* 控制每一行前面的空格 */
for (int col = 1; col <= numberOfLine - row; col++) {
System.out.print(" ");// 第n行前面有有numberOfLine-n个空白
}
for (int col = 0; col <2*row-1; col++) {
System.out.print("*");
}
System.out.println();// 每执行一个最外层循环换行
}
System.out.println("==========================================");
}
}
}
11. 计算自然对数的底数e。可以使用以下公式:e = 1 + 1/1! + 1/2! + 1/3! + …… + 1/i!。当i→∞时即可得出e的值。
思路一:使用递归计算出n的阶乘,以上公式可以看做初始值为1,其中每一项为n的阶乘的倒数,将他们相加即可,实现如下:
public class Test {
public static void main(String[] args) {
double e = 1;
for (int i = 1; i <= 50; i++) {
long num = fact(i);
e += 1.0 / num;
}
System.out.println("e = " + e);
}
/*
* 计算n的阶乘
*/
public static long fact(int n) {
if (n == 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
}
但是以上代码存在一个很严重的问题,它没有办法达到条件i→∞,事实上当i=500时,e = Infinity,当i= 50000时会抛出java.lang.StackOverflowError错误(因为递归的的层数太多),所以以上代码是行不通的。通过观察公式我们可以看出,第二项1/2! = 1 /1!/2;第三项1/3! = 1/2!/3,依据以上思路设计如下算法:
public class Test {
public static void main(String[] args) {
double e = 1;
double num = 1;
for (int i = 1; i <= 5000000; i++) {
num /= i;// 当前的值等于上一次的值除以当前索引
e += num;
}
System.out.println("e = " + e);
}
}
12. 简易日历。
import javax.swing.JOptionPane;
public class Test {
public static void main(String[] args) {
int year = Integer.parseInt(JOptionPane.showInputDialog("请输入年份"));
int firstDay = Integer.parseInt(JOptionPane
.showInputDialog("请输入该年第一日的星期数"));
int numberOfDaysMonth = 0;// 每月的天数
boolean isLeapYear = isLeapYear(year);
for (int month = 1; month <= 12; month++) {
System.out.print("\t\t" + year + "年");
switch (month) {
case 1:
System.out.println("1月");
numberOfDaysMonth = 31;
break;
case 2:
System.out.println("2月");
if (isLeapYear) {
numberOfDaysMonth = 29;
} else {
numberOfDaysMonth = 28;
}
break;
case 3:
System.out.println("3月");
numberOfDaysMonth = 31;
break;
case 4:
System.out.println("4月");
numberOfDaysMonth = 30;
break;
case 5:
System.out.println("5月");
numberOfDaysMonth = 31;
break;
case 6:
System.out.println("6月");
numberOfDaysMonth = 30;
break;
case 7:
System.out.println("7月");
numberOfDaysMonth = 31;
break;
case 8:
System.out.println("8月");
numberOfDaysMonth = 31;
break;
case 9:
System.out.println("9月");
numberOfDaysMonth = 30;
break;
case 10:
System.out.println("10月");
numberOfDaysMonth = 30;
break;
case 11:
System.out.println("11月");
numberOfDaysMonth = 30;
break;
case 12:
System.out.println("12月");
numberOfDaysMonth = 31;
break;
default:
break;
}
System.out.println("--------------------------------------------");
System.out.println("日\t一\t二\t三\t四\t五\t六");
for (int i = 0; i < firstDay; i++) {
System.out.print('\t');
}
int i = 0;
for (i = 1; i <= numberOfDaysMonth; i++) {
System.out.print(i + "\t");
if ((i + firstDay) % 7 == 0) {
System.out.println();
}
}
System.out.println();
System.out.println();
firstDay = (firstDay + numberOfDaysMonth) % 7;
}
}
private static boolean isLeapYear(int year) {
if (0 == year % 400 || 0 == year % 4 && 0 != year % 100) {
return true;
} else {
return false;
}
}
}
一个真正有用的日历:
import java.util.Scanner;
public class PrintCalendar {
public static void main(String[] args) {
/* 读取输入 */
Scanner scanner = new Scanner(System.in);
System.out.println("请输入年份:");
int year = scanner.nextInt();
if (year < 1900) {
System.out.println("年份从1900年开始!");
System.exit(1);
}
System.out.println("请输入月份:");
int month = scanner.nextInt();
if (month < 1 || month > 12) {
System.out.println("月份必须是1~12!");
System.exit(2);
}
scanner.close();
printMonth(year, month);// 打印日历
}
/** 打印指定年月的日历 */
private static void printMonth(int year, int month) {
printMonthTitle(year, month);
printMonthBody(year, month);
}
/** 打印日历头 */
private static void printMonthTitle(int year, int month) {
System.out.println(" " + year + "年" + month + "月");
System.out.println("-----------------------------------------------");
System.out.println("日\t一\t二\t三\t四\t五\t六");
}
/** 打印日历体 */
private static void printMonthBody(int year, int month) {
int startDay = getStartDay(year, month);
int numberOfDaysInMonth = getNumberOfDaysInMonth(year, month);
int i = 0;
for (i = 0; i < startDay; i++) {
System.out.print("\t");
}
for (i = 1; i <= numberOfDaysInMonth; i++) {
System.out.print(i + "\t");
if ((i + startDay) % 7 == 0) {
System.out.println();
}
}
}
/** 得到这个月的1号是星期几 */
private static int getStartDay(int year, int month) {
final int START_DAY_FOR_1_1_1900 = 1;// 1900-01-01是星期一
int totalNumberOfDays = getTotalNumberOfDays(year, month);
return (totalNumberOfDays + START_DAY_FOR_1_1_1990) % 7;
}
/** 计算距离1900-01-01的天数 */
private static int getTotalNumberOfDays(int year, int month) {
int total = 0;
for (int i = 1900; i < year; i++) {
total += isLeapYear(year) ? 366 : 365;
}
for (int i = 1; i < month; i++) {
total += getNumberOfDaysInMonth(year, i);
}
return total;
}
/** 判断是否是闰年 */
private static boolean isLeapYear(int year) {
return year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
}
/** 得到该月份的天数 */
private static int getNumberOfDaysInMonth(int year, int month) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8
|| month == 10 || month == 12) {
return 31;
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
return 30;
} else {
return isLeapYear(year) ? 29 : 28;
}
}
}
运行结果:
13. 【完全数】如果一个正整数等于除它本身之外其他所有除数之和,就称之为完全数。例如:6是第一个完全数,因为6 = 1+2+3.下一个完全数是28 = 1+2+4+7+14.10000以下的完全数一共有4个。编写程序,找出这4个完全数。
基本思想是对于一个数找出其所有因子(除本身之外的因子),然后将其所有的因子相加,如果和该数吻合,就代表该数是完全数。实现如下:
public class Test {
public static void main(String[] args) {
System.out.println("10000以下的完全数:");
for (int number = 6; number <= 10000; number++) {
int sum = 0;
for (int divisor = 1; divisor < number; divisor++) {
if (number % divisor == 0) {
sum += divisor;
}
}
if (sum == number) {
System.out.print(number + "\t");
}
}
}
}
运行结果:
14. 【十进制转化为二进制】输入一个十进制数输出其对应的二进制(不允许使用Integer.toBinaryString()方法)。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入十进制整数:");
String binaryString = "";
int num = new Scanner(System.in).nextInt();
do {
// 这一句非常巧妙:将原先的字符串追加到当前字符串的末尾
binaryString = num % 2 + binaryString;
} while ((num /= 2) != 0);
System.out.println("对应的二进制数是:" + binaryString);
}
}
同理,可以完成“十进制到十六进制的转换”【关键就是字符串的拼接顺序问题】
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入十进制整数:");
String hexString = "";
int num = new Scanner(System.in).nextInt();
do {
int currentNum = num % 16;
switch (currentNum) {
case 10:
hexString = 'A' + hexString;
break;
case 11:
hexString = 'B' + hexString;
break;
case 12:
hexString = 'C' + hexString;
break;
case 13:
hexString = 'D' + hexString;
break;
case 14:
hexString = 'E' + hexString;
break;
case 15:
hexString = 'F' + hexString;
break;
default:
hexString = currentNum + hexString;
break;
}
} while ((num /= 16) != 0);
System.out.println("对应的十六进制数是:" + hexString);
}
}
另一种实现:
import java.util.Scanner;
public class Decimal2HexConversion {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个整数:");
int number = scanner.nextInt();
scanner.close();
System.out.println(number + "转化为16进制后是:" + decimal2HexString(number));
}
private static String decimal2HexString(int number) {
String hexString = "";
do {
int hexValue = number % 16;
hexString = toHexChar(hexValue) + hexString;
} while ((number /= 16) != 0);
return hexString;
}
private static char toHexChar(int hexValue) {
if (hexValue >= 0 && hexValue <= 9) {
return (char) ('0' + hexValue);
} else {
return (char) (hexValue - 10 + 'A');
}
}
}
15. (计算机体系结构方面:比特级的操作)一个int类型的数据需要使用32byte存储。编写程序,提示用户输入一个短整型,然后显示这个整数的32比特形式。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个整数:");
int value = scanner.nextInt();
System.out.println("补码表示:");
int mask = 1;
int count = 0;
for (int i = 31; i >= 0; i--) {
int temp = value >> i;
int bit = temp & mask;
System.out.print(bit);
if (++count % 4 == 0) {
System.out.print(',');
}
}
}
}
16. 【双素数】双素数是指一对差值为2的素数。例如:3和5是一对双素数,5和7是一对双素数,而11和13也是一对双素数。编写程序找出小于1000的所有双素数。显示结果如下:
(3,5)
(5,7)
……
解析:这个题的难点在于如何保存前一个素数。我们可以采用以下的算法:首先令前一个数p1 = 2,第二个数p2从3开始递增,依次判断p2是否是素数,如果p2是素数那么进一步判断p2与p1的差值是否是2,如果是就打印结果;最后将p2的值赋值给p1(更新p1的值,因为p2是素数那么更新后的p1也就是素数了)。实现如下:
public class Test {
public static void main(String[] args) {
int p1 = 2;
for (int p2 = 3; p2 <= 1000; p2++)
if (isPrime(p2)) {
if (p2 - p1 == 2) {
System.out.println("(" + p1 + "," + p2 + ")");
}
p1 = p2;
}
}
private static boolean isPrime(double number) {
for (int i = 2; i <= number / 2; i++) {
if (number % i == 0) {
return false;
}
}
return true;
}
}
17. 根据currentTimeMillis输出年月日星期。
public class Test {
public static void main(String[] args) {
System.out.println(getTimeAndDate());
}
private static String getTimeAndDate() {
long totalMillis = System.currentTimeMillis();
int currentMills = (int) (totalMillis % 1000);
long totalSecond = totalMillis / 1000;
int currentSecond = (int) (totalSecond % 60);
int totalMinute = (int) (totalSecond / 60);
int currentMinute = totalMinute % 60;
int totalHour = totalMinute / 60;
int currentHour = (totalHour + 8) % 24;
int totalDay = totalHour / 24 + 1;
int week = (4 + totalDay - 1) % 7;
int year = 0;
for (year = 1970; totalDay > (isLeapYear(year) ? 366 : 365); year++) {
totalDay -= (isLeapYear(year) ? 366 : 365);
}
int month;
for (month = 1; totalDay > getNumberOfDaysInMonth(year, month); month++) {
totalDay -= getNumberOfDaysInMonth(year, month);
}
return "系统时间:" + year + "年" + month + "月" + totalDay + "日 "
+ currentHour + ":" + currentMinute + ":" + currentSecond + "."
+ currentMills + " " + getWeekName(week);
}
private static int getNumberOfDaysInMonth(int year, int month) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8
|| month == 10 || month == 12) {
return 31;
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
return 30;
} else {
return isLeapYear(year) ? 29 : 28;
}
}
private static String getWeekName(int week) {
String weekName = null;
switch (week) {
case 0:
weekName = "星期天";
break;
case 1:
weekName = "星期一";
break;
case 2:
weekName = "星期二";
break;
case 3:
weekName = "星期三";
break;
case 4:
weekName = "星期四";
break;
case 5:
weekName = "星期五";
break;
case 6:
weekName = "星期六";
break;
default:
break;
}
return weekName;
}
private static boolean isLeapYear(int year) {
return year % 400 == 0 || year % 4 == 0 && year % 100 != 0;
}
}
运行结果:
18.输出原来数组的逆序(注意并不改变原来的数组,仅仅是返回一个新的数组,新的数组中的元素是原来数组的逆序)。
public class Test {
public static void main(String[] args) {
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
System.out.println("原来的数组元素:");
for (int i : a) {
System.out.print(i + "\t");
}
int[] b = reverse(a);
System.out.println("\n逆序后数组元素:");
for (int i : b) {
System.out.print(i + "\t");
}
}
/** 返回原来数组的逆序 */
private static int[] reverse(int[] a) {
int[] result = new int[a.length];// 开辟和传入数组相同的空间
for (int i = 0, j = a.length - 1; i < a.length; i++, j--) {
result[i] = a[j];// 新数组与传入数组的对应关系(0,length-1)、(1,lenth-2)……
}
return result;
}
}
19. 选择排序和插入排序。
选择排序:
插入排序:
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
double[] a = { 2, 9, 5, 4, 8, 1, 6 };
double[] b = Arrays.copyOf(a, a.length);
System.out.println("原来的数组:");
for (double d : a) {
System.out.print(d + "\t");
}
selectionSort(a);
System.out.println("\n选择排序【升序排序】(先找出最小的):");
for (double d : a) {
System.out.print(d + "\t");
}
insertionSort(b);
System.out.println("\n插入排序【升序排序】(不断向已经排好序的数组中插入元素)");
for (double d : b) {
System.out.print(d + "\t");
}
}
/** 选择排序 */
private static void selectionSort(double[] list) {
for (int i = 0; i < list.length - 1; i++) {
// 在list[i]~list[list.length-1]之间找出最小值
double currentMin = list[i];
int currentMinIndex = i;
for (int j = i + 1; j < list.length; j++) {
if (currentMin > list[j]) {
currentMin = list[j];
currentMinIndex = j;
}
}
if (currentMinIndex != i) {
list[currentMinIndex] = list[i];
list[i] = currentMin;
}
}
}
/** 插入排序 */
private static void insertionSort(double[] list) {
for (int i = 1; i < list.length; i++) {
double currentElement = list[i];
// 把list[i]插入到list[0]~list[i-1]之间,这样list[0]~list[i]就排好序了
int j;
for (j = i - 1; j >= 0 && list[j] > currentElement; j--) {
list[j + 1] = list[j];
}
// 把当前元素插入到list[j+1]
list[j + 1] = currentElement;
}
}
}
在选择排序中,外层循环迭代执行以寻找list[1]~list[list.length-1]列表中的最小值,然后将它和list[i]互换。变量i的初值是0,最外层的每次迭代完成之后,list[i]都被放置到正确的位置。
在插入排序中,外层循环获取已经排好序的子数列list[0~i-1],内层循环将list[i]插入到list[0]~list[i-1]的子数列中。为了将list[i]插入list[0]~list[i-1],需要将list[i]存储在一个名为currentElement的变量中。如果list[i-1]>currentElement,就需要将list[i-1]移到list[i];如果list[i-2]>currentElement,就需要将list[i-2]移动到list[i-1],依此类推,直到list[i-k]<=currentElement或者k>i(传递的是排好序的数列的第一个元素)。将currentElement赋值给list[i-k+1]。例如:为了将4插入到{2,5,9}中,因为9>4,需要将list[2](9)移动到list[3],又因为5>4,需要将list[1](5)移动到list[2],最后将currentElement(4)移动到list[1],如图所示:
20. 【豆机】,也称为梅花瓶或者高尔顿瓶,是一个用来做统计实验的设备,是一个三角形形状的均匀放置钉子(或者钩子)的直立板子,如图所示: