跳转至

排序算法

排序算法

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

方法一:快速排序

//快速排序
//左闭右开
void quick_sort(vector<int>& nums, int l, int r) {
    //如果数组大小为1,则无需排序
    if (l + 1 >= r) {
        return;
    }
    //因为传入的是nums.size()所以要减1
    int first = l, last = r - 1, key = nums[first];
    //确定中心点位置为first
    while (first < last) {
        while (first < last && nums[last] >= key) {
            --last;
        }
        //从后往前,找到比key值小的数,搬到first的位置
        nums[first] = nums[last];
        while (first < last && nums[first] <= key) {
            ++first;
        }
        //从前往后,找到比key值大的数,搬到刚才空出来的last的位置
        nums[last] = nums[first];
    }
    //把key值赋给first位,此时的first=last
    nums[first] = key;
    //对低子表递归排序
    quick_sort(nums, l, first);
    //对高子表递归排序
    quick_sort(nums, first + 1, r);
}

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        quick_sort(nums, 0, nums.size());
        return nums[nums.size() - k];
    }
};

方法二:sort排序

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        return nums[nums.size() - k];
    }
};

方法三:优先队列,小顶堆

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int, vector<int>, greater<int>> res;
        for (auto& a : nums) {
            res.push(a);
            if (res.size() > k)
                res.pop();
        }
        return res.top();
    }
};

347 前K个高频元素

方法一:桶排序

class Solution {
public:
    vector<int> topKFrequent(vector<int>& nums, int k) {
        unordered_map<int, int> counts;
        int max_count = 0;
        //查找最大频次
        //根据每个数的频次放入unordered_map容器 1:4, 2:2, 3:1, 4:1
        for (const int& num : nums) {
            max_count = max(max_count, ++counts[num]);
        }
        //按照频次建立4个新桶,1:[3,4], 2:[2], 3:[1], 4:[1]
        vector<vector<int>> buckets(max_count + 1);
        for (const auto& p : counts) {
            buckets[p.second].push_back(p.first);
        }
        //从后往前遍历,直到找到k个频次最高的桶
        vector<int> ans;
        for (int i = max_count; i >= 0 && ans.size() < k; --i) {
            for (const int& num : buckets[i]) {
                ans.push_back(num);
                if (ans.size() == k) {
                    break;
                }
            }
        }
        return ans;
    }
};

532 数组中的k-diff数对

方法1:排序+二分查找

class Solution {
public:
    int findPairs(vector<int>& nums, int k) {
        int n=nums.size(),res=0;
        // 对数组进行排序
        sort(nums.begin(),nums.end());
        // 从左到右比遍历,在[i+1,n-1]的范围内二分查找nums[i]+k是否存在即可
        for(int i=0;i<n-1;i++){
            // 重复的不计算
            if(i>0 && nums[i]==nums[i-1]){
                continue;
            }
            int target=nums[i]+k;
            int left=i+1,right=n-1;
            int ans=-1;
            while(left<=right){
                int mid=left+(right-left)/2;
                if(nums[mid]>=target){
                    ans=mid;
                    right=mid-1;
                }
                else{
                    left=mid+1;
                }
            }
            // 判断是否找到
            if(ans!=-1 && nums[ans]==target){
                res++;
            }
        }
        return res;
    }
};

912 排序数组

方法1:冒泡排序(超时)

冒泡排序是从左到右依次比较相邻的两个元素,如果前一个元素比较大,就把前一个元素和后一个交换位置,遍历数组之后保证最后一个元素相对于前面的永远是最大的。然后让最后一个保持不变,重新遍历前n-1个元素,保证第n-1个元素在前n-1个元素里面是最大的。依此规律直到第2个元素是前2个元素里面最大的,排序就结束了。

因为这个排序的过程很像冒泡泡,找到最大的元素不停的移动到最后端,所以这个排序算法就叫冒泡排序。

冒泡排序的最大特点就是代码简单,短短的五行代码就能完成整个排序的操作。

时间复杂度比较稳定不管怎样都需要O(n^2)次比较,时间复杂度

