public class Solution {
public int findKthLargest(int[] nums, int k) {
return partition(nums, k, 0, nums.length - 1);
}
private int partition(int[] nums, int k, int start, int end){
int pivot = nums[start];
int left = start;
int right = end;
while(left <= right){
while(left <= right && nums[left] >= pivot) left++;
while(left <= right && nums[right] <= pivot) right--;
if(left < right) swap(nums, left, right);
}
swap(nums, start, right);
if(k == right + 1) return nums[right];
if(k > right + 1){
return partition(nums, k, right + 1, end);
} else {
return partition(nums, k, start, right - 1);
}
}
private void swap(int[] nums, int a, int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
这题也可以用 3-way partitioning 的思路写,复杂度一样
public class Solution {
public int findKthLargest(int[] nums, int k) {
return partition(nums, k, 0, nums.length - 1);
}
private int partition(int[] nums, int k, int start, int end){
int pivot = nums[start];
int left = start;
int right = end;
int cur = start;
while(cur <= right){
if(nums[cur] > pivot){
swap(nums, cur ++, left ++);
} else if (nums[cur] < pivot){
swap(nums, cur, right--);
} else {
cur ++;
}
}
right = cur - 1;
if(k == right + 1) return nums[right];
if(k > right + 1){
return partition(nums, k, right + 1, end);
} else {
return partition(nums, k, start, right - 1);
}
}
private void swap(int[] nums, int a, int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
全不带等号的比较方式,如果 pivot 元素有唯一对应,可以 partition 并且 left == right 停留在 pivot 上;否则多个等于 pivot 时会死循环,因为不带等号无法让指针跨过 等于 pivot 的元素。
/**
* 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) {
// write your code here
helper(nuts, bolts, compare, 0, nuts.length - 1);
}
private void helper(String[] nuts, String[] bolts, NBComparator compare,
int start, int end){
if(start >= end) return;
int pivot = partitionNuts(nuts, bolts[start], start, end, compare);
partitionBolts(bolts, nuts[pivot], start, end, compare);
helper(nuts, bolts, compare, start, pivot - 1);
helper(nuts, bolts, compare, pivot + 1, end);
}
private int partitionNuts(String[] nuts, String bolt, int start, int end,
NBComparator compare){
int left = start;
int right = end;
while(left < right){
while(left < right && compare.cmp(nuts[left], bolt) < 0) left ++;
while(left < right && compare.cmp(nuts[right], bolt) > 0) right --;
if(left < right) swap(nuts, left, right);
}
// 最终 left = right ,都停留在 pivot 上
return left;
}
private int partitionBolts(String[] bolts, String nut, int start, int end,
NBComparator compare){
int left = start;
int right = end;
while(left < right){
while(left < right && compare.cmp(nut, bolts[left]) > 0) left ++;
while(left < right && compare.cmp(nut, bolts[right]) < 0) right --;
if(left < right) swap(bolts, left, right);
}
return right;
}
private void swap(String[] arr, int a, int b){
String temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
};
只有在和 right 换元素时,cur 指针的位置是不动的,因为下一轮还要看一下换过来的元素是不是 < key 要放到左边。
O(n) 时间复杂度
public class Solution {
public void sortColors(int[] nums) {
int left = 0;
int right = nums.length - 1;
int i = 0;
while(i <= right){
if(nums[i] < 1){
swap(nums, left++, i++);
} else if(nums[i] > 1){
swap(nums, i, right--);
} else {
i ++;
}
}
}
private void swap(int[] nums, int a, int b){
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
3-way partition 的进阶版本,k-way partition.
利用已知最大和最小 key,维护双指针对撞
数组结构是
【最小key】【cur + unknown】【最大key】
这种写法的复杂度分析稍微麻烦一些,最大为 O(n * k/2) 每次复杂度上限为O(n),最多进行 k / 2 次循环,然而要考虑每次迭代会固定去掉头尾两部分数组,导致 n 逐渐变小,实际的复杂度要根据 k 个数字的分部情况来看,k 的分布越偏向于【1,k】 的两侧,复杂度就越低。
class Solution {
/**
* @param colors: A list of integer
* @param k: An integer
* @return: nothing
*/
public void sortColors2(int[] colors, int k) {
// write your code here
int left = 0;
int right = colors.length - 1;
int cur;
int lowColor = 1;
int highColor = k;
while(lowColor < highColor){
cur = left;
while(cur <= right){
if(colors[cur] == lowColor){
swap(colors, cur ++, left ++);
} else if(colors[cur] == highColor){
swap(colors, cur, right --);
} else {
cur ++;
}
}
lowColor ++;
highColor --;
}
}
private void swap(int[] colors, int a, int b){
int temp = colors[a];
colors[a] = colors[b];
colors[b] = temp;
}
}
public class Solution {
/**
*@param chars: The letter array you should sort by Case
*@return: void
*/
public void sortLetters(char[] chars) {
//write your code here
int left = 0;
int right = chars.length - 1;
int cur = 0;
while(cur <= right){
if(chars[cur] >= 'a'){
swap(chars, cur ++, left ++);
} else if(chars[cur] < 'a'){
swap(chars, cur, right--);
} else {
cur ++;
}
}
}
private void swap(char[] chars, int a, int b){
char temp = chars[a];
chars[a] = chars[b];
chars[b] = temp;
return;
}
}