voidinsertSort(vector<int>& arr){ if (arr.size() < 2) return; //0~0 有序的 //0~i 变为有序 for (int i = 1; i < arr.size(); i++) { for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) { swap(arr[j], arr[j + 1]); } } }
二分法
经常在有序数组上,使用二分搜索,但是有序不是必要条件。
只要能正确构建左右两侧的逻辑,就可以使用二分。
一个有序数组,找某个数是否存在
一个有序数组,找 >= 某个数的最左侧位置
一个有序数组,找 <= 某个数的最右侧位置
局部最小值问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
boolexist(vector<int> sortArr, int num){ if (sortArr.size() == 0) returnfalse; int L = 0, R = sortArr.size() - 1; int mid = 0; //L...R while (L < R) { //L..R 至少两个数 mid = L + ((R - L) >> 1); //mid = (L + R) / 2 if (sortArr[mid] == num) { returntrue; } elseif (sortArr[mid] > num) { R = mid - 1; } else { L = mid + 1; } } return sortArr[L] == num; }
搜索>= 某个数的最左侧位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
intnearestIndex(vector<int>& arr, int value){ int L = 0, R = arr.size() - 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; }
intonlyKtimes(vector<int>& arr, int k, int m){ vector<int> help(32, 0); //help[i]位置的1出现的次数 for (int num : arr) { for (int i = 0; i < 32; i++) { if (((num >> i) & 1) != 0) help[i]++; } } int ans = 0; for (int i = 0; i < 32; i++) { /*返回只出现k次的数,如果不是k次,返回-1; if (help[i] % m == 0) continue; if (help[i] % m == k) { ans |= 1 << i; } else { return -1; }*/ if (help[i] % m != 0) { //在第i位上有1 ans |= 1 << i; } } return ans; }
//arr[L...R]排有序 // T(N) = 2 * T(N / 2) + O(N) // O(N * logN) voidprocess(vector<int>& arr, int L, int R){ if (L == R) { //base case return; } int mid = L + ((R - L) >> 1); process(arr, L, mid); process(arr, mid + 1, R); merge(arr, L, mid, R); }
voidmerge(vector<int>& arr, int L, int M, int R){ vector<int> help(R - L + 1); int i = 0; int p1 = L; int p2 = M + 1; while (p1 <= M && p2 <= R) { help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; } // 要么p1越界了,要么p2越界了 while (p1 <= M) { help[i++] = arr[p1++]; } while (p2 <= R) { help[i++] = arr[p2++]; } for (i = 0; i < help.size(); i++) { arr[L + i] = help[i]; } }
voidmergesort2(vector<int> arr){ if (arr.size() < 1) return; int N = arr.size(); // 步长 int mergeSize = 1; while (mergeSize < N) { // log N // 当前左组的,第一个位置 int L = 0; while (L < N) { if (mergeSize >= N - L) { break; } int M = L + mergeSize - 1; int R = min(mergeSize + M, N - 1); merge(arr, L, M, R); L = R + 1; } // 防止溢出 if (mergeSize > N / 2) { break; } mergeSize <<= 1; } }
voidmerge(vector<int>& arr, int L, int M, int R){ vector<int> help = newint[R - L + 1]; int i = 0; int p1 = L; int p2 = M + 1; while (p1 <= M && p2 <= R) { help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; } // 要么p1越界了,要么p2越界了 while (p1 <= M) { help[i++] = arr[p1++]; } while (p2 <= R) { help[i++] = arr[p2++]; } for (i = 0; i < help.length; i++) { arr[L + i] = help[i]; } }
// arr[L..R]既要排好序,也要求小和返回 // 所有merge时,产生的小和,累加 // 左 排序 merge // 右 排序 merge // merge intprocess(vector<int>& arr, int l, int r){ if (l == r) { return0; } // l < r int mid = l + ((r - l) >> 1); return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r); }
intmerge(vector<int>& arr, int L, int m, int r){ vector<int> help(r - L + 1); int i = 0; int p1 = L; int p2 = m + 1; int res = 0; while (p1 <= m && p2 <= r) { res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0; help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; } while (p1 <= m) { help[i++] = arr[p1++]; } while (p2 <= r) { help[i++] = arr[p2++]; } for (i = 0; i < help.size(); i++) { arr[L + i] = help[i]; } return res; }
intprocess(vector<int>& arr, int l, int r){ if (l == r) return0; //l < r int mid = l + ((r - l) >> 1); returnprocess(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r); } intmerge(vector<int>& arr, int l, int m, int r){ // [L....M] [M+1....R] int ans = 0; // 目前囊括进来的数,是从[M+1, windowR) int windowR = m + 1; for (int i = l; i <= m; i++) { while (windowR <= r && (long) arr[i] > (long) arr[windowR] * 2) { windowR++; } ans += windowR - m - 1; } vector<int> help(r - l + 1); int i = 0; int p1 = l, p2 = m + 1; while (p1 <= m && p2 <= r) { help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; } while (p1 <= L) { help[i++] = arr[p1++]; } while (p2 <= m) { help[i++] = arr[p2++]; } for (i = 0; i < help.size(); i++) { arr[l + i] = help[i]; } return ans; }
//划分函数,对原序列进行分解,将其分解为两个子序列,以基准元素pivot为界, //左侧子序列都比pivot小,右侧子序列都比pivot大。 intpartition(vector<int>& arr, int low, int high){ int i = low, j = high, pivot = arr[low]; //基准元素 while (i < j) { while (i < j && arr[j] > pivot) j--; //向左扫描 while (i < j && arr[i] <= pivot) i++; //向右扫描 if (i < j) { swap(arr[i++], arr[j--]); //交换arr[i]和arr[j] } } if (arr[i] > pivot) { swap(arr[low], arr[i - 1]); //交换arr[i - 1]和arr[low],并返回基准元素位置i - 1 return i - 1; } swap(arr[i], arr[low]); //交换arr[i]和arr[low],并返回基准元素位置i return i; }
//快速排序函数。首先对原序列划分,得到划分的中间位置mid;然后以中间位置为界, //分别对左半部分(low,mid-1)执行快速排序,对右半部分(mid+1,high)执行快速排序。 //递归结束的条件是low≥high voidqsort(vector<int>& arr, int low, int high){ if (low < high) { int p = partition(arr, low, high); //划分 qsort(arr, low, p - 1); //左区间递归快排 qsort(arr, p + 1, high); //右区间递归快排 } }
// 对有一定顺序的堆,当前第i个结点取根左右的最大值(这个操作称heapfiy) voidheapify(vector<int>& nums, int n, int i){ int l = i * 2 + 1, r = i * 2 + 2;// 左右节点索引, left=2*i+1 right=2*i+2 int maxid = i; if (l < n && nums[l] > nums[maxid]) { maxid = l; } if (r < n && nums[r] > nums[maxid]) { maxid = r; } if (maxid != i) { swap(nums[i], nums[maxid]); heapify(nums, n, maxid); } } // 建立大根堆,从树的倒数第二层第一个结点开始,对每个结点进行heapify操作,然后向上走 voidheapify_build(vector<int>& nums, int n){ int temp = (n - 2) / 2; for (int i = temp; i >= 0; i--) { heapify(nums, n, i); } // 打印当前数组 for (int i = 0; i < nums.size(); i++) cout << nums[i] << " "; cout << endl; } // 建立大根堆之后,每次交换最后一个结点和根节点(最大值), // 对交换后的根节点继续进行heapify(此时堆的最后一位是最大值,因此不用管他,n变为n-1) voidheapify_sort(vector<int>& nums, int n){ heapify_build(nums, n); for (int i = 0; i < n; i++) { swap(nums.front(), nums[n - i - 1]); heapify(nums, n - i - 1, 0); } }
// 辅助函数,构造大根堆 voidadjust(vector<int>& arr, int len, int index){ int maxid = index; int left = 2 * index + 1, right = 2 * index + 2; // 计算第i个节点的左右子节点的下标 left=2*i+1 right=2*i+2 parent=(i-1)/2 if (left < len && arr[left] > arr[maxid]) maxid = left; if (right < len && arr[right] > arr[maxid]) maxid = right; if (maxid != index) { swap(arr[maxid], arr[index]); adjust(arr, len, maxid); // 递归调整其他不满足堆性质的部分 } }
voidheapSortCore(vector<int>& arr, int len){ // 初次构建堆,i从第一个非叶子节点开始进行堆调整,i节点的父节点为parent=(i-1)/2,即(len-1-1)/2 for (int i = len / 2 - 1; i >= 0; i--) { adjust(arr, len, i); } for (int i = len - 1; i > 0; i--) { swap(arr[0], arr[i]);// 将当前最大的放置到数组末尾,将未完成排序的部分继续进行堆排序 adjust(arr, i, 0); } }