一、基础 - 简单排序算法
选择排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public static void selectionSort(int[] arr) { if (arr == null || arr.length < 2) { return; } for (int i = 0; i < arr.length - 1; i++) { int minIndex = i; for (int j = i + 1; j < arr.length; j++) { minIndex = arr[j] < arr[minIndex] ? j : minIndex; } swap(arr, i, minIndex); } }
public static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
|
冒泡排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static void bubbleSort(int[] arr) { if (arr == null || arr.length < 2) { return; } for (int e = arr.length - 1; e > 0; e--) { for (int i = 0; i < e; i++) { if (arr[i] > arr[i + 1]) { swap(arr, i, i + 1); } } } }
public static void swap(int[] arr, int i, int j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; }
|
插入排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static void insertionSort(int[] arr) { if (arr == null || arr.length < 2) { return; } for (int i = 1; i < arr.length; i++) { for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) { swap(arr, j, j + 1); } } }
public static void swap(int[] arr, int i, int j) { arr[i] = arr[i] ^ arr[j]; arr[j] = arr[i] ^ arr[j]; arr[i] = arr[i] ^ arr[j]; }
|
二分法的详解与扩展
1)在一个有序数组中,找某个数是否存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public static boolean exist(int[] sortedArr, int num) { if (sortedArr == null || sortedArr.length == 0) { return false; } int L = 0; int R = sortedArr.length - 1; int mid = 0; while (L < R) { mid = L + ((R - L) >> 1); if (sortedArr[mid] == num) { return true; } else if (sortedArr[mid] > num) { R = mid - 1; } else { L = mid + 1; } } return sortedArr[L] == num; }
|
2)在一个有序数组中,找 >= 某个数最左侧的位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public static int nearestIndex(int[] arr, int value) { int L = 0; int R = arr.length - 1; int index = -1; while (L < R) { int mid = L + ((R - L) >> 1); if (arr[mid] >= value) { index = mid; R = mid - 1; } else { L = mid + 1; } } return index; }
|
3)局部最小值问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public static int getLessIndex(int[] arr) { if (arr == null || arr.length == 0) { return -1; } if (arr.length == 1 || arr[0] < arr[1]) { return 0; } if (arr[arr.length - 1] < arr[arr.length - 2]) { return arr.length - 1; } int left = 1; int right = arr.length - 2; int mid = 0; while (left < right) { mid = (left + right) / 2; if (arr[mid] > arr[mid - 1]) { right = mid - 1; } else if (arr[mid] > arr[mid + 1]) { left = mid + 1; } else { return mid; } } return left; }
|
二、拓展 - 异或运算
异或运算的性质与扩展
0^N == N N^N == 0
异或运算满足交换律和结合率
不用额外变量交换两个数
一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到这一个数
一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到这两个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public static void printOddTimesNum1(int[] arr) { int eO = 0; for (int cur : arr) { eO ^= cur; } System.out.println(eO); } public static void printOddTimesNum2(int[] arr) { int eO = 0, eOhasOne = 0; for (int curNum : arr) { eO ^= curNum; } int rightOne = eO & (~eO + 1); for (int cur : arr) { if ((cur & rightOne) != 0) { eOhasOne ^= cur; } } System.out.println(eOhasOne + " " + (eO ^ eOhasOne)); }
|
master 公式
Master 公式用来较为简便地评估递归算法的时间复杂度
T(N) = a*T(N/b) + O(N^d)
log (b,a) > d -> 复杂度为 O (N^log (b,a))
log (b,a) = d -> 复杂度为 O (N^d * logN)
log (b,a) < d -> 复杂度为 O (N^d)
其中
a:生成的子问题数(比如二叉树的递归遍历就是 a = 2)
b:表示每次递归是母问题的 1/b 的数据规模
N:母问题的数据规模
d:额外操作的次数
参考:
【1】左神算法 - 基础 01 - 认识复杂度和简单排序算法
【2】[数据结构与算法中的 Master 公式](