Find Kth题目类型总结 (quick Select 类型总结)

2024-09-04 14:48

本文主要是介绍Find Kth题目类型总结 (quick Select 类型总结),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先quick select算法的模板要倒背如流,这个是通过quick sort里面提炼得到的算法;两个while一个if,condition相同;后面再递归

Kth Largest Element in an Array (是找从大到小的第k大;注意左边是大的,右边是小的,quick select的模板要熟记)

class Solution {public int findKthLargest(int[] nums, int k) {if(nums == null || nums.length == 0) {return -1;}return findKth(nums, 0, nums.length - 1, k);}private int findKth(int[] nums, int start, int end, int k) {if(start == end) {return nums[start];}int i = start; int j = end;int mid = start + (end - start) / 2;int pivot = nums[mid];while(i <= j) {while(i <= j && nums[i] > pivot) {i++;}while(i <= j && nums[j] < pivot) {j--;}if(i <= j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;i++;j--;}}if(start + k - 1 <= j){return findKth(nums, start, j, k);}if(start + k - 1 >= i) {return findKth(nums, i, end, k - (i - start));}return nums[j + 1];}
}

Kth Smallest Numbers in Unsorted Array (quickselect标准解法:O(N);)

Sort Colors II (rainbow sort) 思路:按照quick sort的思想来,start, end是数组起点,终点的范围,from to 是颜色的范围,用颜色的中间值,作为pivot,然后小的在左边,大的在右边,先整体有序,再局部有序;注意 start >= end || from >= to base条件的判断,还有midcolor属于左边;

