算法(第四版)Java 第一章1.2节 题解
Posted mereder
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法(第四版)Java 第一章1.2节 题解相关的知识,希望对你有一定的参考价值。
前言
整本《算法》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.2节)
1.2.1
import edu.princeton.cs.algs4.Point2D; import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdRandom; /** * 编写一个Point2D的用例,从命令行接受一个整数N。 * 在单位正方形中生成N个随机点,然后计算两点之间的最短距离。 */ public class E_01 { public static void main(String[] args) { int N = 0; System.out.println("输入N:" ); N = StdIn.readInt(); Point2D[] randompoints = new Point2D[N]; for (int i = 0; i < N; i++) { double x = StdRandom.uniform(0.0,1.0); double y = StdRandom.uniform(0.0,1.0); randompoints[i] = new Point2D(x, y); } double minimumDistance = 9999; for (int i = 0; i < N; i++) { for (int j = N-1; j > i ; j--) { double distance = randompoints[i].distanceTo(randompoints[j]); if (distance <= minimumDistance) minimumDistance = distance; } } System.out.println("最短距离为:"+ minimumDistance); } }
1.2.2
/** * 编写一个Interval1D的用例,从命令行接受一个整数N。从标准输入 * 中读取N个间隔并打印出所有相交的间隔对。 */ public class E_02 { public static void main(String[] args) { int N = 0; System.out.println("输入 N :"); N = StdIn.readInt(); Interval1D[] interval = new Interval1D[N]; for (int i = 0; i < N; i++) { double lo = StdIn.readDouble(); double hi = StdIn.readDouble(); interval[i] = new Interval1D(lo,hi); } for (int i = 0; i < N; i++) { for (int j = i+1; j < N ; j++) { if (interval[i].intersects(interval[j])) System.out.println(interval[i]+" "+interval[j]); } } } }
1.2.3
/** * 编写一个Interval2D的用例,从命令行接受参数N、min和max。生成N个随机的2D间隔,其宽和高均匀地分布在单位正方形中 * 的min和max之间。用StdDraw画出他们并打印出相交的间隔对的数量以及有包含关系的间隔对数量。 */ public class E_03 { public static void main(String[] args) { System.out.println("输入 N :"); int N = StdIn.readInt(); System.out.println("输入min 和 max :"); double min = StdIn.readDouble(); double max = StdIn.readDouble(); StdDraw.setXscale(0.0,1.0); StdDraw.setYscale(0.0,1.0); Interval2D[] boxes = new Interval2D[N]; //保存一个box的左下和右上点 通过对角点判断是否在Box中 box.contains 只能判断点 Point2D[] leftbottom = new Point2D[N]; Point2D[] righttop = new Point2D[N]; for (int i = 0; i < N; i++) { double xmin = StdRandom.uniform(min, max); double xmax = StdRandom.uniform(min, max); double ymin = StdRandom.uniform(min, max); double ymax = StdRandom.uniform(min, max); if(xmin > xmax){ double temp = xmax; xmax = xmin; xmin = temp; } if(ymin > ymax){ double temp = ymax; ymax = ymin; ymin = temp; } Interval1D xinterval = new Interval1D(xmin,xmax); Interval1D yinterval = new Interval1D(ymin,ymax); leftbottom[i] = new Point2D(xmin,ymin); righttop[i] = new Point2D(xmax,ymax); boxes[i] = new Interval2D(xinterval,yinterval); boxes[i].draw(); } int countintersects = 0; int countcontains = 0; for (int i = 0; i < N; i++) { for (int j = i+1; j < N; j++) { if (boxes[i].intersects(boxes[j])) countintersects++; if (boxes[i].contains(leftbottom[j]) && boxes[i].contains(righttop[j])) countcontains++; } } System.out.println("相交的间隔对的数量:"+countintersects); System.out.println("有包含关系的间隔对数量:"+countcontains); } }
1.2.4
/** * 以下代码会打印出什么? * * Result:String2 指向“hello” 当String1被赋值指向“world”时,String1仍然是“hello” * world * hello */ public class E_04 { public static void main(String[] args) { String string1 = "hello"; String string2 = string1; string1 = "world"; System.out.println(string1); System.out.println(string2); } }
1.2.5
/** * 以下代码会打印出什么: * * Result: * Hello World * 方法 s.toUpperCase()和方法s.substring(6,11);都是需要返回一个 String的 */ public class E_05 { public static void main(String[] args) { String s = "Hello World"; s.toUpperCase(); s.substring(6,11); System.out.println(s); } }
1.2.6
/** * 如果字符串s中的字符循环移动任意位置后能够得到另一个字符串t * 那么s就被称为t的回环变位。编写一个程序检查两个给定的字符串s * 和t是否互为回环变位。 * Hint:答案只需要一行用到indexof length 和字符串链接的代码。 */ public class E_06 { public static void main(String[] args) { String s = "TGACGAC"; String t = "ACTGACG"; if (s.length() == t.length() && (s.concat(s).indexOf(t) > 0) ) System.out.println("true"); else System.out.println("false"); } }
1.2.7
/** * 一下递归函数的返回值是什么: * Result: * 将字符串倒置(分治思想) */ public class E_07 { public static String mystery(String s){ int N = s.length(); if (N <= 1 ) return s; String a = s.substring(0,N/2); String b = s.substring(N/2,N); return mystery(b)+mystery(a); } public static void main(String[] args) { String string = "Hello World!Hello Java!"; String invertString = mystery(string); System.out.println(invertString); } }
1.2.8
/** * 设a[] b[] 均为长 数百万的整型数组。以下代码的作用是什么?有效吗? * Anwser:这段代码会将他们交换。效率不能再高了。 * 因为它复制的是引用而不是需要复制数百万个元素 */ public class E_08 { public static void main(String[] args) { int[] a = new int[10000000]; int[] b = new int[10000000]; int t[] = a; a = b; b = t; } }
1.2.9
/** * 修改BinartSearch,使用Counter 统计在有查找中被检查的键的总数并在查找全部接受后打印该值 * hint :在main中创建一个Counter对象并将它作为参数传递给rank() */ public class E_09 { public static int rank_(int key, int[] a, Counter counter){ int lo = 0; int hi = a.length-1; while(lo <= hi){ int mid = lo + (hi - lo) / 2; if (key < a[mid]){ counter.increment(); hi = mid - 1; } else if (key > a[mid]){ counter.increment(); lo = mid + 1; } else{ counter.increment(); return mid; } } return -1; } public static void main(String[] args) { int a[] = {1,2,3,4,5,6,7,8,9,10}; Counter counter = new Counter("SearchTime"); if (rank_(2,a,counter)> 0) System.out.println(counter); else System.out.println("No data!"); } }
1.2.10
/** * 编写一个VisualCounter类,支持加一减一操作。它的构造函数接受两个参数N和MAX 其中N指定了操作的最大次数。 * max指定了计数器的最大绝对值。作为副作用,用图像显示每次计数器变化后的值 */ public class E_10 { public static class VisualCounter{ private int times; private final int N; private final int Max; private int count = 0; public VisualCounter(int max,int n) { times = 0; if (max < 0) { Max = -max; System.out.println("Input max error"); } else{ Max = max; } N = n; StdDraw.setXscale(0,n+1); StdDraw.setYscale(-(max+1),max+1); StdDraw.point(0,0); } public void increment(){ if (times < N && Math.abs(count) < Max) { count++; times++; } else System.out.println("out of N or Max!"); } public int getTimes() { return times; } public int getCount() { return count; } public void decrement(){ if (times < N && Math.abs(count) < Max) { count--; times++; } else System.out.println("out of N or Max!"); } } public static void main(String[] args){ int N = 100; int Max = 100; VisualCounter visualCounter = new VisualCounter(Max,N); int count = 0; int times = 0; for (int i = 0; i < 40; i++) { count = visualCounter.getCount(); times = visualCounter.getTimes(); visualCounter.increment(); StdDraw.point(times,count); } for (int i = 0; i < 30; i++) { count = visualCounter.getCount(); times = visualCounter.getTimes(); visualCounter.decrement(); StdDraw.point(times,count); } for (int i = 0; i < 30; i++) { count = visualCounter.getCount(); times = visualCounter.getTimes(); visualCounter.increment(); StdDraw.point(times,count); } } }
1.2.11
/** * 根据Date的API 实现一个SmartDate类型 * 在日期非法时抛出一个异常 */ public class E_11 { public static class SmartDate { private static final int[] DAYS = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; private final int month; // month (between 1 and 12) private final int day; // day (between 1 and DAYS[month] private final int year; // year public SmartDate(int month, int day, int year) { if (!isValid(month, day, year)) throw new IllegalArgumentException("Invalid date"); this.month = month; this.day = day; this.year = year; } public SmartDate(String date) { String[] fields = date.split("/"); if (fields.length != 3) { throw new IllegalArgumentException("Invalid date"); } month = Integer.parseInt(fields[0]); day = Integer.parseInt(fields[1]); year = Integer.parseInt(fields[2]); if (!isValid(month, day, year)) throw new IllegalArgumentException("Invalid date"); } public int getMonth() { return month; } public int getDay() { return day; } public int getYear() { return year; } private static boolean isValid(int m, int d, int y) { if (m < 1 || m > 12) return false; if (d < 1 || d > DAYS[m]) return false; if (m == 2 && d == 29 && !isLeapYear(y)) return false; return true; } private static boolean isLeapYear(int y) { if (y % 400 == 0) return true; if (y % 100 == 0) return false; return y % 4 == 0; } public String toString() { return month + "/" + day + "/" + year; } } public static void main(String[] args) { SmartDate smartDate = new SmartDate(1,30,2018); System.out.println(smartDate); SmartDate errorDate = new SmartDate(2,30,2018); System.out.println(errorDate); /* 标准输出结果: 1/30/2018 Exception in thread "main" java.lang.IllegalArgumentException: Invalid date * */ } }
1.2.12(包含计算星期几的Zeller 公式)
详情Zekller 公式解析参考:http://www.cnblogs.com/mq0036/p/3534314.html
/** * 添加一个dayOfweek的方法,为日期中每周日返回Monday、Tuesday、Wednesday * Thursday、Friday、Saturday、Sunday 假定时间是21世纪 */ public class E_12 { public static class SmartDate { private static final int[] DAYS = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; private final int month; // month (between 1 and 12) private final int day; // day (between 1 and DAYS[month] private final int year; // year public SmartDate(int month, int day, int year) { if (!isValid(month, day, year)) throw new IllegalArgumentException("Invalid date"); this.month = month; this.day = day; this.year = year; } public SmartDate(String date) { String[] fields = date.split("/"); if (fields.length != 3) { throw new IllegalArgumentException("Invalid date"); } month = Integer.parseInt(fields[0]); day = Integer.parseInt(fields[1]); year = Integer.parseInt(fields[2]); if (!isValid(month, day, year)) throw new IllegalArgumentException("Invalid date"); } public int getMonth() { return month; } public int getDay() { return day; } public int getYear() { return year; } private static boolean isValid(int m, int d, int y) { if (m < 1 || m > 12) return false; if (d < 1 || d > DAYS[m]) return false; if (m == 2 && d == 29 && !isLeapYear(y)) return false; return true; } private static boolean isLeapYear(int y) { if (y % 400 == 0) return true; if (y % 100 == 0) return false; return y % 4 == 0; } /** Zeller Formula * @return */ public String dayOfWeek(){ int d = this.getDay(); int m = this.getMonth(); int y = this.getYear(); if (m < 3) { m += 12; y--; } int w = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7; String[] dayOfWeek = {"Monday", "Tuesday", "Wednesday" ,"Thursday", "Friday", "Saturday", "Sunday"}; return dayOfWeek[w]; } public String toString() { return month + "/" + day + "/" + year; } } public static void main(String[] args) { SmartDate smartDate = new SmartDate(7,26,2018); String s = smartDate.dayOfWeek(); System.out.println(s); } }
1.2.13 and 1.2.14
/** * 以Date为模板实现Transaction * 实现equals()方法 */ public class E_13and14 { public static class Transaction{ private String Customer; private Date Date; private double Money; public Transaction(String customer, edu.princeton.cs.algs4.Date date, double money) { Customer = customer; Date = date; Money = money; } public String getCustomer() { return Customer; } public edu.princeton.cs.algs4.Date getDate() { return Date; } public double getMoney() { return Money; } @Override public String toString() { return Customer+" "+Date+" "+Money; } @Override public boolean equals(Object obj) { if (obj == this) return true; if (obj == null) return false; if (obj.getClass() != this.getClass()) return false; Transaction that = (Transaction)obj; return (this.Customer == that.Customer) && (this.Date == that.Date) && (this.Money == that.Money); } } public static void main(String[] args) { Date date = new Date(7,26,2018); Transaction transaction = new Transaction("mereder",date,11.12); Transaction test = new Transaction("jiaojiao",date ,11.12); Transaction test2 = new Transaction("mereder",date,11.12); if (test.equals(transaction)) System.out.println("true"); else System.out.println("false"); if (test2.equals(transaction)) System.out.println("true"); else System.out.println("false"); System.out.println(transaction); } }
1.2.15
/** * 文件输入: * 基于String 的split方法实现In中的静态方法 readInts(); * readAll 的函数中,直接将文件test.txt的所有内容都读到一个字符串中 */ public class E_15 { public static int[] readInts(String name){ In in = new In(name); String input = in.readAll(); String[] words = input.split("\\s+"); int[] ints = new int[words.length]; for (int i = 0; i < words.length; i++) { ints[i] = Integer.parseInt(words[i]); } return ints; } public static void main(String[] args) { int[] ints; ints = readInts("e://test.txt"); for (int i = 0; i < ints.length; i++) { System.out.println(ints[i]); } } }
1.2.16 and 1.2.17 (注意断言机制使用规范 true 程序继续 ;false 产生断言)
/** * 有理数: * 为有理数实现一个不可变数据类型Rational 支持加减乘除操作 * ==================================================================== * public class Rational * -------------------------------------------------------------------- * Rational(int numerator,int denominator) * Rational plus(Rational b) 该数与b之和 * Rational minus(Rational b) 该数与b之差 * Rational times(Ratioanl b) 该数与b之积 * Rational divides(Rational b) 该数与b之商 * Boolean equals(Rational that) 该数与that相等吗 * String toString() 对象的字符串表示 * 只需要使用两个long型实例变量表示分子分母来控制溢出的可能性, * 使用欧几里得算法来保证分子分母没有公因子。编写一个测试用例尖刺实现的所有方法 * * */ public class E_16 { public static class Rational{ private int Numerator; private int Denominator; private long MAX = 2147483641; private long MIN = -2147483641; public Rational(int numerator, int denominator) { if (denominator == 0) throw new ArithmeticException("denominator is zero"); int gcd = gcd(numerator,denominator); Numerator = numerator / gcd; Denominator = denominator / gcd; if (denominator < 0){ Denominator = -Denominator; Numerator = -Numerator; } } public int getNumerator() { return Numerator; } public int getDenominator() { return Denominator; } public Rational plus(Rational b){ //if (isPlusOverflow(Numerator * b.Denominator,Denominator * b.Numerator)) System.out.println("plus overflow"); assert isPlusOverflow( Numerator * b.Denominator,Denominator * b.Numerator):"plus overflow"; assert isTimesOverflow(Denominator , b.Denominator):"times overflow"; int Den = Denominator * b.Denominator; int Num = Numerator * b.Denominator + Denominator * b.Numerator; Rational temp = new Rational(Num,Den); return temp; } public Rational minus(Rational b){ int Den = this.Denominator * b.Denominator; int Num = this.Numerator * b.Denominator - this.Denominator * b.Numerator; Rational temp = new Rational(Num,Den); return temp; } public Rational times(Rational b){ // if (isTimesOverflow(Denominator ,b.Denominator)) System.out.println("times overflow"); assert isTimesOverflow(Denominator ,b.Denominator):"times overflow"; assert isTimesOverflow(Numerator,b.Numerator):"times overflow"; int Den = Denominator * b.Denominator; int Num = Numerator * b.Numerator; Rational temp = new Rational(Num,Den); return temp; } public Rational divides(Rational b){ Rational daoshu = new Rational(b.Denominator,b.Numerator); Rational temp = this.times(daoshu); return temp; } public Boolean equals(Rational that){ if (that == null) return false; if (that.getClass() != this.getClass()) return false; Rational temp = (Rational) that; return this.compareTo(that) == 0; } private int compareTo(Rational that) { long lhs = this.Numerator * that.Denominator; long rhs = this.Denominator * that.Numerator; if (lhs < rhs) return -1; if (lhs > rhs) return +1; return 0; } private int gcd(int a, int b){ if (b < 0 ) b = -b; if (a < 0 ) a = -a; if (a % b == 0) return b; else return gcd(b,a % b); } /** * @param a * @param b * @return true 程序继续 false 则抛出异常 */ private boolean isPlusOverflow(int a,int b){ if (a > 0 && b > 0) return !(a + b < 0); else if(a < 0 && b < 0){ return ! (a + b > 0); } return true; } /** * @param a * @param b * @return true 程序顺利进行不启动assert false 启动断言 */ private boolean isTimesOverflow(int a,int b){ if (a < 0) { a = -a; } if (b < 0) { b = -b; } if (a == 0 || b == 0) { return true; } else { return !(a * b < 0); } } @Override public String toString() { if (Denominator == 1) return Numerator + ""; else return Numerator + "/" + Denominator; } } public static void main(String[] args) { int a = -2147483647; int b = 1; Rational rational = new Rational(-2147483645,b); Rational rational1 = new Rational(2,b); Rational rational2 = new Rational(3,5); Rational temp = rational.plus(rational1); System.out.println(temp); temp = rational.minus(rational1); System.out.println(temp); temp = rational.times(rational1); System.out.println(temp); temp = rational.divides(rational2); System.out.println(temp); } }
1.2.18(与直接对所有数据的平方求和的方法相比较。这种实现能够更好的避免四舍五入产生的误差。)
/** * 累加器的方差: * 以下代码为Accumulator 类添加了var() 和stddev()方法,他们计算了 * addDataValue()方法的参数的方差和标准差 验证这段代码 * * 与直接对所有数据的平方求和的方法相比较。这种实现能够更好的避免四舍五入产生的误差。 */ public class E_18 { public static class Accumulator{ private double m; private double s; private int N; public Accumulator() { m = 0; s = 0; N = 0; } public void addDaraValue(double x){ N++; s = s + 1.0 * (N-1) / N * (x - m) * (x - m); m = m + (x - m) / N; } public double mean(){ return m; } public double var(){ return s / (N-1); } public double stddev(){ return Math.sqrt(this.var()); } @Override public String toString() { return "Mean (" + N + " values ):" + String.format("%7.5f",mean()) + " var : " + var() + " stddev :" + stddev(); } } public static void main(String[] args) { Accumulator accumulator = new Accumulator(); for (int i = 0; i < 10; i++) { double temp = StdRandom.uniform(1,100); accumulator.addDaraValue(temp); } System.out.println(accumulator); } }
1.2.19
/** * 字符串解析为Date 和 Transaction 类型编写能够解析字符串数据的构造函数。它接受一个String参数指定的初始值: * ================================================================================= * 类型 格式 举例 * --------------------------------------------------------------------------------- * Date 由斜杠分割的整数 5/22/1939 * Transaction 客户、日期和金额,由空白字符分隔 Turing 5/22/1939 11.99 */ public class E_19 { /** * 由于前面写了该类型的其他方法 这里仅放一个构造函数 和 toString检验 */ public static class Transaction { private String Customer; private Date Date; private double Money; public Transaction(String information) { String[] words = information.split(" "); Customer = words[0]; Date = new Date(words[1]); Money = Double.parseDouble(words[2]); } @Override public String toString() { return "用户:"+Customer+" 日期:"+Date+" 金额:"+Money; } } /** * 更全的参考 edu.princeton.cs.algs4/Date.java */ public static class Date{ private static final int[] DAYS = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; private final int month; // month (between 1 and 12) private final int day; // day (between 1 and DAYS[month] private final int year; // year public Date(String date) { String[] fields = date.split("/"); if (fields.length != 3) { throw new IllegalArgumentException("Invalid date"); } month = Integer.parseInt(fields[0]); day = Integer.parseInt(fields[1]); year = Integer.parseInt(fields[2]); if (!isValid(month, day, year)) throw new IllegalArgumentException("Invalid date"); } private static boolean isValid(int m, int d, int y) { if (m < 1 || m > 12) return false; if (d < 1 || d > DAYS[m]) return false; if (m == 2 && d == 29 && !isLeapYear(y)) return false; return true; } private static boolean isLeapYear(int y) { if (y % 400 == 0) return true; if (y % 100 == 0) return false; return y % 4 == 0; } @Override public String toString() { return "年:"+year+" 月:"+month+" 日:"+day; } } public static void main(String[] args) { Date date = new Date("5/22/1939"); Transaction transaction = new Transaction("Turing 5/22/1939 11.99"); System.out.println(date); System.out.println(transaction); /**Result * 年:1939 月:5 日:22 * 用户:Turing 日期:年:1939 月:5 日:22 金额:11.99 * */ } }
以上是关于算法(第四版)Java 第一章1.2节 题解的主要内容,如果未能解决你的问题,请参考以下文章