Page 25
实践题1.24
题目描述:素数除了1和它本身没有其他因子(1不是素数,最小素数是2)
问题1. 写一个程序判断正整数N是不是素数?
问题2. 如果N是一个非常大的整数,如何判断?
// 实践题1.24问题1答案
public static boolean isPrime(int num) {
boolean flag = true;
if (num <= 1) {
flag = false;
}else {
for (int i = 2; i < num; i++) { // 循环条件可优化为 i <= Math.sqrt(num)
if (num % i == 0) {
flag = false;
}
}
}
return flag;
}
问题2解析:
如何判定一个大整数是否为素数
// 实践题1.24问题2答案
// 正在研究解决方案
实践题1.26
题目描述:对于一个规模为N的数组,如果有一个元素出现大于N/2次,则称其为过半元素,因此一个数组中最多只有一个过半元素。
问题:给出一个算法,如果数组中存在过半元素的话就找出来,如果不存在,则给出报告。
// 实践题1.26答案:该算法对存在过半元素的数组有效;对不存在过半元素的数组无效,无法给出报告。
public class FindOverHalfNumber {
public static int findTheNumber(int[] array) {
int length = array.length;
int theNumber = array[0];
int thisTime = 0; // 标记次数
for (int i = 0; i < length; i++) {
if (thisTime == 0) {
theNumber = array[i];
thisTime++;
} else {
if (array[i] == theNumber) { // 与前一个数相同则标记次数加一
thisTime++;
} else { // 与前一个数不同则标记次数减一
thisTime--;
}
}
}
return theNumber;
}
public static void main(String[] args) {
int[] array = {1,0,1,2,3,1,1,3}; System.out.println(FindOverHalfNumber.findTheNumber(array));
}
}
实践题1.27
题目描述:输入是一个N*N的矩阵,可以完全放到内存中,每行从左至右递增,每列从上至下递增,给出一个算法判断X是否在这个矩阵里。
暴力查找:遍历矩阵,我就不贴代码了。
二分查找:先从矩阵开始从上到下二分查找X所在的行,再在该行查找X,存在返回true,不存在则返回false
// 实践题1.27答案(二分查找)
// array is two_dimension array which has N lines and N columns
public static boolean findNumber(int[][] array, int number) {
int lineStart = 0;
int lineEnd = array.length-1;
int columnStart = 0;
int columnEnd = array[0].length-1;
int lineMid = 0;
boolean flag = false;
// 先寻找目标元素所在的行,start==end时停止,找到该行
while (lineStart < lineEnd) {
lineMid = (lineStart + lineEnd)/2; // 中间行
if (number == array[lineMid][0]) {
flag = true;
break;
} else if (number < array[lineMid][0]) {
lineEnd = lineMid -1; // 行首元素在行首最小
} else if(number >= array[lineMid][0] && number < array[lineMid+1][0]){
lineStart = lineMid;
break; //找到该行
} else {
lineStart = lineMid + 1;
}
}
// 再查找目标元素的列
if (flag == false) {
int resultLine = lineStart;
int columnMid = 0;
while (columnStart <= columnEnd) {
columnMid = (columnStart + columnEnd)/2;
if (number < array[resultLine][columnMid]) {
columnEnd = columnMid-1;
} else if(number > array[resultLine][columnMid]){
columnStart = columnMid+1;
} else {
flag = true;
break;
}
}
}
return flag;
}
根据矩阵性质进行优化:从上至下递增,从左至右递增。从矩阵最后一行第一个元素开始查找(该元素在所在行最小在所在列最大),小于目标数X则在该行向右查找,大于目标数X则在该列向上查找,直到找到X或到达第一行最后一列为止。
// 实践题1.27答案,最优解
public static boolean findNumber2(int[][] array, int number) {
int lineNum = array.length;
int columnNum = array[0].length;
boolean flag = false;
for (int i = lineNum-1, j = 0; i >= 0 && j < columnNum;) {
if (array[i][j] == number) {
flag = true;
break;
} else if (array[i][j] < number) {
j++;
} else {
i--;
}
}
return flag;
}
实践题1.28
问题描述:设计一个有效算法,将一个正整数类型的数组array作为输入,并计算:
1. 对于j >= i,array[j] + array[i]的最大值
2. 对于j >= i,array[j] - array[i]的最大值
3. 对于j >= i,array[j] * array[i]的最大值
4. 对于j >= i,array[j] / array[i]的最大值
// 实践题1.26答案
public class ArrayUtils {
// 问题1:寻找两个最大的数
public static int maxSumOfTwoEle(int[] array) {
int max = 0;
int preMax = 0;
if (array[0] > array[1]) {
max = array[0];
preMax = array[1];
} else {
max = array[1];
preMax = array[0];
}
for (int i = 2; i < array.length; i++) {
if (array[i] >= max) {
preMax = max;
max = array[i];
} else if (array[i] < max && array[i] >= preMax) {
preMax = array[i];
}
}
return max+preMax;
}
// 问题2:寻找最大的数和最小的数(不合题意,正在努力修改中...)
public static int maxDifferenceOfTwoEle(int[] array) {
int max = 0;
int min = 0;
if (array[0] > array[1]) {
max = array[0];
min = array[1];
} else {
max = array[1];
min = array[0];
}
for (int i = 2; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
} else if (array[i] < min) {
min = array[i];
}
}
return max-min;
}
public static void main(String[] args) {
int[] array = {-1,-2,-3,-4,-5,-6,-7,7,6,5,4,3,2,1};
System.out.println(ArrayUtils.maxSumOfTwoEle(array));
System.out.println(ArrayUtils.maxDifferenceOfTwoEle(array));
}
}
程序设计题1.29
问题描述:埃拉托色尼筛子是一种用来计算所有小于等于N的素数的方法,写一个程序实现该算法。
算法思想:先建立一个从整数2到N的表格,从表格中选出最小的质数2开始,计数器加一,然后删去表格中2的倍数,再从表格中选出最小的质数3,计数器加一,然后删去表格中3的倍数,再依次选出最小的质数,计数器加一,删去其倍数,直到该质数(记为j)的平方刚好大于N为止,最后再计算表格中j之后的质数个数加到计数器中即可,该计数器即为所求。
public class FilterPrime {
public static int filter(int number) {
BitSet b = new BitSet(number + 1);
int count = 0;
int i = 2; // 设置BitSet:每一位代表true或false,节省空间
int j = 2; // 寻找质数的倍数
for ( ; i <= number; i++){
b.set(i);
}
while (j * j <= number) {
if (b.get(j)) {// 如果该位是质数
count++;
int k = 2 * j;
while (k <= number) {
b.clear(k);
k += j;// k是i的倍数,将第k位移除
}
}
j++;
}
while (j <= number) {// 计算sqrt(number)后面的数
if (b.get(j))
count++;
j++;
}
return count;
}
public static void main(String[] args) {
System.out.println(FilterPrime.filter(5));
}
}