LeetCode-排序

思想

如何写程序:分析程序代码:入口,分叉逻辑(各个分支情况列举),出口考虑(各种边界条件,特别是=的情况)

控制结束的条件,初始,各个分支情况流程逻辑;结束时的条件:(正常结束,异常结束,边界值)

快速选择:用于求解Kth Element问题,也就是第K个元素的问题。

可以使用快速排序的partition()进行实现。需要先打乱数组,否则最坏情况下时间复杂度是$O\left(N^{2}\right)$.

用于求解TopK Elements问题,也是就是K个最小元素的问题。可以维护一个大小为K的最小堆,最小堆中的元素就是最小元素。最小堆要用大顶堆来实现,大顶堆表示堆顶元素是堆中最大元素。这是因为我们要得到k个最小的元素,因此当遍历到一个新的元素时,需要知道这个新元素是否比堆中的最大元素更小,更小的话就把堆中的最大元素去除,并将新元素添加到堆中。所以我们需要很容易的得到最大元素并移除最大元素,大顶堆可以很好的满足这个要求。

堆也是用于与求解Kth Element问题,得到了大小为k的最小堆之后,因为使用了大顶堆来实现,因此堆顶元素就是第K大的元素

快速选择也可以求解TopK Elements问题,因为找到Kth Element之后,遍历一次数组,所有小于等于KthElement的元素都是TopK Elements。

可以看到,快速选择和堆排序都可以求解 Kth Element 和 TopK Elements 问题。第K个元素和前K元素

215. Kth Largest Element in an Array (Medium)

Kth Element

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.

题目描述:找到倒数第 k 个的元素。

solution 1:

1
2
3
4
5
6
7
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
return nums[nums.size() - k];
}
};

solution 2:

1
2
3
4
5
6
7
8
9
10
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int> q(nums.begin(), nums.end());
for(int i = 0; i < k, i++) {
q.pop();
}
return q.top();
}
};

熟悉快排:核心思想是每次都要先找一个中枢点Pivot然后遍历其他所有的数字,像这道题从大往小排的话,就把大于中枢点的数字放到左半边,把小于中枢点的放在右半边,这样中枢点是整个数组中第几大的数字就确定了,虽然左右两部分各自不一定是完全有序的,但是并不影响本题要求的结果,因为左半部分的所有值都大于右半部分的任意值,所以我们求出中枢点的位置,如果正好是k-1,那么直接返回该位置上的数字;如果大于k-1,说明要求的数字在左半部分,更新右边界,再求新的中枢点位置;反之则更新右半部分,求中枢点的位置;

桶排序

1. 出现频率最多的 k 个元素

  1. Top K Frequent Elements

    Given a non-empty array of integers, return the k most frequent elements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Integer> frequencyForNum = new HashMap<>();
for (int num : nums) {
frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1);
}
List<Integer>[] buckets = new ArrayList[nums.length + 1];
for (int key : frequencyForNum.keySet()) {
int frequency = frequencyForNum.get(key);
if (buckets[frequency] == null) {
buckets[frequency] = new ArrayList<>();
}
buckets[frequency].add(key);
}
List<Integer> topK = new ArrayList<>();
for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) {
if (buckets[i] == null) {
continue;
}
if (buckets[i].size() <= (k - topK.size())) {
topK.addAll(buckets[i]);
} else {
topK.addAll(buckets[i].subList(0, k - topK.size()));
}
}
return topK;
}

设置若干个桶,每个桶存储出现频率相同的数。桶的下标表示数出现的频率,即第 i 个桶中存储的数出现的频率为 i。把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer, Integer> frequencyForNum = new HashMap<>();
for (int num : nums) {
frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1);
}
List<Integer>[] buckets = new ArrayList[nums.length + 1];
for (int key : frequencyForNum.keySet()) {
int frequency = frequencyForNum.get(key);
if (buckets[frequency] == null) {
buckets[frequency] = new ArrayList<>();
}
buckets[frequency].add(key);
}
List<Integer> topK = new ArrayList<>();
for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) {
if (buckets[i] == null) {
continue;
}
if (buckets[i].size() <= (k - topK.size())) {
topK.addAll(buckets[i]);
} else {
topK.addAll(buckets[i].subList(0, k - topK.size()));
}
}
return topK;
}

2. 按照字符出现次数对字符串排序

451. Sort Characters By Frequency (Medium)

Given a string, sort it in decreasing order based on the frequency of characters.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public String frequencySort(String s) {
Map<Character, Integer> frequencyForNum = new HashMap<>();
for (char c : s.toCharArray())
frequencyForNum.put(c, frequencyForNum.getOrDefault(c, 0) + 1);

List<Character>[] frequencyBucket = new ArrayList[s.length() + 1];
for (char c : frequencyForNum.keySet()) {
int f = frequencyForNum.get(c);
if (frequencyBucket[f] == null) {
frequencyBucket[f] = new ArrayList<>();
}
frequencyBucket[f].add(c);
}
StringBuilder str = new StringBuilder();
for (int i = frequencyBucket.length - 1; i >= 0; i--) {
if (frequencyBucket[i] == null) {
continue;
}
for (char c : frequencyBucket[i]) {
for (int j = 0; j < i; j++) {
str.append(c);
}
}
}
return str.toString();
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×