1.1.29 等值键
本质上是对于二分算法的拓展
这里默认数组为升序排列,找到中间值之后,只需满足“中间值”比“键值”小(大),中间的下(上)一个值比“键值”大(小),"中间值"与键值“相等”要考虑到值重复的情况,同时边界的问题也要考虑在内.
重复值的统计就相对来说简单一些,这里的思路是立足一点向前和向后统计累加,应该有更加优雅的解法.
// 返回小于键值的元素数量
public static int rankOfKey(int key, int[] a) {
int lo = 0;
int hi = a.length - 1;
int mid = 0;
while (lo <= hi) {
mid = lo + (hi - lo) / 2;
if (a[mid] < key) {
lo = mid + 1;
if (lo > hi || a[lo] > key) return lo;
}
else if (a[mid] > key) {
hi = mid - 1;
if (hi < 0) hi = 0;
if (hi == 0 || a[hi] < key) return hi;
}
else {
while (a[mid] == key)
if (mid > 0) mid--;
else return 0;
return mid + 1;
}
}
return -1;
}
//返回等于该键值的数量
public static int count(int key, int[] a) {
int lo = 0;
int hi = a.length - 1;
int count = 0;
int start;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (a[mid] < key) lo = mid + 1;
else if (a[mid] > key) hi = mid - 1;
else {
count++;
start = mid;
while (mid < a.length - 1 && a[++mid] == key) count++;
while (start > 0 && a[--start] == key) count++;
return count;
}
}
return 0;
}
1.1.30 数组练习
判断i,j是否互质,创建数组并赋值,利用阿基米德算法来解决这个问题。
import edu.princeton.cs.algs4.StdOut;
public class ArraysPra {
public static void main(String[] args) {
Boolean[][] a = createArray(10);
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1; j++) {
StdOut.println("i: " + i + " j: " + j + " " + a[i][j]);
}
}
}
public static Boolean[][] createArray(int n) {
Boolean[][] a = new Boolean[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == 0 || j == 0) a[i][j] = true;
else if (archimedes(i, j) <= 1) a[i][j] = true;
else a[i][j] = false;
}
}
return a;
}
// 阿基米德算法,求解最大公约数
public static int archimedes(int m, int n) {
// StdOut.println("m: " + m + " n: " + n);
if (m % n == 0) return n;
else return archimedes(n, m % n);
}
}
1.1.31 随机连接
这里主要是熟悉api的调用,书中提到的绘图方法。(不过这熟悉的三角计算是怎么回事?)
import edu.princeton.cs.algs4.StdDraw;
import edu.princeton.cs.algs4.StdRandom;
import java.awt.Color;
public class Link {
public static void randomConnection(int n, double p) {
double r = 0.4;
double x0 = 0.5;
double y0 = 0.5;
double angle = 360.0 / n;
double[][] points = new double[n][2];
StdDraw.setPenRadius(0.01);
StdDraw.setPenColor(Color.gray);
for (int i = 0; i < n; i++) {
points[i][0] = x0 + r * Math.cos(angle * i * Math.PI / 180);
points[i][1] = y0 + r * Math.sin(angle * i * Math.PI / 180);
StdDraw.point(points[i][0], points[i][1]);
}
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (StdRandom.bernoulli(p))
StdDraw.line(points[i][0], points[i][1], points[j][0], points[j][1]);
}
}
}
public static void main(String[] args) {
if (args.length == 2) {
randomConnection(
Integer.parseInt(args[0]),
Double.parseDouble(args[1])
);
}
}
}