package class03;
import java.util.Arrays;
// 有序数组中找到num
public class Code_BSExist {
// arr保证有序
public static boolean find(int[] arr, int num) { // 二分法,有缺陷
if (arr == null || arr.length == 0) { // 边界条件
return false;
}
int L = 0; // 左边界
int R = arr.length - 1; // 有边界
// arr[L....R] 即arr[0...arr.length-1] 这个范围找num
while (L <= R) { // <= 是有效范围
int mid = (L + R) / 2; //中点位置
if (arr[mid] == num) {
return true; // 找到了 正确
} else if (arr[mid] < num) { // 小于的情况,左边的丢掉,继续找,新的L是mid+1
L = mid + 1;
} else { // 大于num的情况,右侧不可能,继续找,新的R是mid-1
R = mid - 1;
}
}
return false; // 以上情况都没找到return false
}
// for test
public static boolean test(int[] arr, int num) { // 对数器
for (int cur : arr) {
if (cur == num) {
return true;
}
}
return false;
}
public static int[] generateRandomArray(int maxLen, int maxValue) {
int[] arr = new int[(int) ((maxLen + 1) * Math.random())];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
}
return arr;
}
public static void main(String[] args) {
int testTime = 500000;
int maxLen = 10;
int maxValue = 100;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr = generateRandomArray(maxLen, maxValue);
Arrays.sort(arr); // 排序
int value = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
if (test(arr, value) != find(arr, value)) {
System.out.println("出错了!");
succeed = false;
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked!");
}
}
package class03;
import java.util.Arrays;
//在有序数组中找到>=num最左的位置
// [1,2,2,2,3,4,5,6,7] >=2 的最左位置的数是索引为1的数2,>=4 的最左位置是索引为5的数4
public class Code_BSNearLeft {
// arr有序,找>=num 最左
public static int mostLeftNoLessNumIndex(int[] arr, int num) {
if (arr == null || arr.length == 0) {
return -1;// -1代表不在里面,返回-1代表没这个概念
}
int L = 0;
int R = arr.length - 1;
int ans = -1; // 最晚发生的ans,令他等于-1
while (L <= R) {// 范围
// 在while里面会更新ans,直到找到符合最左位置的索引,它就跳出循环,return 它
int mid = (L + R) / 2;
if (arr[mid] >= num) {
ans = mid; // 往左找,需要更新
R = mid - 1;
} else { // arr[mid]=这个数,它将以-1返回,即没这个数。
}
// for test
public static int test(int[] arr, int value) { //对数器
for (int i = 0; i < arr.length; i++) { // 从左边开始遍历
if (arr[i] >= value) {// 第一个大于等于value的返回其索引位置
return i;
}
}
return -1;
}
// for test
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) (Math.random() * (maxSize + 1))];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * (maxValue + 1)) - (int) (Math.random() * (maxValue));
}
return arr;
}
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static void main(String[] args) {
int maxSize = 10;
int maxValue = 100;
int testTime = 500000;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr = generateRandomArray(maxSize, maxValue);
Arrays.sort(arr);// 排序
int value = (int) (Math.random() * (maxValue + 1)) - (int) (Math.random() * (maxValue));
if (test(arr, value) != mostLeftNoLessNumIndex(arr, value)) {
printArray(arr);
System.out.println(value);
System.out.println(test(arr, value));
System.out.println(mostLeftNoLessNumIndex(arr, value));
succeed = false;
break;
}
}
System.out.println(succeed ? "Nice!" : "Fucking fucked");// 无问题Nice,有问题Fucking fucked
}
}
package class03;
import java.util.Arrays;
public class Code_BSNearRight {
//在有序数组中找到<=num最右的位置
// [1,2,2,2,3,4,5,6,7] <=2 的最左位置的数是索引为3的数2,<=4 的最左位置是索引为5的数4
// arr有序,找<=num 最右
public static int mostRightNoLessNumIndex(int[] arr, int num) {
if (arr == null || arr.length == 0) {
return -1;
}
int L = 0;
int R = arr.length - 1;
int ans = -1;
while (L <= R) {
int mid = (L + R) / 2;
if (arr[mid] <= num) {
ans = mid; // 更新ans
L = mid + 1; // <=num,左边砍掉,找最右的数
} else {//arr[mid]>num
R = mid - 1;// 右边砍掉
}
}
return ans; // 返回正确的结果
}
//for test
public static int test(int[] arr, int value) {// 对数器
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] <= value) {
return i;
}
}
return -1;
}
// for test
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) (Math.random() * (maxSize + 1))];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * (maxValue + 1)) - (int) (Math.random() * (maxValue));
}
return arr;
}
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static void main(String[] args) {
int maxSize = 10;
int maxValue = 100;
int testTime = 500000; // 测试次数
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
int[] arr = generateRandomArray(maxSize, maxValue);
Arrays.sort(arr);
int value = (int) (Math.random() * (maxValue + 1)) - (int) (Math.random() * (maxValue));
if (test(arr, value) != mostRightNoLessNumIndex(arr, value)) {
printArray(arr);
System.out.println(value);
System.out.println(test(arr, value));
System.out.println(mostRightNoLessNumIndex(arr, value));
succeed = false;
break;
}
}
System.out.println(succeed ? "Nice" : "Fucking fucked");
}
}
package class03;
// 局部最小值问题(无序数组)
// 一个数组,无序,数组有条件,任意两个相邻的数之间不相等 [1,2,3,2,3,4]...
/*
* 局部最小定义:
* 1)[0]<[1] 0位置的数是局部最小
* 2)[N-1]<[N-2] N-1位置的数是局部最小
* 3)左>[i]<右 i位置的数局部最小
* 总结以上三点,0~N-1必存在局部最小。0~1下降,N-2~N-1上升,所以必有
* 问题:返回以上其中一个局部最小即可
* */
public class Code_BSAwesome {
// arr整体无序,要满足相邻的数不相等
public static int oneMidIndex(int[] arr) {
if (arr == null || arr.length == 0) {// 边界条件
return -1;
}
int N = arr.length;
if (N == 1) {
return 0;// 一个数,默认0位置最小
}
if (arr[0] < arr[1]) {
return 0;
}
if (arr[N - 1] < arr[N - 2]) {
return N - 1;
}
//N > 2 的时候
// 二分
int L = 0;
int R = N - 1;
// L~R肯定有局部最小
while (L < R - 1) { // (边界条件) 为什么是L[i]<右
return mid; // 三个数(包括三个数)以上返回mid
} else {
/*
* 不同时小,(我是arr[mid])
* 1)左 > 我 我 > 右
* 2)左 < 我 我 < 右
* 3)左 < 我 我 > 右
* */
// 如果是2、3情况,不用管右边,在左边继续找就行
if (arr[mid] > arr[mid - 1]) { // 砍掉右边,R这时候来到mid-1位置
R = mid - 1;// 更新R的位置
} else { // 否则就是1情况。 arr[mid] > arr[mid+1](必定)
// 砍掉左边,L这时候来到mid+1位置
L = mid + 1;// 更新L的位置
}
}
}
// L~R出来之后就是L>=R-1,要么两个数,要么只有一个数
return arr[L] < arr[R] ? L : R;// 如果arr[L] 0) {
arr[0] = (int) (Math.random() * maxValue);
for (int i = 1; i < len; i++) {
do {
arr[i] = (int) (Math.random() * maxValue);
} while (arr[i] == arr[i - 1]); // 如果相邻数相等,它就返回重做
}
}
return arr;
}
// 测试
public static boolean check(int[] arr, int minIndex) {
if (arr.length == 0) {
return minIndex == -1;
}
int left = minIndex - 1; // 定义局部最小左边的位置
int right = minIndex + 1; // 定义局部最小右边的位置
boolean leftBigger = left >= 0 ? arr[left] > arr[minIndex] : true; // 如果 left >= 0 时(有效位置),看是不是左边位置的数大于我,<0就越界,则无数不影响
boolean rightBigger = right < arr.length ? arr[right] > arr[minIndex] : true; // 如果 left < arr.length 时(有效位置),看是不是右边位置的数大于我,>arr.length就越界,则不管
return leftBigger && rightBigger; // 同时满足
}
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int testTime = 1000000;
int maxLen = 10;
int maxValue = 200;
System.out.println("测试开始");
for (int i = 0; i < testTime; i++) {
int[] arr = randomArray(maxLen, maxValue);
int ans = oneMidIndex(arr);
if (!check(arr, ans)) { // 如果有问题就打印以下内容
printArray(arr); // 数组
System.out.println(ans); // 位置
break;
}
}
System.out.println("测试结束");
}
}
package class03;
import sun.reflect.generics.tree.Tree;
import java.util.HashMap;
import java.util.TreeMap;
public class Code_HashMapTreeMap {
public static class Node {
public int value;
public Node(int v) {
value = v;
}
}
// (K,V)表,不管加了多少条数据,它都是常数时间,时间复杂度O(1),固定时间,它的时间比较大
public static void main(String[] args) {
// String在HashMap表是按值传递的
// 按值传递,一张哈希表占一个字节
HashMap map = new HashMap<>();
map.put("lisifang", "我是李四方"); // 新增数据
System.out.println(map.containsKey("guojiahui")); // 查询是否有guojiahui这个key,上面刚加,所以一定有返回true
System.out.println(map.containsKey("guo")); // 无,则返回false
System.out.println(map.get("guojiahui")); // 取出K对应的V我是李四方
map.put("guojiahui", "他1是李四方"); // 更新数据
System.out.println(map.get("guojiahui")); // 他是李四方
// put既是新增操作也是更新value操作
// map.remove("guojiahui"); // 删除
// System.out.println(map.containsKey("guojiahui")); // false
// System.out.println(map.get("guojiahui")); // 空 null值
String test1 = "guojiahui";
String test2 = "guojiahui";
System.out.println(map.containsKey(test1));
System.out.println(map.containsKey(test2));
HashMap map2 = new HashMap<>();
map2.put(1234567, "我是1234567");
Integer a = 1234567;
Integer b = 1234567;
System.out.println(a == b); // false == 比较a的内存地址和b的内存地址是不是一块内存区域。 比较a和b的值用a.equals(b)
// 哈希表中不管你的内存地址,只要你的值相等,它就存在
// Integer Double Float String Char 在哈希表中全部按值传递
System.out.println(map2.containsKey(a)); // true
System.out.println(map2.containsKey(b)); // true
// 非基础类型,非原生类型,哈希表它按引用传递
// 按引用传递,它一个地址占8字节,一张哈希表总共两个,所以它占16字节
Node node1 = new Node(1);
Node node2 = new Node(1);
HashMap map3 = new HashMap<>();
map3.put(node1,"我进来了");
System.out.println(map3.containsKey(node1)); // true 在
System.out.println(map3.containsKey(node2)); // false 不在
System.out.println("=====================");
// 有序表,它的时间复杂度全部是O(logN),比哈希表慢
TreeMap treeMap1 = new TreeMap<>();
treeMap1.put(3,"我是3");
treeMap1.put(0,"我是3");
treeMap1.put(7,"我是3");
treeMap1.put(2,"我是3");
treeMap1.put(5,"我是3");
treeMap1.put(9,"我是3");
System.out.println(treeMap1.containsKey(7)); // true 存在
System.out.println(treeMap1.containsKey(6)); // false 不存在
System.out.println(treeMap1.get(3)); // 我是3
treeMap1.put(3,"他是3"); //更新
System.out.println(treeMap1.get(3)); // 他是3
treeMap1.remove(3); // 删除
System.out.println(treeMap1.get(3)); // null
// 与哈希表不同的
// 内部排好序
System.out.println(treeMap1.firstKey()); // 0
System.out.println(treeMap1.lastKey()); // 9
// <=5 离5最近的key告诉我
System.out.println(treeMap1.floorKey(5)); // 5
// <=6 离6最近的key告诉我
System.out.println(treeMap1.floorKey(6)); // 5
// >=5 离5最近的key告诉我
System.out.println(treeMap1.ceilingKey(5)); // 5
// >=6 离6最近的key告诉我
System.out.println(treeMap1.ceilingKey(6)); // 7
// 以下会报错,自己搞出来的结构,key不可比较,需要自己定义好key
// 原生结构它会自己定义好来
Node node3 = new Node(3);
Node node4 = new Node(4);
TreeMap treeMap2 = new TreeMap<>();
treeMap2.put(node3,"我是node3");
treeMap2.put(node4,"我是node4");
}
}