空间复杂度是O(1),所有操作在原来的数组完成就可以了,不需要额外的空间。

算法是稳定的,在冒泡的过程中如果两个元素相等,那么他们的位置是不会交换的。

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        int n=nums.size();
        for(int i=0;i<n;i++){
            for(int j=0;j<n-i-1;j++){
                if(nums[j]>nums[j+1]){
                    swap(nums[j], nums[j+1]);
                }
            }
        }
        return nums;
    }
};

插入排序(超时)

选择排序(超时)

快速排序(超时)

因为有很极端的例子,全部相等、或者倒序,让时间复杂度恶化为\(O(n^2)\)

方法2:希尔排序(可过)

class Solution {
public:
    void shell(vector<int>& nums, int gap, int i){
        int inserted=nums[i];
        int j;
        for(j=i-gap;j>=0 && inserted<nums[j];j-=gap){
            nums[j+gap]=nums[j];
        }
        nums[j+gap]=inserted;
    }

    vector<int> sortArray(vector<int>& nums) {
        int len=nums.size();
        for(int gap=len/2;gap>0;gap/=2){
            for(int i=gap;i<len;i++){
                shell(nums, gap, i);
            }
        }
        return nums;
    }
};

方法3:归并排序(可过)

class Solution {
public:
    void sort(vector<int>& nums, vector<int>& numsTemp, int low, int high){
        if(low>=high) return;
        int len =high-low;
        int mid=low+len/2;
        int start1=low, end1=mid, start2=mid+1, end2=high;
        sort(nums, numsTemp, start1, end1);
        sort(nums, numsTemp, start2, end2);
        int index=low;
        while(start1<=end1 && start2<=end2){
            numsTemp[index++]=nums[start1]<nums[start2]?nums[start1++]:nums[start2++];
        }

        while(start1<=end1){
            numsTemp[index++]=nums[start1++];
        }
        while(start2<=end2){
            numsTemp[index++]=nums[start2++];
        }

        for(index=low;index<=high;++index){
            nums[index]=numsTemp[index];
        }
    }


    vector<int> sortArray(vector<int>& nums) {
        int len=nums.size();
        vector<int> numsTemp(len, 0);
        sort(nums, numsTemp, 0, nums.size()-1);
        return nums;
    }
};

方法4:堆排序(可过)

class Solution {
public:
    void heapify(vector<int>& nums, int n, int i){
        int l=i*2+1;
        int r=i*2+2;
        int max=i;
        if(l<n && nums[l]>nums[max]) max=l;
        if(r<n && nums[r]>nums[max]) max=r;
        if(max!=i){
            swap(nums[max], nums[i]);
            heapify(nums, n, max);
        }
    }

    void heapify_build(vector<int>& nums, int n){
        int parent=(n-2)/2;
        for(int i=parent;i>=0;i--){
            heapify(nums, n, i);
        }
    }


    vector<int> sortArray(vector<int>& nums) {
        int n=nums.size();
        heapify_build(nums, n);
        for(int i=0;i<n;i++){
            swap(nums.front(), nums[n-i-1]);
            heapify(nums, n-i-1, 0);
        }
        return nums;
    }
};

方法4:堆排序(就记这个)

class Solution {
public:
    /* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
    void shiftDown(vector<int>& nums, int n, int i){
        while(true){
            int l=2*i+1;
            int r=2*i+2;
            int ma=i;
            if(l<n && nums[l]>nums[ma]){
                ma=l;
            }
            if(r<n && nums[r]>nums[ma]){
                ma=r;
            }
            if(ma==i){
                break;
            }
            swap(nums[ma], nums[i]);
            i=ma;
        }
    }

    vector<int> sortArray(vector<int>& nums) {
        int n=nums.size();
        for(int i=(n-2)/2;i>=0;i--){
            shiftDown(nums, n, i);
        }

        for(int i=nums.size()-1;i>0;i--){
            swap(nums[0], nums[i]);
            shiftDown(nums, i, 0);
        }
        return nums;
    }
};