二分法 记住有效条件 L <= R 才是循环的有效条件
// 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;while (L <= R) {int mid = (L + R) / 2;if (arr[mid] == num) {return true;} else if (arr[mid] < num) {L = mid + 1;} else {R = mid - 1;}}return false;}
在有序数组中找到>=num最左的位置
1位置 就是>=2的最左位置
在数组中点位置 5 找到>=2 的位置 变量t记录先记录位置 数组有序 舍弃掉记录的右半部
指针左移 0-4范围 中点 2位置 不是>=2的 变量t不更新
3-4 范围 找 中点位置3 是>=2 的 变量t更新 3位置左边可能也有但是已经没数了 
// arr有序的,>=num 最左public static int mostLeftNoLessNumIndex(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;R = mid - 1;} else {L = mid + 1;}}return ans;}
局部最小值
有一个无序数组 任意相邻的两个数不相等
确定边界值 0位置和1位置 n-2位置和n-1位置 谁小返回谁 。 中点mid也是 如果最小就直接返回
mid比左边大 砍掉右边 左边继续二分
注意边界条件 mid-1 mid+1 都要在 L-R范围
// arr 相邻的数不相等!public static int oneMinIndex(int[] arr) {if (arr == null || arr.length == 0) {return -1;}int N = arr.length;if (N == 1) {return 0;}if (arr[0] < arr[1]) {return 0;}if (arr[N - 1] < arr[N - 2]) {return N - 1;}int L = 0;int R = N - 1;// L...R 肯定有局部最小while (L < R - 1) {int mid = (L + R) / 2;if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1]) {return mid;} else {if (arr[mid] > arr[mid - 1]) {R = mid - 1;} else {L = mid + 1;}}}return arr[L] < arr[R] ? L : R;}// 生成随机数组,且相邻数不相等public static int[] randomArray(int maxLen, int maxValue) {int len = (int) (Math.random() * maxLen);int[] arr = new int[len];if (len > 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;boolean rightBigger = right < arr.length ? arr[right] > arr[minIndex] : true;return leftBigger && rightBigger;}public static void printArray(int[] arr) {for (int num : arr) {System.out.print(num + " ");}System.out.println();}public static void main(String[] args) {int maxLen = 100;int maxValue = 200;int testTime = 1000000;System.out.println("测试开始");for (int i = 0; i < testTime; i++) {int[] arr = randomArray(maxLen, maxValue);int ans = oneMinIndex(arr);if (!check(arr, ans)) {printArray(arr);System.out.println(ans);break;}}System.out.println("测试结束");}
时间复杂度
要假设最差情况
复杂度排序表
动态数组
arrayList就是动态数组 会自动扩容
问题 扩容行为 会不会影响 arrayList的整体表现
看放入N个数 扩容的总代价
扩容代价 将原数组内容 放入新数组
代价 规律为等比数列 等比数列最后的总代价为 O(N)
加N为O(N) 加1可化为 O(1)
动态数组 虽然存在扩容行为 但是在时间复杂度上没有影响 可以做到和固定数组一样 还支持动态扩容(仅只时间复杂度)

哈希表不论存多少数据 增删改差 都是常数时间O(1) 只是比较大的常数时间 比数组寻址的时间要大
不会去查test1的引用地址 而是直接查内容
哈希表 值查的是一个东西 就存在 按值传递
自定义的非基础类型 非原生类型 按引用传递 只关心内存地址
有序表 treemap 增删改差 时间复杂度 logN级别
