1.编写一个程序,提示用户输入一个字符串,然后显示最大连续递增的有序子字符串。分析你的程序的时间复杂度。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入字符串:");
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
scanner.close();
char pre_c = s.charAt(0);
int m = 1, n = 1, mi = 1;
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) > pre_c)
++n;
else {
if (m < n) {
m = n;
mi = i;
}
n = 1;
}
pre_c = s.charAt(i);
}
System.out.println("最大连续递增子串为:" + (n > m ? s.substring(s.length() - n) : s.substring(mi - m, mi)));
}
}
时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1)。
2.编写一个程序,提示用户输入一个字符串,然后显示最大连续递增的有序字符子序列。分析你的程序的时间复杂度。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入字符串:");
Scanner scanner = new Scanner(System.in);
String s = scanner.nextLine();
scanner.close();
if (s.isEmpty()) {
System.out.println("最大连续递增的有序字符子序列为:");
return;
}
int n = s.length();
String[] d = new String[n]; // d[i] 表示第 i 个字符结尾的子序列
for (int i = 0; i < n; i++) {
char c = s.charAt(i);
d[i] = String.valueOf(c);
for (int j = 0; j < i; j++)
if (s.charAt(j) < c && d[j].length() >= d[i].length())
d[i] = d[j] + c;
}
String res = d[0];
for (int i = 1; i < n; i++)
if (d[i].length() > res.length())
res = d[i];
System.out.println("最大连续递增的有序字符子序列为:" + res);
}
}
(动态规划)时间复杂度为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( n ) O(n) O(n)。
3.编写一个时间复杂度为
O
(
n
)
O(n)
O(n)的程序,提示用户输入两个字符串,然后检测第二个字符串是否为第一个字符串的子串。假定在字符串中相邻的字符是不同的。(不要使用String
类中的indexOf
方法)
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入两个字符串");
Scanner scanner = new Scanner(System.in);
String s1 = scanner.nextLine();
String s2 = scanner.nextLine();
scanner.close();
int i = KMP(s1, s2);
System.out.println(i == -1 ? "不是子串!" : "在下标" + i + "处成功匹配!");
}
public static int KMP(String s, String p) {
int[] next = KMP_next(p);
int i = 0, j = 0, n = s.length(), m = p.length();
while (i < n) {
if (s.charAt(i) == p.charAt(j)) {
++i;
++j;
} else if (j > 0)
j = next[j - 1];
else
++i;
if (j == m) return i - j;
}
return -1;
}
private static int[] KMP_next(String p) {
int n = p.length(), i = 1, j = 0;
int[] a = new int[n];
while (i < n)
if (p.charAt(j) == p.charAt(i))
a[i++] = ++j;
else if (j == 0)
a[i++] = 0;
else
j = a[j - 1];
return a;
}
}
4.改进程序清单22-15中的Boyer-Moore算法实现,在 O ( 1 ) O(1) O(1)的时间内测试不匹配字符位于模式中的哪里,使用模式中所有字符组成的规则集。如果测试为假,算法可以将模式划过不匹配字符。
5.编写一个时间复杂度为 O ( n ) O(n) O(n)的程序,提示用户输入一个以0结束的整数序列,找出同样数字的最长连续子序列。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
int pre = 0, index = -1;
int current, currentIndex = 0, currentCount = 1;
int maxNum = 0, maxIndex = 0, maxCount = 1;
Scanner scanner = new Scanner(System.in);
while ((current = scanner.nextInt()) != 0) {
++index;
if (current == pre) {
++currentCount;
continue;
}
if (currentCount > maxCount) {
maxNum = pre;
maxIndex = currentIndex;
maxCount = currentCount;
}
currentIndex = index;
currentCount = 1;
pre = current;
}
scanner.close();
System.out.printf("The longest same number sequence starts at index %d with %d values of %d.", maxIndex, maxCount, maxNum);
}
}
6.编写一个程序,使用程序清单22-3和程序清单22-4中的算法,求下标从40到45的每两个连续的斐波那契数的GCD,并求其执行时间。
7.22.8节介绍了一个使用分治法求最近点对的算法。实现这个算法,使其满足下面的要求:
- 定义一个名为
Pair
的类,其数据域p1
和p2
表示两个点,名为getDistance()
的方法返回这两个点之间的距离。 - 实现下面的方法:
import java.awt.geom.Point2D;
public class Pair {
public Point2D p1, p2;
public Pair(Point2D p1, Point2D p2) {
this.p1 = p1;
this.p2 = p2;
}
public double getDistance() {
return Point2D.distance(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
public static Pair getClosestPair(double[][] points) {
Closest2DPointsFinder<double[]> finder = new Closest2DPointsFinder<>(points) {
@Override
public double getX(double[] point) {
return point[0];
}
@Override
public double getY(double[] point) {
return point[1];
}
};
return finder.getClosestDistancePair();
}
public static Pair getClosestPair(Point2D[] points) {
Closest2DPointsFinder<Point2D> finder = new Closest2DPointsFinder<>(points) {
@Override
public double getX(Point2D point) {
return point.getX();
}
@Override
public double getY(Point2D point) {
return point.getY();
}
};
return finder.getClosestDistancePair();
}
public static double distance(Point2D p1, Point2D p2) {
return Point2D.distance(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
public static double distance(double x1, double y1, double x2, double y2) {
return Point2D.distance(x1, y1, x2, y2);
}
}
import java.awt.geom.Point2D;
import java.util.Comparator;
public abstract class Closest2DPointsFinder<E> extends ClosestPointsFinder<E> {
public Closest2DPointsFinder(E[] points, Comparator<E> comparator) {
super(points);
super.init(comparator);
}
public Closest2DPointsFinder(E[] points) {
super(points);
super.init(new Comparator<E>() {
@Override
public int compare(E o1, E o2) {
if (getX(o1) > getX(o2)) return 1;
if (getX(o1) == getX(o2))
if (getY(o1) > getY(o2))
return 1;
else if (getY(o1) == getY(o2))
return 0;
return -1;
}
});
}
public abstract double getY(E e);
public Point2D toPoint2D(E e) {
return new Point2D.Double(getX(e), getY(e));
}
@Override
public double getDistance(E e1, E e2) {
return Point2D.distance(getX(e1), getY(e1), getX(e2), getY(e2));
}
public Pair getClosestDistancePair() {
ClosestPointsFinder<E>.PointsPairRef ref = getClosestDistance();
return new Pair(toPoint2D(points[ref.p1Index]), toPoint2D(points[ref.p2Index]));
}
}
import java.util.Arrays;
import java.util.Comparator;
public abstract class ClosestPointsFinder<E> {
protected E[] points;
public ClosestPointsFinder(E[] points) {
this.points = points;
}
public void init(Comparator<E> comparator) {
Arrays.sort(points, comparator);
}
public abstract double getDistance(E e1, E e2);
public double getDistanceByIndex(int index1, int index2) {
return getDistance(points[index1], points[index2]);
}
public abstract double getX(E e);
public double getXByIndex(int index) {
return getX(points[index]);
}
public class PointsPairRef {
public int p1Index, p2Index;
public double distance;
public PointsPairRef(int p1, int p2, double d) {
p1Index = p1;
p2Index = p2;
distance = d;
}
public PointsPairRef(int p1, int p2) {
p1Index = p1;
p2Index = p2;
distance = getDistanceByIndex(p1, p2);
}
public PointsPairRef(int p) {
p1Index = p2Index = p;
distance = Double.MAX_VALUE;
}
public boolean isValid() {
return p1Index != p2Index;
}
}
private PointsPairRef getClosestDistance(int l, int r) {
if (l + 1 >= r) return new PointsPairRef(l);
if (l + 2 == r) return new PointsPairRef(l, l + 1);
int m = (l + r) >> 1;
PointsPairRef L = getClosestDistance(l, m), R = getClosestDistance(m + 1, r);
double d, t;
int m1, m2;
if (L.isValid())
if (R.isValid()) {
if (L.distance > R.distance) {
d = R.distance;
m1 = R.p1Index;
m2 = R.p2Index;
} else {
d = L.distance;
m1 = L.p1Index;
m2 = L.p2Index;
}
for (int i = binarySearch(l, m, d); i < m; i++) {
double di = getDistanceByIndex(i, m);
if (di < d) {
d = di;
m1 = i;
m2 = m;
}
}
for (int i = binarySearch(m + 1, r, d); i < r; i++) {
double di = getDistanceByIndex(i, m);
if (di < d) {
d = di;
m1 = i;
m2 = m;
}
}
} else {
d = getDistanceByIndex(m, R.p1Index);
m1 = m;
m2 = R.p1Index;
for (int i = binarySearch(l, m, d); i < m; i++) {
double di = getDistanceByIndex(i, m);
if (di < d) {
d = di;
m2 = i;
}
}
}
else if (R.isValid()) {
d = getDistanceByIndex(m, L.p1Index);
m1 = m;
m2 = L.p1Index;
for (int i = binarySearch(m + 1, r, d); i < r; i++) {
double di = getDistanceByIndex(i, m);
if (di < d) {
d = di;
m2 = i;
}
}
} else {
d = getDistanceByIndex(L.p1Index, m);
t = getDistanceByIndex(R.p1Index, m);
if (d > t) {
d = getDistanceByIndex(L.p1Index, R.p1Index);
return d > t ? new PointsPairRef(R.p1Index, m, t) : new PointsPairRef(L.p1Index, R.p1Index, d);
} else {
t = getDistanceByIndex(L.p1Index, R.p1Index);
return d > t ? new PointsPairRef(L.p1Index, R.p1Index, t) : new PointsPairRef(L.p1Index, m, d);
}
}
return new PointsPairRef(m1, m2, d);
}
private int binarySearch(int l, int r, double key) {
--r;
while (l <= r) {
int m = (l + r) >> 1;
if (getXByIndex(m) > key)
r = m - 1;
else
l = m + 1;
}
return l;
}
public PointsPairRef getClosestDistance() {
return getClosestDistance(0, points.length);
}
}
8.编写一个程序,找出不大于10 000 000 000的所有素数。大概有455 052 511个这样的素数。你的程序应该满足下面的要求:
- 应该将这些素数都存储在一个名为PrimeNumber.dat的二进制数据文件中。当找到一个新素数时,将该数字追加到这个文件中。
- 为了判断一个新的数是否为素数,程序应该从数据文件加载这些素数到一个大小为10000的
long
型数组。如果数组中没有任何数是这个新数的除数,继续从该数据文件中读取接下来的10000个素数,直到找到除数或者读取完文件中的所有数字。如果没找到除数,这个新的数字就是素数。 - 因为执行该程序要花很长时间,所以应该把它作为UNIX机器上的一个批处理任务来运行。如果机器被关闭或重启,程序应该使用二进制数据文件中存储的素数来继续,而不是从零开始启动。
import java.io.*;
public class PrimeFinder {
private int bufferSize;
private RandomAccessFile primesFile;
private long currentNumber;
private long maxNumber;
private long[] buffer;
public PrimeFinder(String fileName, long maxNumber, int bufferSize) throws IOException {
this.maxNumber = maxNumber;
this.bufferSize = bufferSize;
try {
primesFile = new RandomAccessFile(fileName, "rw");
if (primesFile.length() == 0L) {
currentNumber = 3L;
primesFile.writeLong(2L);
} else
try {
primesFile.seek(primesFile.length() - Long.BYTES);
currentNumber = primesFile.readLong();
} catch (IOException e) {
currentNumber = 3L;
primesFile.writeLong(2L);
}
} catch (FileNotFoundException e) {
File file = new File(fileName);
file.createNewFile();
primesFile = new RandomAccessFile(file, "rw");
currentNumber = 3L;
primesFile.writeLong(2L);
} finally {
buffer = new long[bufferSize];
}
}
public PrimeFinder(String fileName, long maxNumber) throws IOException {
this(fileName, maxNumber, 10000);
}
public PrimeFinder(String fileName) throws IOException {
this(fileName, 10000000000L);
}
public PrimeFinder() throws IOException {
this("PrimeNumber.dat");
}
private static boolean isnPrimeInBuffer(long number, long[] buffer, int size) {
for (int i = 0; i < size; i++)
if (number % buffer[i] == 0L)
return true;
return false;
}
private boolean isPrime() throws IOException {
int currentBufferSize = 0;
primesFile.seek(0L);
boolean isnEOF = true;
do {
do
try {
buffer[currentBufferSize] = primesFile.readLong();
} catch (EOFException e) {
isnEOF = false;
break;
}
while (++currentBufferSize < bufferSize);
if (isnPrimeInBuffer(currentNumber, buffer, currentBufferSize)) return false;
currentBufferSize = 0;
} while (isnEOF);
return true;
}
public void findPrimes() throws IOException {
while (currentNumber < maxNumber) {
if (isPrime()) primesFile.writeLong(currentNumber);
currentNumber += 2;
}
primesFile.close();
}
}
9.编写一个程序,利用卷包裹算法为点集找到凸包。
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
public abstract class GiftWrapper<E> {
public abstract double getX(E e);
public abstract double getY(E e);
public Point2D toPoint2D(E e) {
return new Point2D.Double(getX(e), getY(e));
}
// 生成的列表是原数组元素的浅拷贝
public ArrayList<E> getConvexHull(E[] points) {
int n = points.length;
if (n < 4) return new ArrayList<>(List.of(points));
ArrayList<E> list = new ArrayList<>();
int firstIndex = getRightLowestPointIndex(points), preIndex = firstIndex;
E prePoint = points[firstIndex];
do {
list.add(prePoint);
int i = preIndex == 0 ? 1 : 0;
double mx = getX(points[i]) - getX(prePoint), my = getY(points[i]) - getY(prePoint);
for (int j = i + 1; j < n; j++) {
if (j == preIndex) continue;
double jx = getX(points[j]) - getX(prePoint), jy = getY(points[j]) - getY(prePoint);
if (onRight(mx, my, jx, jy)) {
i = j;
mx = jx;
my = jy;
}
}
prePoint = points[preIndex = i];
} while (preIndex != firstIndex);
return list;
}
public ArrayList<Point2D> getConvexHullPoint2D(E[] points) {
int n = points.length;
if (n < 4) {
ArrayList<Point2D> list = new ArrayList<>();
for (E e : points) list.add(toPoint2D(e));
return list;
}
ArrayList<Point2D> list = new ArrayList<>();
int firstIndex = getRightLowestPointIndex(points), preIndex = firstIndex;
E prePoint = points[firstIndex];
do {
list.add(toPoint2D(prePoint));
int i = preIndex == 0 ? 1 : 0;
double mx = getX(points[i]) - getX(prePoint), my = getY(points[i]) - getY(prePoint);
for (int j = i + 1; j < n; j++) {
if (j == preIndex) continue;
double jx = getX(points[j]) - getX(prePoint), jy = getY(points[j]) - getY(prePoint);
if (onRight(mx, my, jx, jy)) {
i = j;
mx = jx;
my = jy;
}
}
prePoint = points[preIndex = i];
} while (preIndex != firstIndex);
return list;
}
// 判断向量2是否在向量1的右侧
private static boolean onRight(double vector1X, double vector1Y, double vector2X, double vector2Y) {
// 旋转坐标系使得第1个向量位于第1象限
if (vector1X < 0)
if (vector1Y < 0) {
vector1X = -vector1X;
vector1Y = -vector1Y;
vector2X = -vector2X;
vector2Y = -vector2Y;
} else {
double t = vector1Y;
vector1Y = -vector1X;
vector1X = t;
t = vector2Y;
vector2Y = -vector2X;
vector2X = t;
}
else if (vector1Y < 0) {
double t = vector1X;
vector1X = -vector1Y;
vector1Y = t;
t = vector2X;
vector2X = -vector2Y;
vector2Y = t;
}
if (vector2X < 0)
if (vector2Y > 0)
return false;
else
return vector2X * vector1Y > vector2Y * vector1X;
else if (vector2Y < 0)
return true;
else {
if (vector2X == 0 && vector1X == 0) return vector2Y > vector1Y;
vector1Y *= vector2X;
vector2Y *= vector1X;
return vector1Y == vector2Y ? vector2X > vector1X : vector1Y > vector2Y;
}
}
private int getRightLowestPointIndex(E[] points) {
int n = points.length;
int r = 0;
for (int i = 1; i < n; i++)
if (getY(points[i]) < getY(points[r]) || getY(points[i]) == getY(points[r]) && getX(points[i]) > getX(points[r]))
r = i;
return r;
}
}
测试程序:
import java.awt.geom.Point2D;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
double[][] points = {{1, 2.4}, {2.5, 2}, {1.5, 34.5}, {5.5, 6}, {6, 2.4}, {5.5, 9}};
ArrayList<Point2D> res = new GiftWrapper<double[]>() {
@Override
public double getX(double[] point) {
return point[0];
}
@Override
public double getY(double[] point) {
return point[1];
}
}.getConvexHullPoint2D(points);
for (Point2D p : res) System.out.printf("(%f,%f)\n", p.getX(), p.getY());
}
}