前言
整本《算法》Java版的题解已经托管在Github上:https://github.com/Mereder/Algorithms_4th ,大家根据README.md的导航可以迅速定位章节。
书中代码用到了很多《算法》官方提供的依赖:https://algs4.cs.princeton.edu/home/ 大家可以去官网多逛逛,图书章节配合官网内容一起看效果很好。
欢迎大家站内私聊交流!小白一枚,还请前辈们多多指教!
本部分内容全部以代码形式展示,编译器为IDEA 2018版,Java版本为1.8.0_151,系统为Windows7 。
内容(1.1节)
1.1.1
/** * 给出以下表达式的值 */ public class E_1 { public static void main(String[] args) { System.out.println((0 + 15) / 2); System.out.println(2.0e-6 * 100000000.1); System.out.println( true && false || true && true); } }
1.1.2
/** * 给出以下表达式的类型和值 */ public class E_2 { public static void main(String[] args) { System.out.println((1 + 2.236) / 2); System.out.println(1 + 2 + 3 + 4.0); System.out.println(4.1 >= 4); System.out.println(1 + 2 + "3"); //1+2 =3 (int ) 3+"3" convert to string "33" } }
1.1.3
import java.util.Scanner; /** * 编写一个程序,从命令行得到三个整数参数,如果他们都相等打印equal * 否则打印 not equal */ public class E_3 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int a = scanner.nextInt(); int b = scanner.nextInt(); int c = scanner.nextInt(); if (a == b && b == c){ System.out.println("equal"); } else System.out.println("not equal"); } }
1.1.4
/** * 以下语句有什么问题 */ public class E_4 { public static void main(String[] args) { int a = 2,b=3,c=0; /** * Cannot resolve symbol 'then' * */ //if (a > b) then c = 0; // if a > b {c = 0} //if() if(a > b) c = 0; //bingo // if (a > b) c = 0 //Lack of semicolons behind c = 0 // else b= 0; } }
1.1.5
import java.util.Scanner; /** * 编写一段程序,如果double类型的x和y都严格位于0和1之间打印true * 否则打印false */ public class E_5 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); double x = scanner.nextDouble(); double y = scanner.nextDouble(); if (x > 0.0 && x < 1.0 && y > 0.0 && y < 1.0 ){ System.out.println("true"); } else System.out.println("false"); } }
1.1.6
import edu.princeton.cs.algs4.StdOut; public class E_6 { public static void main(String[] args) { int f = 0; int g = 1; for (int i = 0; i <= 15 ; i++) { StdOut.println(f); f = f + g; g = f - g; } } } /*** print result: * 0 * 1 * 1 * 2 * 3 * 5 * 8 * 13 * 21 * 34 * 55 * 89 * 144 * 233 * 377 * 610 * * * * * */
1.1.7
/**result: * 3.00009 * 499500 * 10000 */ public class E_7 { public static void a(){ double t = 9.0; while (Math.abs(t - 9.0/t) > .001){ t = (9.0/t + t) / 2.0; } System.out.printf("%.5f\n",t); } public static void b(){ int sum = 0; for (int i = 1; i < 1000; i++) { for (int j = 0; j < i; j++) { sum++; } } System.out.println(sum); } public static void c(){ int sum = 0; for (int i = 1; i < 1000; i *= 2) { for (int j = 0; j < 1000; j++) { sum++; } } System.out.println(sum); } public static void main(String[] args) { a(); b(); c(); } }
1.1.8
/**result: * b char * 197 ASCII b = 98 c = 99 单个字符不能跟字符串一样拼接 自动转换为int类型进行相加 * e 'a' = 97 基础上 +4 得到 101 ASCII中 为 e */ public class E_8 { public static void main(String[] args) { System.out.println('b'); System.out.println('b' + 'c'); System.out.println((char)('b' + 'c')); //test System.out.println((char)('a'+ 4)); } }
1.1.9
import java.util.Scanner; /** * 编写一段代码,将一个正整数用二进制表示转换为一个String类型的值s */ public class E_9 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int M = N; String s = ""; while (N > 0){ int a = N % 2; s += a; N /= 2; } System.out.println(s); System.out.println(toBianryString(M)); } /** * @param N * @return BinaryString * Official method from Algs4 book */ public static String toBianryString(int N){ String s = ""; for (int n = N; n > 0 ; n /= 2) { s = (n % 2) +s; } return s; } }
1.1.10
/**Error Message: * Variable 'a' might not have been initialized * * solution: * 没有用new 为a[] */ public class E_10 { public static void main(String[] args) { int a[] = new int[10]; for (int i = 0; i < 10; i++) { //unexpected token a[i] = i * i; } } }
1.1.11
import edu.princeton.cs.algs4.StdRandom; /** * 编写一段代码,打印出一个二维布尔数组的内容。其中 使用*表示真,空格表示假 * 打印出行号和列号 * * 注意:格式控制问题 */ public class E_11 { public static void main(String[] args) { int row = 5; int col = 5; boolean[][] test = new boolean[row][col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { test[i][j] = StdRandom.bernoulli(0.5); } } for (int i = 0; i < 5; i++) { System.out.printf(" %d",i); } System.out.println(); for (int i = 0; i < row; i++) { System.out.printf("%d",i); for (int j = 0; j < col; j++) { if (j == 0){ if (test[i][j]) System.out.printf("*"); else System.out.printf(" "); } else { if (test[i][j]) System.out.printf(" *"); else System.out.printf(" "); } } System.out.println(); } } }
1.1.12
/** * 以下代码段会打印出什么结果 */ public class E_12 { public static void main(String[] args) { 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]]; } /** * 应该是输出 a[i] 打印i没啥意义啊 */ for (int i = 0; i < 10; i++) { System.out.println(a[i]); } } }
1.1.13
/** * 编写一段代码,打印出一个M行N列的二维数组的转置 * */ public class E_13 { public static void main(String[] args) { int M = 5; int N = 8; int[][] original = new int[M][N]; //M行N列初始化 for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { original[i][j] = StdRandom.uniform(1,10); System.out.printf("%d ",original[i][j]); } System.out.println(); } //转置输出 for (int i = 0; i < N; i++) { for (int j = 0; j < M ; j++) { System.out.printf("%d ",original[j][i]); } System.out.println(); } } }
1.1.14
import java.util.Scanner; /** * 编写一个静态方法lg() ,接受一个整型参数N,返回不大于 以2为底N的对数 的最大整数。 * 不使用Math库 * * * 整型参数N 确保了 以2为底N的对数 是大于等于0 的 * 确保 2^x 小于等于 N; */ public class E_14 { public static int lg(int N){ int sum = 1; int i = 0; while(sum <= N){ sum *= 2; i++; } i = i-1; return i; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int result = lg(N); System.out.println(result); } }
1.1.15
import edu.princeton.cs.algs4.StdRandom; /** * 编写一个静态方法histogram() 接受一个整型数组a[] 和一个整数M为参数 * 返回一个大小为 M 的数组,其中第i个元素的值为整数i在参数数组中出现的次数。 * 如果a[] 中的值均在 0到M-1 之间,返回数组中的所有元素之和应该和a.length()相等。 */ public class E_15 { public static int[] histogram(int[] a,int M){ int[] result = new int[M]; for (int i = 0; i < M; i++) { result[i] = 0; } for (int i = 0; i < a.length; i++) { result[a[i]]++; } return result; } public static void main(String[] args) { int num = 10; int M = 20; int[] a = new int[num]; for (int i = 0; i < num; i++) { a[i] = StdRandom.uniform(0,M-1); } int[] result = histogram(a,M); int sum = 0; for (int i = 0; i < result.length; i++) { sum += result[i]; System.out.println(result[i]); } System.out.println("返回数组元素相加之和为:"+sum); System.out.println("数组a长度为:"+a.length); } }
1.1.16
/** * 给出exR1(6) 的 返回值 * * Result:311361142246 */ public class E_16 { public static String exR1(int n){ if (n <= 0) return ""; return exR1(n-3)+ n + exR1(n-2) + n; } public static void main(String[] args) { int n = 6; System.out.println(exR1(n)); } }
1.1.17
/** * 找出下列递归函数的问题 * * solution: * 不满足递归调用条件: * 必定要有一个明确的结束递归的条件。(本题看似有 n <= 0 但是该条件对递归过程无约束) * 所以本题函数会循环往复直到发生StackOverFlow */ public class E_17 { public static String exR2(int n ){ String s = exR2(n-3) + n + exR2(n-2) + n; if (n <= 0) return ""; return s; } public static void main(String[] args) { int n = 6; System.out.println(exR2(6)); } }
1.1.18
/** * mystery(2,25)== 50 * mystery(3,11) == 33 * mystery (a,b) 给出的计算结果是 a*b * mystery (a,b) 给出的计算结果是 a^b */ public class E_18 { /** * @param a * @param b * @return a*b */ public static int mystery(int a,int b){ if (b == 0) return 0; if (b % 2 == 0) return mystery(a+a,b/2); return mystery(a+a,b/2) + a; } /** * @param a * @param b * @return a^b */ public static int mystery_1(int a,int b){ if (b == 0) return 1; if (b % 2 == 0) return mystery_1(a*a,b/2); return mystery_1(a*a,b/2) * a; } public static void main(String[] args) { int a = 4; int b = 5; int result = mystery_1(a,b); System.out.println(result); } }
1.1.19
import edu.princeton.cs.algs4.Queue; import edu.princeton.cs.algs4.StdOut; /** * 斐波那契数列 * * 更好的实现,用数组保存已经计算过的值: * 原理:不使用数组的时候,计算一个F(10)需要依次递归F(9)F(8)……F(1)F(0) * 使用数组时候,可以保存之前计算过的数值,F(10) = F(9) + F(8) 而F(9)与F(8) * 之前计算过,并进行了保存,所以可以迅速得出F(10)的结果。 * * 顺便拓展下 队列实现方式 和 循环实现方式 */ public class E_19 { /** * 递归实现 空间O(N)递归工作栈 时间 O( N^2 ) * @param N * @return F(N); */ public static long F(int N){ if (N == 0) return 0; if (N == 1) return 1; return F(N-1) + F(N-2 ); } /** * 数组实现过程空间O(N) 时间 O(N) * @param N * @return F(N) */ public static long F_array(int N){ long[] array = new long[N+1]; array[0] = 0; array[1] = 1; for (int i = 2; i < N+1 ; i++) { array[i] = array[i-1] + array[i-2]; } return array[N]; } /**循环解决 实际上是运用 三个变量进行的 不断 相加 换位置 * O(1)空间复杂度 O(N) 时间复杂度 * @param N * @return F(N) */ public static long F_loop(int N){ long first = 0; long second = 1; long temp = 0; for (int i = 0; i < N-1;i++){ temp = first + second; first = second; second = temp; } return temp; } /** * 不知道java里面如何按序取到将要出队的前两个元素 * 这里耍了个心机 就是 入队元素 = 出队元素 + 队头对头元素 * 实际过程跟循环有点像。 * 空间O(1) 时间O(N) * @param N * @return F(N) */ public static long F_Queue(int N){ Queue<Long> QL = new Queue<Long>(); QL.enqueue((long)0); QL.enqueue((long)1); for (int i = 0; i < N-1 ; i++) { QL.enqueue(QL.dequeue()+ QL.peek()); } QL.dequeue(); return QL.peek(); } public static void main(String[] args) { for (int N = 0;N < 10;N++){ StdOut.println(N + " " + F(N)); } System.out.println(F_array(9)); System.out.println(F_loop(9)); System.out.println(F_Queue(9)); } }
1.1.20
/** * 编写一个递归的静态方法计算 ln(N!) 的值 */ public class E_20 { public static double calculate(int N){ if (N == 1 || N == 0) return 1; return N * calculate(N-1); } public static void main(String[] args) { int N = 5; double result= Math.log(calculate(N)); // System.out.println(calculate(N)); System.out.printf("%.5f\n",result); } }
1.1.21
import edu.princeton.cs.algs4.StdIn; /** * 编写一段程序,从标准输入按行读取数据,其中每行包含一个名字和两个整数。 * 然后用printf打印一张表格,每行的若干列数据包含名字、两个整数和第一个 * 整数除以第二个整数的结果,精确到小数点后三位。 */ public class E_21 { public static void main(String[] args) { int N = 3; //数据组数 String[] name = new String[N]; int[] a = new int[N]; int[] b = new int[N]; for (int i = 0; i < N; i++) { String[] content = StdIn.readLine().split(" "); // 按行读取 name[i] = content[0]; a[i] = Integer.parseInt(content[1]); b[i] = Integer.parseInt(content[2]); } System.out.printf("%4s\t|%4s\t|%4s\t|%4s\n","姓名","整数a","整数b","计算"); for (int i = 0; i < N; i++) { System.out.printf("%4s\t|%4d\t|%4d\t|%.3f\n",name[i],a[i],b[i],a[i]/(b[i]*1.0)); } } }
1.1.22
/** * 使用rank()的递归方法重现实现BinarySearch() 并跟踪该方法的调用, * 每当该方法被调用时,打印出它的参数lo和hi并按照递归的深度缩进。 * hint:为递归方法添加一个参数来保存递归的深度 */ public class E_22 { public static int BinarSearch(int key,int[] a){ return rank(key,a,0,a.length-1,0); } private static int rank(int key, int[] a, int lo, int hi,int depth) { int para = depth; while(para > 0){ System.out.print(" "); para--; } System.out.println(lo + " " + hi); if (lo > hi) return -1; int mid = lo + ( hi - lo )/ 2; if (key < a[mid] ) return rank(key,a,lo,mid-1,++depth); else if (key > a[mid] ) return rank(key,a,mid+1,hi,++depth); else return mid; } public static void main(String[] args) { int a[] = {1,2,3,4,5,6,7,8,9,10}; int result = BinarSearch(2,a); System.out.println(result); } }
1.1.23
import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdRandom; import java.util.Arrays; /** * 为BinarySearch 的测试用例添加一个参数: * + 打印出标准输入中不在白名单上的值 * - 打印出标准输入中在白名单上的值 */ public class E_23 { public static int BinarySearch(int key,int[] a){ int lo = 0; int hi = a.length-1; while (lo <= hi){ int mid = lo + (hi - lo) / 2; if (key < a[mid]) hi = mid - 1; else if (key > a[mid]) lo = mid + 1; else return mid; } return -1; } public static void main(String[] args) { int N = 10; int[] whiteList = new int[N]; for (int i = 0; i < N; i++) { whiteList[i] = StdRandom.uniform(1,20); } Arrays.sort(whiteList); for (int i = 0; i < N; i++) { System.out.printf("%d ",whiteList[i]); } System.out.println(); System.out.println("输入操作 '+' or '-'"); char ops = StdIn.readChar(); StdIn.readLine(); System.out.println("输入测试数:"); String[] keys = StdIn.readLine().split(" +"); for (int i = 0; i < keys.length; i++) { if (BinarySearch(Integer.parseInt(keys[i]),whiteList) < 0 && ops == '+'){ System.out.printf("%s ", keys[i]); } else if (BinarySearch(Integer.parseInt(keys[i]),whiteList) > 0 && ops == '-'){ System.out.printf("%s ",keys[i]); } } System.out.println(); } }
1.1.24
/** * 给出 使用欧几里得算法计算 105 和 24的最大公约数的过程中得到的一系列 * p 和 q 的值。拓展 该算法中的代码得到一个程序Euclid,从命令行接受两个 * 参数,计算他们的最大公约数并打印出每次调用递归方法时的两个参数。使用 * 你的程序计算1111111和1234567 的最大公约数 */ public class E_24 { public static int Euclid(int a,int b){ if (a < b){ System.out.println(b + " " +a); if (b % a == 0){ return a; } else{ return Euclid(a,b % a); } } else { System.out.println(a + " " +b); if (a % b == 0) { return b; } else{ return Euclid(b, a % b); } } } public static void main(String[] args) { System.out.println(Euclid(105,24)); System.out.println(Euclid(1111111,1234567)); } }
1.1.25
使用数学归纳法证明欧几里得算法能够计算任意一对非负整数p和q的最大公约数
1.1.26
/** * 将三个数字排序 * 假设 a、b、c和t 都是同一种原始数字类型的变量。 * 证明以下代码能够将a,b,c按照升序排列 */ public class E_26 { public static void main(String[] args) { int a = 5; int b = 4; int c = 3; int t ; if(a > b ){ t = a; a = b; b = t; } if (a > c){ t = a; a = c; c = t; } if (b > c){ t = b; b = c; c = t; } System.out.println(a +" "+b+" "+c); } }
1.1.27
/** * 二项分布: * 估计用以下代码计算binomial(100,50,0.25) 将会产生的递归调用次数 * * 将计算过的值保存在数组中,并给出一个更好的实现 */ public class E_27 { public static int count = 0; public static double array[][]; public static double binomial(int N,int k,double p){ count ++; System.out.println(count); if (N == 0 && k == 0) return 1.0; if (N < 0 || k < 0) return 0.0; return (1.0 - p)*binomial(N-1,k,p) + p * binomial(N-1,k-1,p); } public static double binomial_array(int N,int k,double p){ array = new double[N+1][k+1]; for (int i = 0; i <= N; i++) { for (int j = 0; j <= k; j++) { array[i][j] = -1; } } return calculate(N,k,p); } private static double calculate(int N,int k,double p) { count++; if (N == 0 && k == 0) { // array[0][0] = 1.0; return 1.0; } if (N < 0 || k < 0) return 0.0; if (array[N][k] == -1){ array[N][k] = (1.0 - p)*calculate(N-1,k,p) + p * calculate(N-1,k-1,p); } return array[N][k]; } public static void main(String[] args) { // double result = binomial(5,1,0.25); double result1 = binomial_array(100,50,0.25); System.out.println(count); System.out.println(result1); } }
1.1.28
import edu.princeton.cs.algs4.StdRandom; import java.util.*; /** * 删除重复元素: * 修改BinarySearch 类中的测试用例来删去排序后白名单中的所有重复元素 */ public class E_28 { private static int count; public static int BinarySearch_(int key,int[] a){ int lo = 0; int hi = a.length-1; while(lo <= hi){ int mid = lo + (hi - lo) / 2; if (key < a[mid]) hi = mid - 1; else if (key > a[mid]) lo = mid + 1; else return mid; } return -1; } /** * @param whiteList * @return Nozero[] * s使用数组方法处理 较为繁琐 */ public static int[] delete_same1(int[] whiteList) { int[] newlist = new int[whiteList.length]; int i = 0; int j = 0; newlist[j] = whiteList[i]; i++; while (i < whiteList.length){ if (whiteList[i] != newlist[j]){ j++; newlist[j] = whiteList[i]; i++; } else i++; } count = j+1; int Nozero[] = Arrays.copyOf(newlist,count); return Nozero; } /** * @param whiteList * 创建一个集合,遍历数组并放入集合,通过contains()方法判断是否已经存在 * 然后用toArray转成数组 */ public static void delete_same2(int[] whiteList){ List list = new ArrayList(); for(int i=0;i < whiteList.length;i++){ if(!list.contains(whiteList[i])){ list.add(whiteList[i]); } } Object[] newArray = list.toArray(); for(int i=0;i<newArray.length;i++){ System.out.printf("%d ",newArray[i]); } } /** * @param arr * @return Object[] objects * 最简单的方法就是利用Set集合无序不可重复的特性进行元素过滤 */ public static Object[] delete_same3(int[] arr){ //实例化一个set集合 Set set = new HashSet(); //遍历数组并存入集合,如果元素已存在则不会重复存入 for (int i = 0; i < arr.length; i++) { set.add(arr[i]); } //返回Set集合的数组形式 return set.toArray(); } public static void main(String[] args) { int N = 10; int[] whiteList = new int[N]; for (int i = 0; i < N; i++) { whiteList[i] = StdRandom.uniform(1,20); } Arrays.sort(whiteList); System.out.println("方法1:"); int[] Nozero = Arrays.copyOf(delete_same1(whiteList),count); for (int i = 0; i < Nozero.length; i++) { System.out.printf("%d ",Nozero[i]); } System.out.println("\n方法二:"); delete_same2(whiteList); System.out.println("\n方法三:"); Object[] objects = delete_same3(whiteList); Arrays.sort(objects); for (Object object:objects) { System.out.printf("%d ",object); } System.out.println("二分查找结果:"); System.out.println(BinarySearch_(1,whiteList)); } }
1.1.29
import java.util.Arrays; /** * 等键值: 为BinarySearch类添加一个静态方法 rank(),它接受一个键和一个整型有序数组 * (可能存在重复键值)作为参数并返回数组中小于该键的元素数量,以及一个类似的方法count() * 来返回数组中等于该键的元素数量,以及一个类似的方法count()来返回数组中等于该键的元素数量。注意:如果i * 和j分别是rank(key,a)和count(key,a)的返回值,那么a[i...i+j-1]就是数组中所有和key相等的元素 * */ public class E_29 { public static int count(int key,int[] a){ int count = 0; for (int i = 0; i < a.length; i++) { if (a[i] == key) count++; } return count; } public static int rank(int key,int[] a){ int rank = 0; for (int i = 0; i < a.length; i++) { if (a[i] < key){ rank++; } } return rank; } public static void main(String[] args) { int N = 10; int[] whiteList ={17 ,11, 9 ,2 ,18, 5, 14, 11, 6 ,11}; Arrays.sort(whiteList); int i = 0; //rank 返回 int j = 0; //count 返回 i = rank(11,whiteList); j = count(11,whiteList); System.out.println(i+" "+ j); //输出a[i]...a[i+j-1]的相同键值 for (int k = i; k <= i+j-1; k++) { System.out.println(whiteList[k]); } } }
1.1.30
/** * 数组练习: * 编写一段程序,创建一个N*N的布尔型数组a[][]。其中当i和j互质时(没有相同因子) * a[i][j]为true,否则为false * * 判断互质:最大公约数为1 互质,否则不互质 */ public class E_30 { public static boolean relatively_prime(int a,int b){ if (gcd(a,b) == 1) return true; else return false; } public static int gcd(int a, int b) { if (a < b) { int t = b; b = a; a = t; } if(b == 0) return a; else return gcd(b,a%b); } public static void main(String[] args) { int N = 10; boolean[][] a = new boolean[N][N]; for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (relatively_prime(i,j)) a[i][j] = true; else a[i][j] = false; } } System.out.println(""); } }
1.1.31(未完成)
/** * 随机链接: * 编写一段程序从命令行接受一个整数N和double值p作为参数在一个圆上画出大小为0.05且间距相等的N个点,然后将 * 每对点按照概率p用灰线连接 */ public class E_31 { public static void main(String[] args) { } }
1.1.32
import edu.princeton.cs.algs4.StdDraw; import edu.princeton.cs.algs4.StdRandom; /** * 直方图: * 假设标准输入中有一系列double值。编写一段程序,从命令行接受一个整数N和 * 两个double值l和r,将(l,r)分为N段并用StdDraw 画出输入流中的值落入每段 * 的数量的直方图。 */ public class E_32 { public static void main(String[] args) { int N = 10; double l = 0.3; double r = 0.8; //标准输入doubles int numdouble = 50; double[] doubles = new double[numdouble]; for (int i = 0; i < numdouble; i++) { doubles[i] = StdRandom.uniform(l,r); } double divi = (r-l) / N; int count[] = new int[N]; for (int i = 0; i < numdouble; i++) { count[(int)((doubles[i]-l)/divi)]++; } for (int i = 0; i < N; i++) { System.out.println(count[i]); } for (int i = 0; i < N; i++) { double x = l+i*divi; double y = count[i]/2.0 /10.0; //保证横纵坐标比例 加上一个 /10.0 double rw = 0.5 * divi; double rh = count[i] / 2.0 /10.0;//保证横纵坐标比例 加上一个 /10.0 StdDraw.filledRectangle(x,y,rw,rh); } } }
1.1.33(Matrix 矩阵库)
import edu.princeton.cs.algs4.StdRandom; /** * 矩阵库:编写一个Matrix库并实现以下API * =================================================== * public class Matrix * --------------------------------------------------- * static double dot(double[]x double[] y) 向量点乘 * static double[][] mult(double[][] a,double[][] b) 矩阵之积 * static double[][] transpose(double[][] a) 矩阵转置 * static double[] mult(double[][] a,double[] x) 矩阵向量积 * static double[] mult(double[]y, double[][] a) 向量矩阵积 */ public class E_33 { /** * @param x 向量x数组 * @param y 向量y数组 * @return dot 点乘结果 */ public static double dot(double[]x , double[]y){ double dot = 0; if (x.length == y.length) { for (int i = 0; i < x.length; i++) { dot += x[i] * y[i]; } return dot; } else return dot; } /**矩阵乘法 * @param a * @param b * @return */ public static double[][] mult(double[][] a,double[][] b){ int arow = a.length; int acol = a[0].length; int brow = b.length; int bcol = b[0].length; if (acol != brow) return null; else { double[][] temp = new double[arow][bcol]; for (int i = 0; i < arow; i++) { for (int j = 0; j < bcol; j++) { for (int k = 0; k < acol; k++) { temp[i][j] += a[i][k]*b[k][j]; } } } return temp; } } /** 矩阵转置 * @param a * @return */ public static double[][] transpose(double[][] a){ int row = a.length; int col = a[0].length; double[][] temp = new double[row][col]; for (int i = 0; i < row ; i++) { for (int j = 0; j < col; j++) { temp[i][j] = a[j][i]; } } return temp; } /**矩阵 向量 乘法 * 右向量 -》 列向量 * @param a * @param x * @return */ public static double[] mult(double[][] a,double[] x){ int arow = a.length; int acol = a[0].length; int xlen = x.length; if (acol == xlen){ double[] temp = new double[arow]; for (int i = 0; i < arow; i++) { for (int j = 0; j < xlen; j++) { temp[i] += a[i][j] * x[j]; } } return temp; } else return null; } /**向量 矩阵乘法 * 左向量-》行向量 * @param y * @param a * @return */ public static double[] mult(double[]y, double[][] a){ int ylen = y.length; int arow = a.length; int acol = a[0].length; if (ylen == arow){ double[] temp = new double[acol]; for (int i = 0; i < acol ; i++) { for (int j = 0; j < arow; j++) { temp[i] += y[j] * a[j][i]; } } return temp; } else return null; } public static void main(String[] args) { int row = 3; int col = 3; double[][] a = new double[row][col]; double[][] b = new double[col][row+1]; double [] x = new double[row]; double [] y = new double[row]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { a[i][j] = StdRandom.uniform(1.0,10.0); } } for (int i = 0; i < col; i++) { for (int j = 0; j < row+1; j++) { b[i][j] = StdRandom.uniform(1.0,10.0); } } for (int i = 0; i < x.length; i++) { x[i] = StdRandom.uniform(1.0,10.0); y[i] = StdRandom.uniform(1.0,10.0); } System.out.println("count dot"); System.out.println(dot(x,y)); System.out.println("multiply a[][] b[][]"); for (int i = 0; i < a.length; i++) { for (int j = 0; j < b[0].length; j++) { System.out.printf("%.2f ",mult(a,b)[i][j]); } System.out.println(); } System.out.println("transpose "); for (int i = 0; i < a[0].length; i++) { for (int j = 0; j < a.length; j++) { System.out.printf("%.2f ",transpose(a)[i][j]); } System.out.println(); } System.out.println("mult a[][] x[] "); for (int i = 0; i < a.length; i++) { System.out.printf("%.2f ",mult(a,x)[i]); } System.out.println(); System.out.println("mult y[] a[][] "); for (int i = 0; i < a[0].length; i++) { System.out.printf("%.2f ",mult(y,a)[i]); } System.out.println(); } }
1.1.34
import edu.princeton.cs.algs4.StdIn; import java.util.Arrays; /**写在前面: * 本题各个方法或者实现 都是单独的,如果考虑整体操作的话,只需要一次标准输入即可,此时需要一个数组保存 * 标准输入的结果,然后再进行各个操作。 * 过滤: * 以下哪些任务需要(比如在数组中)保存标准输入中的所有值? * 2 6 7 8 * 哪些可以被实现为一个过滤器且仅使用固定数量的变量和固定大小的数组(和N无关)? * 1 两个变量 4 一个变量 5一个变量 3 使用k大小数组 * 4 和 5可以写在一个过滤器里面 * 在每个问题中,输入都来自于标准输入且含有N个0到1的实数。 * 1 打印出最大和最小的数 * 2 打印出所有数的中位数 * 3 打印出第k小的数,k<100 * 4 打印出所有数的平方和 * 5 打印出N个数的平均值 * 6 打印出大于平均值的数的百分比 * 7 将N个数按照升序打印 * 8 将N个数按照随机顺序打印 */ public class E_34 { /**1 打印出最大和最小的数 * 需要两个变量 * @param N */ public static void max_min(int N){ double max = 0.0; double min = 1.0; for (int i = 0; i < N; i++) { double value = StdIn.readDouble(); if (value >= max) max = value; if (value <= min) min = value; } System.out.println("最大值:"+max); System.out.println("最小值:"+min); } /** 打印出所有数的中位数 * 需要保存整个数组 * @param N */ public static void Median(int N){ double Median = 0.0; double[] sort = new double[N]; for (int i = 0; i < N; i++) { sort[i] = StdIn.readDouble(); } Arrays.sort(sort); if (N%2 == 0){ Median = (sort[N/2]+sort[N/2-1])/2.0; } else { Median = sort[N/2]; } System.out.println("中位数为:"+Median); } /**第K小的数 效率不高使用K大小数组 * 效率高的话 还是用全数组 排一次序 * @param N * @param k */ public static void Kth_minum(int N,int k){ double[] kth_minum = new double[k]; for (int i = 0; i < k; i++) { kth_minum[i] = StdIn.readDouble(); } Arrays.sort(kth_minum); for (int i = k; i < N; i++) { double value = StdIn.readDouble(); if (value < kth_minum[k-1]){ kth_minum[k-1] = value; Arrays.sort(kth_minum); } else continue; } System.out.println("第K小的数为:"+kth_minum[k-1]); } /**打印出所有数的平方和 * 打印出N个数的平均值 * @param N */ public static void Ave_Quadraticsum(int N){ double Ave= 0.0; double Quadraticsum = 0.0; for (int i = 0; i < N; i++) { double value = StdIn.readDouble(); Ave += value; Quadraticsum += value*value; } System.out.println("平均数为:"+(Ave/N)); System.out.println("平方和为:"+Quadraticsum); } /** 先求平均数 再就百分比 * @param N */ public static void LargerThanAverage(int N){ double Ave = 0.0; double value[] = new double[N]; for (int i = 0; i < N; i++) { value[i] = StdIn.readDouble(); Ave += value[i]; } Ave = Ave / N; int count = 0; for (int i = 0 ; i < N; i++) { if (value[i] > Ave) count++; } double percent = count / (N*1.0)*100 ; System.out.println("大于平均值的数的百分比:"+percent+"%"); } public static void printSeq(int N){ double[] Ascendingorder = new double[N]; System.out.println("随机顺序打印:"); for (int i = 0; i < N; i++) { double value = StdIn.readDouble(); Ascendingorder[i] = value; System.out.printf("%f ",value); } System.out.println("升序打印:"); Arrays.sort(Ascendingorder); for (int i = 0; i < N; i++) { System.out.printf("%f ",Ascendingorder[i]); } System.out.println(); } public static void main(String[] args) { int N = 10; int k = 5; System.out.println("打印出最大最小值:"); max_min(N); System.out.println("打印中位数:"); Median(N); System.out.println("打印第K小的数:"); Kth_minum(N,k); System.out.println("打印平均数和平方和:"); Ave_Quadraticsum(N ); printSeq(N); } }
1.1.35
import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdRandom; /** * 用实验模拟N次掷骰子,并在计算两个1到6之间的随机整数之和时记录每个值出现的频率 * 以验证他们的概率。N要多大时才能够保证你的经验数据和准确数据的吻合程度达到小数点后三位。 *Result: 测试区间在 7*10^5 ~ 8*10^5 之间 */ public class E_35 { public static double[] Standard(){ int SIDES = 6; double[] dist = new double[2*SIDES+1]; for (int i = 1; i <= SIDES; i++) { for (int j = 1; j <= SIDES ; j++) { dist[i+j] += 1.0; } } for (int i = 2; i <= 2*SIDES ; i++) { dist[i] /= 36.0; } return dist; } public static void main(String[] args) { int N = 0; N = StdIn.readInt(); int SIDES = 6; double[] Experiment = new double[2*SIDES+1]; for (int i = 0; i < N; i++) { int a = StdRandom.uniform(1,7); //包括1 但是不包括 7 所以为1-6 int b = StdRandom.uniform(1,7); Experiment[a+b] += 1.0; } double[] Standard = Standard(); for (int i = 1; i <= 2*SIDES; i++) { Experiment[i] /= N; if (Math.abs(Experiment[i]-Standard[i]) > 0.001){ System.out.println("精度不够!"); } System.out.printf("%.3f ",Standard[i]); } } }
1.1.36
import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdRandom; /** *ShuffleTest: */ public class E_36 { public static void main(String[] args) { System.out.println("输入M 和 N:"); int M = StdIn.readInt(); int N = StdIn.readInt(); int a[] = new int[M]; int printM[][] = new int[M][M]; for (int k = 0; k < N ; k++) { for (int i = 0; i < M; i++) { a[i] = i; } StdRandom.shuffle(a); for (int i = 0; i < M; i++) { //对于所有的列J,行i表示的是i在打乱后落到j的位置的次数。 printM[a[i]][i]++; } } for (int i = 0; i < M; i++) { for (int j = 0; j < M; j++) { System.out.printf("%d ",printM[i][j]); } System.out.println(); } } }
1.1.37
import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdRandom; /** * 糟糕的打乱:数组中的所有元素的值不接近N/M 且值之间相差较大 */ public class E_37 { public static void shuffle(int[] a) { if (a == null) { throw new IllegalArgumentException("argument is null"); } int n = a.length; for (int i = 0; i < n; i++) { int r = StdRandom.uniform(0,n); // between 0 and n-1(包含) int temp = a[i]; a[i] = a[r]; a[r] = temp; } } public static void main(String[] args) { System.out.println("输入M 和 N:"); int M = StdIn.readInt(); int N = StdIn.readInt(); int a[] = new int[M]; int printM[][] = new int[M][M]; for (int k = 0; k < N ; k++) { for (int i = 0; i < M; i++) { a[i] = i; } shuffle(a); for (int i = 0; i < M; i++) { //对于所有的列J,行i表示的是i在打乱后落到j的位置的次数。 printM[a[i]][i]++; } } for (int i = 0; i < M; i++) { for (int j = 0; j < M; j++) { System.out.printf("%d ",printM[i][j]); } System.out.println(); } } }
1.1.38
import edu.princeton.cs.algs4.In; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.Arrays; import java.util.Scanner; /** * 对比二分查找和暴力查找: * 暴力查找用时为:365078ms * 二分查找用时为:3864ms */ public class E_38 { public static int rank(int key,int[] a){ int lo = 0; int hi = a.length-1; while(lo <= hi ){ int mid = lo + (hi - lo) / 2; if (key < a[mid ]) hi = mid - 1; else if (key > a[mid] ) lo = mid + 1; else return mid; } return -1; } public static int BruteForceSearch(int key,int[] a){ for (int i = 0; i < a.length ; i++) { if (a[i] == key) return i; } return -1; } public static void main(String[] args) { int[] whitelist = In.readInts("data/largeW.txt"); FileInputStream fis= null; try { fis = new FileInputStream("data/largeT.txt"); } catch (FileNotFoundException e) { e.printStackTrace(); } System.setIn(fis); Scanner sc = new Scanner(System.in); //计算暴力算法时间: long starTime = System.currentTimeMillis(); while(sc.hasNext()){ int key = sc.nextInt(); if (BruteForceSearch(key,whitelist) < 0) System.out.println(key); } long endTime = System.currentTimeMillis(); long BruteTime = endTime - starTime; try { fis = new FileInputStream("data/largeT.txt"); } catch (FileNotFoundException e) { e.printStackTrace(); } System.setIn(fis); Scanner sc1 = new Scanner(System.in); starTime = System.currentTimeMillis(); Arrays.sort(whitelist); while(sc1.hasNext()){ int key = sc1.nextInt(); if (rank(key,whitelist) < 0) System.out.println(key); } endTime = System.currentTimeMillis(); long BinaryTime = endTime - starTime; System.out.println("暴力查找用时为:" + BruteTime+"ms"); System.out.println("二分查找用时为:" + BinaryTime+"ms"); } }
1.1.39
import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdRandom; /** * 随机匹配: * 从命令行接受一个整型参数T,并会分别针对N=10^3 ^4 ^5 ^6 将一下实验运行T遍: * 生成两个大小为N的随机6位正整数数组并找出同时存在于两个数组中的整数的数量。 * 打印一个表格,对于每个N给出T次实验中该数量的平均值。 */ public class E_39 { public static int BinartSearch(int key,int[] a){ int lo = 0; int hi = a.length-1; while(lo <= hi ){ int mid = lo + (hi - lo) / 2; if (key < a[mid ]) hi = mid - 1; else if (key > a[mid] ) lo = mid + 1; else return mid; } return -1; } public static double ComputerAverage(int Count,int T){ int[] whitelist = new int[Count]; int[] compare = new int[Count]; int[] SameNumb = new int[T]; for (int i = 0; i < T; i++) { for (int k = 0; k < Count; k++) { whitelist[k] = StdRandom.uniform(100000,1000000); compare[k] = StdRandom.uniform(100000,1000000); } for (int j = 0; j < compare.length; j++) { if (BinartSearch(compare[j],whitelist) > 0){ SameNumb[i]++; } } } double Average = 0.0; for (int i = 0; i < T; i++) { Average += SameNumb[i]; } Average = Average / T; return Average; } public static void main(String[] args) { int T = 0 ; System.out.println("输入整数T:"); T = StdIn.readInt(); int N3 = 1000; int N4 = 10000; int N5 = 100000; int N6 = 1000000; double result = 0; result = ComputerAverage(N3,T); System.out.println("N = 10^3 时数量为:"+result); result = ComputerAverage(N4,T); System.out.println("N = 10^4 时数量为:"+result); result = ComputerAverage(N5,T); System.out.println("N = 10^5 时数量为:"+result); result = ComputerAverage(N6,T); System.out.println("N = 10^6 时数量为:"+result); } }