1 白名单过滤
问题描述:
想象有一家信用卡公司,需要检查用户的交易账号是否有效,为此,他需要:
- 将客户的账号保存到一个文件中,我们称它为白名单;
- 从标准输入中得到每笔交易的账号;
- 使用这个测试用例在标准输出中打印所欲与任何账户无关的账号,公司可能拒绝侧类交易。
将白名单排序后,二分查找
画图与控制台的实现如下(没用之前准备工作的DrawArray,以为那个封装的还不是很好),输入为官网提供的两个文件,eclipse配置如下:data\tinyW.txt data\tinyT.txt
package com.duoduo.algs4.Fundamentals;
import java.awt.Color;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import com.duoduo.algs4.util.RedirectStream;
import com.duoduo.std.DrawArray;
import edu.princeton.cs.introcs.Draw;
import edu.princeton.cs.introcs.In;
import edu.princeton.cs.introcs.StdIn;
import edu.princeton.cs.introcs.StdOut;
public class BinarySearch {
// precondition: array a[] is sorted
public static int rank(int key, int[] a) {
int lo = 0;
int hi = a.length - 1;
while (lo <= hi) {
// Key is in a[lo..hi] or not present.
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 X_DOWN = 0.5;
public static double Y_DOWN = 200;
public static Draw DrawArray(int[] a, int loc, Draw draw) {
return DrawArray(a, X_DOWN, Y_DOWN, loc, draw);
}
public static Draw DrawArray(int[] a, double X_DOWN, double Y_DOWN,
int loc, Draw draw) {
int N = a.length;
double x = 1.0 * loc / N;
double y = a[loc] / Y_DOWN;
double rw = X_DOWN / N;
double rh = a[loc] / Y_DOWN;
draw.setPenColor(Color.RED);
draw.filledRectangle(x, y, rw, rh);
draw.setPenColor();
return draw;
}
public static void testConsole(String whiteListName,String guestListName) throws IOException {
StdOut.println("console");
int[] whiteList = In.readInts(whiteListName);
FileInputStream fis = RedirectStream.redirectFileToStdin(guestListName);
Arrays.sort(whiteList);
while (!StdIn.isEmpty()){
int key = StdIn.readInt();
if(rank(key, whiteList) == -1)
StdOut.println(key);
}
if(fis!=null){
fis.close();
}
}
public static void testDraw(String whiteListName,String guestListName) {
StdOut.println("testDraw");
int[] whitelist = In.readInts(whiteListName);
int[] guestlist = In.readInts(guestListName);
Arrays.sort(whitelist);
Draw draw1 = DrawArray.DrawArray(whitelist, X_DOWN, Y_DOWN,"白名单");
Draw draw2 = DrawArray.DrawArray(guestlist, X_DOWN, Y_DOWN,"黑名单");
int local;
int key;
int N = guestlist.length;
for (int i = 0; i < N; i++) {
key = guestlist[i];
local = rank(key, whitelist);
// 白名单中匹配了多少条,以及黑名单有多少条没被匹配。
if (local == -1) {
StdOut.println(key);
//guest中下标为i的元素不在白名单中
DrawArray(guestlist, i, draw2);
} else {
DrawArray(whitelist, local, draw1);
}
}
}
public static void main(String[] args) throws IOException {
testDraw(args[0],args[1]);
testConsole(args[0],args[1]);
}
}
运行结果:
控制台输出:
testDraw
50
99
13
console
50
99
13
图形结果
防止溢出
int mid = lo + (hi - lo) / 2;
2 将rank改为递归(1),打印递归深度,以及lo和hi
打印深度是加了一个deeps保存深度值:
package com.duoduo.algs4.Fundamentals;
import java.awt.Color;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import com.duoduo.algs4.util.RedirectStream;
import com.duoduo.std.DrawArray;
import edu.princeton.cs.introcs.Draw;
import edu.princeton.cs.introcs.In;
import edu.princeton.cs.introcs.StdIn;
import edu.princeton.cs.introcs.StdOut;
public class BinarySearchRecursion {
public static int rank(int key, int[] a) {
//打印深度
return rank(key, a, 0, a.length - 1, 0);
//不打印深度
// return rank(key, a, 0, a.length - 1);
}
public static int rank(int key, int[] a, int lo, int hi) {
if (lo > hi) {
return -1;
}
int mid = lo + (hi - lo) / 2;
if (key == a[mid]) {
return mid;
} else if (key < a[mid]) {
hi = mid - 1;
} else {
lo = mid + 1;
}
return rank(key, a, lo, hi);
}
// 打印递归深度 P35 1.1.22
public static int rank(int key, int[] a, int lo, int hi, int deeps) {
StdOut.println("此次递归的深度为:" + deeps + " lo:" + lo + " hi:" + hi);
if (lo > hi) {
return -1;
}
int mid = lo + (hi - lo) / 2;
if (key == a[mid]) {
return mid;
} else if (key < a[mid]) {
hi = mid - 1;
} else {
lo = mid + 1;
}
return rank(key, a, lo, hi, deeps + 1);
}
public static void testConsole(String whiteListName, String guestListName)
throws IOException {
int[] whiteList = In.readInts(whiteListName);
FileInputStream fis = RedirectStream.redirectFileToStdin(guestListName);
Arrays.sort(whiteList);
while (!StdIn.isEmpty()) {
int key = StdIn.readInt();
if (rank(key, whiteList) == -1)
StdOut.println(key);
}
if (fis != null) {
fis.close();
}
}
public static void main(String[] args) throws IOException {
testConsole(args[0], args[1]);
}
}
运行结果
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:4 hi:6
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:8 hi:10
此次递归的深度为:3 lo:10 hi:10
此次递归的深度为:4 lo:10 hi:9
50
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:3 lo:0 hi:0
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:4 lo:15 hi:15
此次递归的深度为:5 lo:16 hi:15
99
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:4 hi:6
此次递归的深度为:3 lo:4 hi:4
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:4 hi:6
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:4 lo:15 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:3 lo:0 hi:0
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:8 hi:10
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:0 hi:6
此次递归的深度为:2 lo:0 hi:2
此次递归的深度为:3 lo:2 hi:2
此次递归的深度为:4 lo:3 hi:2
13
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:8 hi:10
此次递归的深度为:3 lo:10 hi:10
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:14 hi:15
此次递归的深度为:4 lo:15 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:0 lo:0 hi:15
此次递归的深度为:1 lo:8 hi:15
此次递归的深度为:2 lo:12 hi:15
此次递归的深度为:3 lo:12 hi:12
3 删除重复元素
- 步骤1:排序
- 步骤2:二分搜索[i+1,...n]
- 步骤3:如果不存在,加入新数组,如果存在,go next
package com.duoduo.algs4.Fundamentals;
import java.io.IOException;
import java.util.Arrays;
import com.duoduo.algs4.util.ArrayUtil;
import edu.princeton.cs.introcs.In;
import edu.princeton.cs.introcs.StdOut;
public class RemoveDuplicateElement {
// 删除重复元素
// 步骤1:排序
// 步骤2:二分搜索[i+1,...n]
// 步骤3:如果不存在,加入新数组,如果存在,go next
public static int[] removeDuplicateElement(int[] a) {
int M = a.length;
if (M <= 0) {
return null;
}
int[] b = new int[M];
int index = 0;
int hi = M - 1;
int lo, key;
for (int i = 0; i < M; i++) {
lo = i + 1;
key = a[i];
if (-1 == BinarySearch.rank(key, a, lo, hi)) {
b[index++] = key;
}
}
// 剔除掉0
int[] result = b;
if (index < M) {
result = new int[index];
for (int i = 0; i < index; i++) {
result[i] = b[i];
}
b = null;
}
return result;
}
public static void testConsole(String whiteListName) {
StdOut.println("console");
int[] whiteList = In.readInts(whiteListName);
Arrays.sort(whiteList);
int[] afterRemove = removeDuplicateElement(whiteList);
ArrayUtil.printArray(whiteList);
ArrayUtil.printArray(afterRemove);
}
public static void main(String[] args) {
testConsole(args[0]);
}
}
运行结果
console
数组为:
10 10 11 13 18 23 23 48 50 54 68 77 77 77 84 98 98 99
数组为:
10 11 13 18 23 48 50 54 68 77 84 98 99
使用data\largeT.txt (6.67M),不知道是不因因为数组太大还是怎么回事儿,输出一闪而过
测试方法
public static void testConsole(String whiteListName) {
StdOut.println("console");
int[] whiteList = In.readInts(whiteListName);
Arrays.sort(whiteList);
int[] afterRemove = removeDuplicateElement(whiteList);
StdOut.println("print");
StdOut.println(whiteList.length);
StdOut.println(afterRemove.length);
ArrayUtil.printArray(whiteList);
ArrayUtil.printArray(afterRemove);
}
public static void printArray(int[] a){
int M = a.length;
StdOut.println("数组为:");
for (int i = 0; i < M; i++) {
StdOut.print(a[i] + " ");
}
StdOut.println();
}
注释掉ArrayUtil.printArray后输出
console
print
1000000
631959