快速排序的运用
75. 颜色分类(中等)
思路一:先遍历数组,计算0,1,2的个数,再分别顺序写入数组。
思路二:采用三路快排的思想。
public void sortColors(int[] nums) {
int zero = -1;
int two = nums.length;
for(int i = 0; i < two; ) {
if(nums[i] == 1)
i++;
else if(nums[i] == 0) {
zero++;
swap(nums, zero, i);
i++;
}else if(nums[i] == 2) {
two--;
swap(nums, two, i);
}
}
}
public static void swap(int [] a,int x,int y){
int temp;
temp=a[x];
a[x]=a[y];
a[y]=temp;
}
215. 数组中的第K个最大元素(中等)
思路一:先排序,时间复杂度为O(NlogN)
思路二:采用优先队列,时间复杂度为O(NlogK)
思路二:采用双路快排,时间复杂度为O(N)
public int findKthLargest(int[] nums, int k) {
return findKthLargest(nums, 0, nums.length-1, nums.length+1-k);
}
public static int findKthLargest(int[] nums, int left, int right, int k) {
if(left < right) {
int number = partition(nums, left, right);
if(number + 1 == k)
return nums[number];
else if(number + 1 > k)
return findKthLargest(nums, left, number-1, k);
else
return findKthLargest(nums, number+1, right, k);
}
else
return nums[left];
}
public static int partition(int[] nums, int left, int right) {
int n = nums[left];
int i = left+1, j = right;
while(true) {
while(i <= j && nums[i] < n)
i++;
while(j >= left + 1 && nums[j] > n)
j--;
if( i > j )
break;
swap(nums, i, j);
i++;
j--;
}
swap(nums, i-1, left);
return i-1;
}
public static void swap(int [] a,int x,int y){
int temp;
temp=a[x];
a[x]=a[y];
a[y]=temp;
}
归并排序的运用
88. 合并两个有序数组(简单)
思路一:归并的思想,要开辟新数组,从前往后遍历。
public void merge(int[] nums1, int m, int[] nums2, int n) {
int[] nums3 = new int[m];
for(int i = 0; i<m; i++) {
nums3[i] = nums1[i];
}
int i = 0,j = 0,k = 0;
while(i < m && j < n) {
if(nums3[i] < nums2[j]) {
nums1[k++] = nums3[i++];
}else{
nums1[k++] = nums2[j++];
}
}
while(i < m)
nums1[k++] = nums3[i++];
while(j < n)
nums1[k++] = nums2[j++];
}
思路二:从后往前遍历,则不需要开辟新的数组。
public void merge2(int[] nums1, int m, int[] nums2, int n) {
int len1 = m - 1;
int len2 = n - 1;
int len = m + n - 1;
while(len1 >= 0 && len2 >= 0) {
// 注意--符号在后面,表示先进行计算再减1,这种缩写缩短了代码
nums1[len--] = nums1[len1] > nums2[len2] ? nums1[len1--] : nums2[len2--];
}
// 表示将nums2数组从下标0位置开始,拷贝到nums1数组中,从下标0位置开始,长度为len2+1
System.arraycopy(nums2, 0, nums1, 0, len2 + 1);
}
还有个从后向前的应用,就是数组后移,需要从后向前遍历。
堆排序的运用
347. 前 K 个高频元素(中等)
public int[] topKFrequent(int[] nums, int k) {
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int num: nums){
if(map.containsKey(num))
map.put(num, map.get(num) + 1);
else
map.put(num, 1);
}
PriorityQueue<Integer> pq = new PriorityQueue<>(
(a, b) -> map.get(a) - map.get(b)
);
for(int key: map.keySet()){
if(pq.size() < k)
pq.add(key);
else if(map.get(key) > map.get(pq.peek())){
pq.remove();
pq.add(key);
}
}
int[] num = new int[k];
int i = 0;
while(!pq.isEmpty()){
num[i] = pq.remove();
i++;
}
return num;
}
比较器的解释说明:父节点索引为K,子节点索引为J,最小堆则data[K] < data[J]。
进行shift down时,判断 if(data.get(k).compareTo(data.get(j)) <= 0 ),则break,不进行任何操作。
所以比较器需要 data[K] < data[J] ,return -1; 才行。