public class Solution {/*** @param colors: A list of integer* @param k: An integer* @return: nothing*/public void sortColors2(int[] colors, int k) {if(colors == null || colors.length == 0) {return;}int n = colors.length;quickSelect(colors, 0, n - 1, 1, k);}private void quickSelect(int[] colors, int start, int end, int from, int to) {if(start >= end || from >= to) { // 注意这个base条件的判断,否则出错;return;}int midcolor = from + (to - from) / 2;int i = start; int j = end;while(i <= j) {// midcolor 属于左边;while(i <= j && colors[i] <= midcolor) {i++;}while(i <= j && colors[j] > midcolor) {j--;}if(i <= j) {int temp = colors[i];colors[i] = colors[j];colors[j] = temp;i++;j--;}}// j , i;quickSelect(colors, start, j, from, midcolor); // midcolor属于左边;quickSelect(colors, i, end, midcolor + 1, to);}
}

Kth Largest Element II 思路:可以用quick select模板,注意模板是两个while一个if,另外条件是i <= j ,但是如果数据量特别大,内存存不下的时候,就要用pq,minheap;

public class Solution {/*** @param nums: an integer unsorted array* @param k: an integer from 1 to n* @return: the kth largest element*/public int kthLargestElement2(int[] nums, int k) {if(nums == null || nums.length == 0) {return -1;}PriorityQueue<Integer> minheap = new PriorityQueue<Integer>();for(int num : nums) {if(minheap.size() < k) {minheap.offer(num);} else {// minheap.size() > k;if(num > minheap.peek()) {minheap.poll();minheap.offer(num);}}}return minheap.peek();}
}

Nuts bolts problem 思路:算法比较好想,就是用A最左边的一个pivot, 去sort B,然后用B[index] = A[l]  ,去sort A,然后recursion;每次用start,去sort另外一个数组,首先把match的放到B的头部,然后partition后面的部分,partition完了之后,把start换到j的位子,这样才是一个正确的顺序;

/*** public class NBCompare {*     public int cmp(String a, String b);* }* You can use compare.cmp(a, b) to compare nuts "a" and bolts "b",* if "a" is bigger than "b", it will return 1, else if they are equal,* it will return 0, else if "a" is smaller than "b", it will return -1.* When "a" is not a nut or "b" is not a bolt, it will return 2, which is not valid.
*/
public class Solution {/*** @param nuts: an array of integers* @param bolts: an array of integers* @param compare: a instance of Comparator* @return: nothing*/public void sortNutsAndBolts(String[] nuts, String[] bolts, NBComparator compare) {int n = nuts.length;sort(nuts, bolts, compare, 0, n - 1);}private void sort(String[] nuts, String[] bolts, NBComparator compare, int start, int end){if(start >= end) {return;}String pivot = bolts[start];int index = partition(nuts, compare, start, end, pivot);partition(bolts, compare, start, end, nuts[index]);sort(nuts, bolts, compare, start, index - 1);sort(nuts, bolts, compare, index + 1, end);}private int partition(String[] strs, NBComparator compare, int start, int end, String pivot) {for(int i = start; i <= end; i++) {if(compare.cmp(strs[i], pivot) == 0 || compare.cmp(pivot, strs[i]) == 0) {swap(strs, start, i);break;}}int i = start + 1; int j = end;while(i <= j) {while(i <= j && (compare.cmp(strs[i], pivot) == -1 || compare.cmp(pivot, strs[i]) == 1)) {i++;}while(i <= j && (compare.cmp(strs[j], pivot) == 1 || compare.cmp(pivot, strs[j]) == -1)) {j--;}if(i <= j) {swap(strs, i, j);i++;j--;}}swap(strs, start, j);  // 一定要把头部换到j,这样才是一个正确的顺序;return j;}private void swap(String[] A, int i, int j) {String temp = A[i];A[i] = A[j];A[j] = temp;}
};

Kth Smallest Element in a Sorted Matrix (两种做法:klogk, (x, y) 被下面和右边的元素压着,那么用pq从小到大排序,然后依次把下面和右边的元素加入pq。另外一种,Binary Search,count  value <= mid的元素有多少个,如果<k个,那么第K大的元素在后面,start = mid; 如果 count >= k个,那么  end = mid; 就是用start和end去逼近那个刚好<=k的值。nlogn; )

Kth Smallest Sum In Two Sorted Arrays (这题把两个sort array每一行跟每一列元素加一下

1+2, 1+4, 1+6

7+2, 7+4, 7+6

11+2, 11+4, 11+6, 那么这题从左到右也是递增的,从上到下也是递增的,这题就完完全全变成了上面的一题;代码都不需要变化多少,matrix[i][j] =  A[i] + A[j]; O(klogk)

Merge k Sorted Lists (这题可以用PQ解决,每次加入队伍的开头,然后取走之后,加入第二大的)另外一种方法就是 利用 merge sort的原理,如果我会做 Merge Two Sorted Lists 那么可以用merge sort原理,劈成两半,然后分别sort。O(nlogk)

Kth Smallest Element in a BST (这里就是inorder traverse的stack版本,然后用count一下即可)关于Tree的traverse和divide conquer可以参考: PreOrder, InOrder, PostOrder 题型总结

Median of two Sorted Arrays 基于 FindKth 的算法。整体思想类似于 median of unsorted array 可以用 find kth from unsorted array 的解题思路。

class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {int n = nums1.length;int m = nums2.length;int k = (n + m) / 2;if((n + m) % 2 == 0) {return 0.5 * (findKth(nums1, 0, nums2, 0, k) + findKth(nums1, 0, nums2, 0, k + 1));} else {return (double)findKth(nums1, 0, nums2, 0, k + 1);}}private int findKth(int[] A, int astart, int[] B, int bstart, int k) {if(astart >= A.length) {return B[bstart + k - 1];}if(bstart >= B.length) {return A[astart + k - 1];}if(k == 1) {return Math.min(A[astart], B[bstart]);}int midA = astart + k/2 - 1 >= A.length ? Integer.MAX_VALUE : A[astart + k/2 - 1];int midB = bstart + k/2 - 1 >= B.length ? Integer.MAX_VALUE : B[bstart + k/2 - 1];if(midA < midB) {return findKth(A, astart + k/2, B, bstart, k - k/2);} else{return findKth(A, astart, B, bstart + k/2, k - k/2);}}
}

Kth Largest in N Arrays 思路:可以swap elements in array,也就是array内部可以sort,sort完之后,从最后每次取最大的,然后用maxheap去找最大的,取走一个,找接下来第二大的入pq;

public class Solution {/*** @param arrays: a list of array* @param k: An integer* @return: an integer, K-th largest element in N arrays*/private class Node {public int x;public int y;public int val;public Node(int x, int y, int val) {this.x = x;this.y = y;this.val = val;}}public int KthInArrays(int[][] arrays, int k) {if(arrays == null || arrays.length == 0 ) {return -1;}PriorityQueue<Node> pq = new PriorityQueue<Node>(k, (a, b) -> (b.val - a.val));int n = arrays.length;for(int i = 0; i < n; i++) {Arrays.sort(arrays[i]);if(arrays[i].length > 0) {int lastIndex = arrays[i].length - 1;pq.offer(new Node(i, lastIndex, arrays[i][lastIndex]));}}int count = 0;while(!pq.isEmpty()) {Node node = pq.poll();count++;if(count == k) {return node.val;}if(node.y - 1 >= 0) {pq.offer(new Node(node.x, node.y - 1, arrays[node.x][node.y - 1]));}}return -1;}
}

Find K Closest Elements 思路:先找到起始start point,然后用打擂台的方法O(K)的去取得最近的值;

class Solution {public List<Integer> findClosestElements(int[] arr, int k, int x) {List<Integer> list = new ArrayList<Integer>();if(arr == null || arr.length == 0) {return list;}int index = findCloset(arr, x);list.add(arr[index]);int i = index-1; int j = index+1;int count = 1;while(count < k) {if(0 <= i && j < arr.length) {if(x - arr[i] <= arr[j] - x) {list.add(0,arr[i--]);} else {list.add(arr[j++]);}} else if(i < 0 && j < arr.length) {list.add(arr[j++]);} else if(i >= 0 && j >= arr.length) {list.add(0,arr[i--]);}count++;}return list;}private int findCloset(int[] A, int target) {int start = 0; int end = A.length - 1;while(start + 1 < end) {int mid = start + (end - start) / 2;if(A[mid] == target) {return mid;} else if(A[mid] < target) {start = mid;} else {end = mid;}}// 如果等于的话,那么取前面的start;if(target - A[start] <= A[end] - target) {return start;}return end;}
}

Find Median from Data Stream (nlogk, 用两个堆来维持关系,左边用最大堆,右边用最小堆,如果num[i] 比最大堆的堆顶小,加入最大堆,否则加入最小堆,然后再调整数目,始终保证最大堆比最小堆数目相等,或者只大于1;)

public class Solution {/*** @param nums: A list of integers* @return: the median of numbers*/private PriorityQueue<Integer> maxheap, minheap;public int[] medianII(int[] A) {if(A == null || A.length == 0) {return new int[0];}int n = A.length;maxheap = new PriorityQueue<Integer>(n, Collections.reverseOrder());minheap = new PriorityQueue<Integer>(n);int[] res = new int[n];for(int i = 0; i < A.length; i++) {if(maxheap.isEmpty() || A[i] <= maxheap.peek()){maxheap.offer(A[i]);} else {minheap.offer(A[i]);}balance();res[i] = maxheap.peek();}return res;}private void balance() {// 保证maxheap的size总是比minheap相等或者大于1;while(maxheap.size() < minheap.size()){maxheap.offer(minheap.poll());}while(minheap.size() < maxheap.size() - 1){minheap.offer(maxheap.poll());}}
}

Sliding Window Median (跟 Find Median from Data Stream类似,用maxheap minheap去维持中位数,不同的地方就是window移动的时候,需要把头部的元素给去掉,注意后面一定要再balance一下;)

public class Solution {/*** @param nums: A list of integers* @param k: An integer* @return: The median of the element inside the window at each moving*/private PriorityQueue<Integer> maxheap, minheap;public List<Integer> medianSlidingWindow(int[] nums, int k) {List<Integer> list = new ArrayList<Integer>();if(nums == null || nums.length == 0 || k <= 0) {return list;}maxheap = new PriorityQueue<Integer>(k / 2 +1, Collections.reverseOrder());minheap = new PriorityQueue<Integer>(k);int n = nums.length;for(int i = 0; i < n; i++) {if(maxheap.size() == 0 || nums[i] <= maxheap.peek()){maxheap.offer(nums[i]);} else {minheap.offer(nums[i]);}balance();if(i == k - 1) { // 这个刚刚等于k的时候,只需要加入list;list.add(maxheap.peek());}if(i >= k) { // i >= k的时候就要开始踢人了;int dropNum = nums[i - k];remove(dropNum);balance(); // drop之后一定要balance一下,因为会出现不均衡情况;list.add(maxheap.peek());}}return list;}// remove的时候只需要跟值进行比较就可以,所以minheap maxheap里面存的都是值;不是index;private void remove(int dropNum) {if(dropNum <= maxheap.peek()){maxheap.remove(dropNum);} else {minheap.remove(dropNum);}}private void balance() {while(maxheap.size() < minheap.size()) {maxheap.offer(minheap.poll());}while(minheap.size() < maxheap.size() - 1){minheap.offer(maxheap.poll());}}
}

Top K Frequent Words  思路:注意这个题目需要最大到最小输出,用maxheap,Nlogk;

class Solution {private class Node {public String word;public int fre;public Node(String word, int fre) {this.word = word;this.fre = fre;}}public List<String> topKFrequent(String[] words, int k) {List<String> list = new ArrayList<String>();HashMap<String, Integer> countmap = new HashMap<String, Integer>();for(String word: words) {countmap.put(word, countmap.getOrDefault(word, 0) + 1);}PriorityQueue<Node> pq = new PriorityQueue<Node>((a, b) -> (a.fre != b.fre ?b.fre - a.fre :                 a.word.compareTo(b.word)));for(String word: countmap.keySet()) {pq.offer(new Node(word, countmap.get(word)));}while(!pq.isEmpty() && k > 0) {list.add(pq.poll().word);k--;}return list;}
}

这篇关于Find Kth题目类型总结 (quick Select 类型总结)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1136275

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter

整数Hash散列总结

方法:    step1  :线性探测  step2 散列   当 h(k)位置已经存储有元素的时候,依次探查(h(k)+i) mod S, i=1,2,3…,直到找到空的存储单元为止。其中,S为 数组长度。 HDU 1496   a*x1^2+b*x2^2+c*x3^2+d*x4^2=0 。 x在 [-100,100] 解的个数  const int MaxN = 3000

状态dp总结

zoj 3631  N 个数中选若干数和(只能选一次)<=M 的最大值 const int Max_N = 38 ;int a[1<<16] , b[1<<16] , x[Max_N] , e[Max_N] ;void GetNum(int g[] , int n , int s[] , int &m){ int i , j , t ;m = 0 ;for(i = 0 ;

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0