title: LC101の4. 排序
urlname: yz566z
date: ‘2021-06-08 14:46:14’
tags: [排序]
categories: [算法刷题]


教程

https://zhuanlan.zhihu.com/p/52884590

算法解释

快速排序

思路

找一个基准数,将比它小的丢到左边,比它大的丢到右边
递归地对左右区间做同样操作

图解

LC101の4. 排序 - 图2

代码

  1. void quick_sort(vector<int> &nums, int l, int r) {
  2. if(l + 1 >= r){
  3. return;
  4. }
  5. int first = l, last = r - 1, key = nums[first];
  6. while(first < last){
  7. while(first < last && nums[last] >= key){
  8. last--;
  9. }
  10. nums[first] = nums[last];
  11. while(first < last && nums[first] <= key){
  12. first++;
  13. }
  14. nums[last] = nums[first];
  15. }
  16. nums[first] = key;
  17. quick_sort(nums,l,first);
  18. quick_sort(nums,first + 1,r);
  19. }

归并排序

思路

分成两半,排序,合并
每一半再分成两半,排序,合并
直到分成一个元素,不用排序,直接合并
ps:思想简单,代码简单。合并时需要开辟额外空间,时间复杂度 O(nlogn)

图解

LC101の4. 排序 - 图3

代码

  1. void merge_sort(vector<int> &nums, int l, int r, vector<int> &temp) {
  2. if (l + 1 >= r) {
  3. return;
  4. }
  5. // divide
  6. int m = l + (r - l) / 2;
  7. merge_sort(nums, l, m, temp);
  8. merge_sort(nums, m, r, temp);
  9. // conquer
  10. int p = l, q = m, i = l;
  11. while (p < m || q < r) {
  12. if (q >= r || (p < m && nums[p] <= nums[q])) {
  13. temp[i++] = nums[p++];
  14. } else {
  15. temp[i++] = nums[q++];
  16. }
  17. }
  18. for (i = l; i < r; ++i) {
  19. nums[i] = temp[i];
  20. }
  21. }

插入排序

思路

每一次将一个待排序地数插入到已排好的数列中,从后往前比较

图解

LC101の4. 排序 - 图4

代码

  1. void insertion_sort(vector<int> &nums, int n){
  2. for(int i = 0; i < n; i++){
  3. for(int j = i; j > 0 && nums[j] < nums[j - 1]; j--){
  4. swap(nums[j], nums[j - 1]);
  5. }
  6. }
  7. }

冒泡排序

  1. void bubble_sort(vector<int> &nums, int n){
  2. for(int i = 0; i < n - 1; i++){
  3. for(int j = 0; j < n - 1 - i; j++){
  4. if(nums[j] > nums[j + 1]){
  5. swap(nums[j], nums[j + 1]);
  6. }
  7. }
  8. }
  9. }

选择排序

每次找到最小(大)的放到开头

  1. void selection_sort(vector<int> &nums, int n){
  2. int mid;
  3. for(int i = 0; i < n - 1; i++){
  4. mid = i;
  5. for(int j = i + 1; j < n; j++){
  6. if(nums[j] < nums[mid]){
  7. mid = j;
  8. }
  9. }
  10. swap(nums[mid], nums[i]);
  11. }
  12. }

测试代码

  1. int main(){
  2. vector<int> nums = {1,3,5,7,2,6,4,8,9,2,8,7,6,0,3,5,9,4,1,0};
  3. vector<int> temp(nums.size());
  4. // quick_sort(nums, 0, nums.size());
  5. // merge_sort(nums,0,nums.size(),temp);
  6. // insertion_sort(nums,nums.size());
  7. // bubble_sort(nums,nums.size());
  8. selection_sort(nums,nums.size());
  9. for(int i = 0; i < nums.size(); i++){
  10. cout<<nums[i]<<' ';
  11. }
  12. return 0;
  13. }

快速选择

215. 数组中的第 K 个最大元素

  1. class Solution {
  2. public:
  3. int findKthLargest(vector<int>& nums, int k) {
  4. int l = 0, r = nums.size() - 1, target = nums.size() - k;
  5. while(l < r){
  6. int mid = quickSort(nums, l, r);
  7. if(mid == target){
  8. return nums[mid];
  9. }
  10. else if(mid < target){
  11. l = mid + 1;
  12. }else{
  13. r = mid - 1;
  14. }
  15. }
  16. return nums[l];
  17. }
  18. int quickSort(vector<int> &nums, int l, int r){
  19. int i = l + 1, j = r;
  20. while(true){
  21. while(i < r && nums[i] <= nums[l]){
  22. i++;
  23. }
  24. while(l < j && nums[j] >= nums[l]){
  25. j--;
  26. }
  27. if(i >= j)break;
  28. swap(nums[i], nums[j]);
  29. }
  30. swap(nums[l], nums[j]);
  31. // 比j大的在右,比j小的在左
  32. return j;
  33. }
  34. };

桶排序

347. 前 K 个高频元素

  1. class Solution {
  2. public:
  3. vector<int> topKFrequent(vector<int>& nums, int k) {
  4. int max_count = 0;
  5. unordered_map<int, int> counts;
  6. //统计每个数字出现次数
  7. for(int i = 0; i < nums.size(); i++){
  8. max_count = max(max_count, ++counts[nums[i]]);
  9. }
  10. //将counts存入buckets(1-3,2-2,3-1)
  11. vector<vector<int>> buckets(max_count + 1);
  12. for(const auto & p : counts){
  13. // cout<<p.second<<' '<<p.first<<endl;
  14. buckets[p.second].push_back(p.first);
  15. }
  16. vector<int> ans;
  17. int now = max_count, num = 0;
  18. //将前k个存入ans
  19. while(now){
  20. if(num == k)break;
  21. for(const int & bucket : buckets[now]){
  22. ans.push_back(bucket);
  23. num++;
  24. }
  25. now--;
  26. }
  27. return ans;
  28. }
  29. };

练习

451. 根据字符出现频率排序

  1. class Solution {
  2. public:
  3. string frequencySort(string s) {
  4. unordered_map<char, int> num;
  5. int max_count = 0;
  6. for(int i = 0; i < s.size(); i++){
  7. max_count = max(max_count,++num[s[i]]);
  8. }
  9. unordered_map<int, string> temp;
  10. for(const auto & p : num){
  11. // cout<<p.second<<' '<<p.first<<endl;
  12. temp[p.second] += p.first;
  13. }
  14. string ans = "";
  15. for(int i = max_count; i > 0; i--){
  16. if(temp[i] != ""){
  17. //a,c
  18. for(int j = 0; j < temp[i].size(); j++){
  19. for(int k = 0; k < i; k++){
  20. ans += temp[i][j];
  21. }
  22. }
  23. }
  24. }
  25. return ans;
  26. }
  27. };

75. 颜色分类

  1. class Solution {
  2. public:
  3. void sortColors(vector<int>& nums) {
  4. // sort(nums.begin(),nums.end());
  5. int p = 0, q = nums.size() - 1;
  6. for (int i = 0; i <= q; ++i) {
  7. if (nums[i] == 0) {
  8. nums[i] = nums[p];
  9. nums[p] = 0;
  10. ++p;
  11. }
  12. if (nums[i] == 2) {
  13. nums[i] = nums[q];
  14. nums[q] = 2;
  15. --q;
  16. if (nums[i] != 1) {
  17. --i;
  18. }
  19. }
  20. }
  21. }
  22. };