找第k大或者第k小的题型,也是经常面试考,这里做个总结;
首先quick select算法的模板要倒背如流,这个是通过quick sort里面提炼得到的算法;两个while一个if,condition相同;后面再递归
Kth Smallest Numbers in Unsorted Array
找到一个无序数组中第K小的数
Example
样例 1:
输入: [3, 4, 1, 2, 5], k = 3
输出: 3
样例 2:
输入: [1, 1, 1], k = 2
输出: 1
思路:quickselect标准解法:O(N);
public class Solution {
/**
* @param k: An integer
* @param nums: An integer array
* @return: kth smallest element
*/
public int kthSmallest(int k, int[] nums) {
if(nums == null || nums.length == 0 || k <= 0){
return -1;
}
return quickselect(nums, k, 0, nums.length - 1);
}
private int quickselect(int[] nums, int k, int start, int end) {
if(start == end) {
return nums[start];
}
int mid = start + (end - start) / 2;
int pivot = nums[mid];
int i = start; int j = end;
while(i <= j) {
while(i <= j && nums[i] < pivot) {
i++;
}
while(i <= j && nums[j] > pivot) {
j--;
}
if(i <= j) {
swap(nums, i, j);
i++;
j--;
}
}
if(start + k - 1 <= j) {
return quickselect(nums, k, start, j);
}
if(start + k - 1 >= i) {
return quickselect(nums, k - (i -start), i, end);
}
return nums[j+1];
}
private void swap(int[] A, int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
Kth Largest Element
在数组中找到第 k 大的元素。
Example
样例 1:
输入:
n = 1, nums = [1,3,4,2]
输出:
4
思路:是找从大到小的第k大;思路也是跟上面一样,quick select模板走起;
public class Solution {
/**
* @param n: An integer
* @param nums: An array
* @return: the Kth largest element
*/
public int kthLargestElement(int n, int[] nums) {
if(nums == null || nums.length == 0 || n <= 0){
return -1;
}
return quickselect(nums, n, 0, nums.length - 1);
}
private int quickselect(int[] nums, int k, int start, int end) {
if(start == end) {
return nums[start];
}
int mid = start + (end - start) / 2;
int pivot = nums[mid];
int i = start; int j = end;
while(i <= j) {
while(i <= j && nums[i] > pivot) {
i++;
}
while(i <= j && nums[j] < pivot) {
j--;
}
if(i <= j) {
swap(nums, i, j);
i++;
j--;
}
}
if(start + k - 1 <= j) {
return quickselect(nums, k, start, j);
}
if(start + k - 1 >= i) {
return quickselect(nums, k - (i -start), i, end);
}
return nums[j+1];
}
private void swap(int[] A, int i, int j) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
Kth Smallest Element in a Sorted Matrix
给定一个 n x n 矩阵,每一行和每一列都按照升序排序,找出矩阵中的第 k 小元素。
注意是需要找将所有元素有序排列的第 k 小元素,而不是第 k 个互不相同的元素。
Example
样例1
输入:
[[ 1, 5, 9],[10, 11, 13],[12, 13, 15]]
8
输出: 13
思路:这里用priorityqueue也就是堆来实现log(k)去找 最大最小值;Comparator要会写,倒背如流,然后pq的用法也是基本考法,这题几乎就是送分题;O(klogk)
public class Solution {
/**
* @param matrix: List[List[int]]
* @param k: a integer
* @return: return a integer
*/
private class Node {
public int x;
public int y;
public int value;
public Node(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
}
private class NodeComparator implements Comparator<Node> {
@Override
public int compare(Node a, Node b) {
return (a.value - b.value);
}
}
public int kthSmallest(int[][] A, int k) {
if(A == null || A.length == 0 || A[0].length == 0 || k <= 0){
return 0;
}
int[] dx = {0, 1};
int[] dy = {1, 0};
int n = A.length;
int m = A[0].length;
PriorityQueue<Node> pq = new PriorityQueue<Node>(n*m, new NodeComparator());
boolean[][] visited = new boolean[n][m];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
visited[i][j] = false;
}
}
pq.add(new Node(0 , 0, A[0][0]));
visited[0][0] = true;
int count = 0;
while(!pq.isEmpty()){
Node node = pq.poll();
count++;
if(count == k) {
return node.value;
}
int x = node.x;
int y = node.y;
for(int i = 0; i < dx.length; i++){
int nx = x + dx[i];
int ny = y + dy[i];
if((0 <= nx && nx < n && 0 <= ny && ny < m && !visited[nx][ny])){
pq.add(new Node(nx, ny, A[nx][ny]));
visited[nx][ny] = true;
}
}
}
return -1;
}
}
Kth Smallest Sum In Two Sorted Arrays
给定两个排好序的数组 A, B,定义集合 sum = a + b ,其中a来自A数组,b来自B数组,求 sum 中第k小的元素
Example
样例1
输入:
a = [1, 7, 11]
b = [2, 4, 6]
k = 3
输出: 7
说明: 满足条件的所有的和有[3, 5, 7, 9, 11, 13, 13, 15, 17],其中第三个是7.
思路:这题把两个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)
public class Solution {
/**
* @param A: an integer arrays sorted in ascending order
* @param B: an integer arrays sorted in ascending order
* @param k: An integer
* @return: An integer
*/
private class Node {
public int x;
public int y;
public int value;
public Node(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
}
private class NodeComparator implements Comparator<Node> {
@Override
public int compare(Node a, Node b) {
return (a.value - b.value);
}
}
public int kthSmallestSum(int[] A, int[] B, int k) {
if(A == null || A.length == 0 || B == null || B.length == 0 || k <= 0){
return -1;
}
int[] dx = {0, 1};
int[] dy = {1, 0};
int n = A.length;
int m = B.length;
PriorityQueue<Node> pq = new PriorityQueue<Node>(n*m, new NodeComparator());
boolean[][] visited = new boolean[n][m];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
visited[i][j] = false;
}
}
pq.add(new Node(0 , 0, A[0] + B[0]));
visited[0][0] = true;
int count = 0;
while(!pq.isEmpty()){
Node node = pq.poll();
count++;
if(count == k) {
return node.value;
}
int x = node.x;
int y = node.y;
for(int i = 0; i < dx.length; i++){
int nx = x + dx[i];
int ny = y + dy[i];
if((0 <= nx && nx < n && 0 <= ny && ny < m && !visited[nx][ny])){
pq.add(new Node(nx, ny, A[nx] + B[ny]));
visited[nx][ny] = true;
}
}
}
return -1;
}
}
Kth Largest in N Arrays
在N个数组中找到第K大元素
Example
例1:
输入:
k = 3, [[9,3,2,4,7],[1,2,3,4,8]]
输出:
7
解释:
第三大的元素为 7。
思路:这里题目提示了,只能交换array里面的元素,那么就说明array会非常大,那么不可能combine用quick select来做,那么只能把每个array排序,然后用maxheap去做;两点注意:1. array sort之后,可以从尾巴取,也就是取最大;2. ny是可以减少到0的。
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 value;
public Node(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
}
private class NodeComparator implements Comparator<Node> {
@Override
public int compare(Node a, Node b) {
return (b.value - a.value);
}
}
public int KthInArrays(int[][] arrays, int k) {
if(arrays == null || arrays.length == 0 || k <= 0){
return -1;
}
int n = arrays.length;
for(int i = 0; i < n; i++) {
Arrays.sort(arrays[i]);
}
PriorityQueue<Node> pq = new PriorityQueue<Node>(n, new NodeComparator());
for(int i = 0; i < n; i++) {
if(arrays[i].length != 0) {
int j = arrays[i].length - 1;
pq.offer(new Node(i, j, arrays[i][j]));
}
}
int count = 0;
while(!pq.isEmpty()) {
Node node = pq.poll();
count++;
if(count == k) {
return node.value;
}
int nx = node.x;
int ny = node.y - 1;
if(ny >= 0) { // 注意这里y是可以==0的;
pq.offer(new Node(nx, ny, arrays[nx][ny]));
}
}
return -1;
}
}