// 快速排序递归函数 privatestaticvoidquickSortC(int[] nums, int i, int j){ if (i >= j) return; int k = randomPartition(nums, i, j); quickSortC(nums, i, k - 1); quickSortC(nums, k + 1, j); }
privatestaticvoidswap(int[] nums, int i, int j){ int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; }
// 快速排序分区函数 返回一个数k // 使得数组中i到k-1都是小于k的 k+1到j都是大于k的 privatestaticintpartition(int[] nums, int l, int r){ // 选取最后一个数作为pivot 处理前面的 最后交换 int pivot = nums[r]; // i的含义:i前面都是比pivot小的数 int i = l; // j从l循环到r-1 for (int j = l; j <= r - 1; j++) { // 若j指向的数比pivot小 就交换i和j指向的数 // 同时i自增 这样保证了i前面都是比pivot小的数 if (nums[j] < pivot) { swap(nums, i, j); i++; } } // 最后i就是pivot应该放的位置 swap(nums, i, r); return i; }
// 快速排序常用优化 随机法 // 随机选择一个[l,r]中的数 和r交换 privatestaticintrandomPartition(int[] nums, int l, int r){ // new Random().nextInt(r - l + 1)是[0,r-l] 再+l即可 int x = new Random().nextInt(r - l + 1) + l; swap(nums,x,r); return partition(nums,l,r); }
classSolution{ publicintfindKthLargest(int[] nums, int k){ // 注意第k大元素实际上是逆序数组下标k-1,这里为了方便直接传k-1 return nums[help(nums, 0, nums.length - 1, k - 1)]; }
privateinthelp(int[] nums, int l, int r, int k){ int x = randomPartition(nums, l, r); if (k == x) { return x; } elseif (k > x) { return help(nums, x + 1, r, k); } else { return help(nums, l, x - 1, k); } } // 依然保持随机数优化 privateintrandomPartition(int[] nums, int l, int r){ int x = new Random().nextInt(r - l + 1) + l; swap(nums, x, r); return partition(nums, l, r); }
privateintpartition(int[] nums, int l, int r){ int pivot = nums[r]; int i = l; for (int j = l; j <= r - 1; j++) { // 这里换成大于就是让pivot前面是比pivot大的数 后面是比pivot小的数 if (nums[j] > pivot) { swap(nums, i, j); i++; } } swap(nums, i, r); return i; }
privatevoidswap(int[] nums, int i, int j){ int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }
// 对一共有n个元素的堆数组a的下标为i的元素自上而下堆化 privatevoidheapify(int[] a, int n, int i){ while (true) { // 找出左右孩子哪个最大,然后互换位置 int maxPos = i; // 有左孩子并且父小于左孩子 并取最大值的下标存入maxPos if (i * 2 <= n && a[i] < a[i * 2]) maxPos = i * 2; // 有右孩子并且父和左孩子的最大值小于右孩子 if (i * 2 + 1 <= n && a[maxPos] < a[i * 2 + 1]) maxPos = i * 2 + 1; // 父亲比左右节点都大 说明此时已经是堆了 if (maxPos == i) break; swap(a,i,maxPos); // 进入下一次循环 i = maxPos; } } }
publicstaticvoidbuildHeap(int[] a, int n){ for (int i = n / 2; i >= 1; i--) { heapify(a, n, i); } }
privatestaticvoidswap(int[] a, int i, int j){ int temp = a[i]; a[i] = a[j]; a[j] = temp; }
publicstaticvoidheapify(int[] a, int n, int i){ while (true) { // 找出左右孩子哪个最大,然后互换位置 int maxPos = i; // 有左孩子并且父小于左孩子 并取最大值的下标存入maxPos if (i * 2 <= n && a[i] < a[i * 2]) maxPos = i * 2; // 有右孩子并且父和左孩子的最大值小于右孩子 if (i * 2 + 1 <= n && a[maxPos] < a[i * 2 + 1]) maxPos = i * 2 + 1; // 父亲比左右节点都大 说明此时已经是堆了 if (maxPos == i) break; swap(a, i, maxPos); // 进入下一次循环 i = maxPos; } }
publicstatic Integer[] topK(Integer[] nums, int k) { if (k <= 0) { returnnew Integer[]{}; } // 小顶堆 PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> (a - b)); int n = nums.length; if (n <= k) { Arrays.sort(nums, (a, b) -> (b - a)); return nums; } for (int i = 0; i < k; i++) { pq.add(nums[i]); } for (int i = k; i < n; i++) { if (nums[i] > pq.peek()) { pq.poll(); pq.add(nums[i]); } } Integer[] a = new Integer[k]; for (int i = 0; i < k; i++) { a[k - i - 1] = pq.poll(); } return a; }
publicMedianFinder(){ smallest = new PriorityQueue<>((a, b) -> (a - b)); biggest = new PriorityQueue<>((a, b) -> (b - a)); }
publicvoidaddNum(int num){ if (biggest.isEmpty()) { biggest.add(num); } else { int m = biggest.size(); int n = smallest.size(); int peek = biggest.peek(); // 如果插入数据后总数居个数是奇数 就让大顶堆多存一个元素 // 如果是偶数 就平分
publicvoidbt(int row){ // 结束回溯条件 if (row == 8) { print(); count++; return; } // 一行有8种放法 for (int c = 0; c < 8; c++) { if (isOk(row, c)) { result[row] = c; bt(row + 1); } } }
// 考察这个点能否放置皇后 // 因为是自上而下回溯 所以在本行 只需考虑上面皇后的影响 下面没皇后 privatebooleanisOk(int row, int c){ for (int i = 0; i < row; i++) { // 在同一列 if (result[i] == c) { returnfalse; } // 在左上角 if (row - i == c - result[i]) { returnfalse; } // 在右上角 if (row - i == result[i] - c) { returnfalse; } } returntrue; }
privatevoidprint(){ for (int row = 0; row < 8; row++) { for (int c = 0; c < 8; c++) { if (result[row] == c) { System.out.print("Q "); } else { System.out.print("* "); } } System.out.println(); } System.out.println("================"); }
classSolution{ public List<List<Integer>> permute(int[] nums) { int len = nums.length; List<List<Integer>> res = new ArrayList<>(); if (len == 0) { return res; }
boolean[] used = newboolean[len]; Deque<Integer> path = new ArrayDeque<>();
dfs(nums, len, path, used, res); return res; }
privatevoiddfs(int[] nums, int len, Deque<Integer>path, boolean[] used, List<List<Integer>> res){ //递归出口 if (path.size() == len) { res.add(new ArrayList<>(path)); return; }
classSolution{ boolean[] vis; public List<List<Integer>> permuteUnique(int[] nums) { List<List<Integer>> ans = new ArrayList<List<Integer>>(); List<Integer> perm = new ArrayList<Integer>(); vis = newboolean[nums.length]; Arrays.sort(nums); backtrack(nums, ans, 0, perm); return ans; }
publicvoidbacktrack(int[] nums, List<List<Integer>> ans, int idx, List<Integer> perm){ if (idx == nums.length) { ans.add(new ArrayList<Integer>(perm)); return; } for (int i = 0; i < nums.length; ++i) { if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) { continue; } perm.add(nums[i]); vis[i] = true; backtrack(nums, ans, idx + 1, perm); vis[i] = false; perm.remove(idx); } } }
注意这里的去重思路,需要先对数组排序,乱序是不可以的。然后最关键的部分就是
1 2 3
if (vis[i] || (i > 0 && nums[i] == nums[i - 1] && !vis[i - 1])) { continue; }
classSolution{ public List<List<Integer>> combine(int n, int k) { List<List<Integer>> res = new ArrayList<>(); Deque<Integer> stack = new ArrayDeque<>(); dfs(n,k,1,stack,res); return res;
} privatevoiddfs(int n,int k,int begin,Deque<Integer> stack,List<List<Integer>> res){ if (stack.size() == k){ res.add(new ArrayList<>(stack)); return; } //因为i从begin开始 从1到begin-1是不会被选择的 所以我们没有必要创建used数组来判断谁要不要选 for (int i = begin; i <= n; i++) { stack.addLast(i); dfs(n,k,i+1,stack,res); stack.removeLast(); }