[算法题]排序数组

题目链接: 排序数组

快速排序求解

两个重点:

1. 选取随机数做 key, 不止固定选最左边的数做 key, 避免在数据有序时退化成 O(n^2) 的时间复杂度, 取 key 下标公式:

rand() % (end - begin + 1) + begin (加上begin偏移, 保证当前的 key 在当前的区间内)

2. 三段划分, 将区间划分为 [begin, left] [left + 1, right - 1] [right, end], 如图:

遍历进行中的区间划分, 如图:

划分出来的区间内的值具有如上特性, 这样可以避免数据中有大量重复的值的问题, 因为每次递归的区间只有左边的区间和右边的区间, 中间的区间不会递归, 所以当有大量重复的值时, 递归次数会大大减少.

划分区间的方法, 定义一个变量 i 并赋值为当前区间的 begin, 并且定义变量 left = begin - 1, right = end + 1, 然后以 i 为下标循环遍历当前区间, 循环结束条件为 i == right, 然后要明确:

[begin, left]: 都是小于key的值

[left + 1, right - 1]: 都是等于key的值

[right, end]: 都是大于key的值

根据这些条件, 得出更新区间的规则:

while(i < right)

{

        if(nums[i] < key) swap(nums[++left], nums[i++]); //因为 nums[i] 是小于 key 的, 而区间 [begin, left] 里都是小于 key 的值, 所以要先让 left++, 此时 left 移动到的位置只可能是当前 i 的位置或者是等于 key 的值的位置, 用这个值和 nums[i] 交换没有一点问题, 将比 key 小的数交换后 i 再++

        else if(nums[i] == key) i++; //因为区间 [left + 1, i] 里都是等于 key 的值, 既然当前值也等于 key, 那么 i 直接++就好了

        else swap(nums[--right], nums[i]); //因为 nums[i] 是大于 key 的, 而区间 [right, end] 里都是大于 key 的值, 所以要先让 right--, 此时 right 移动到的位置是没有被遍历过的未知值, 用这个值和 nums[i] 交换没有一点问题, 将比 key 大的数交换后 i 一定不能++, 因为被交换过来的值是未知值, 还需要在下一轮判断后操作

}

题解代码:

class Solution 
{
public:
    void _sortArray(vector<int>& nums, int begin, int end)
    {
        if(begin >= end) return;
        int left = begin - 1, right = end + 1;
        int key = nums[rand() % (end - begin + 1) + begin];
        int i = begin;
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]);
        }
        _sortArray(nums, begin, left);
        _sortArray(nums, right, end);
    }

    vector<int> sortArray(vector<int>& nums) 
    {
        srand(time(nullptr));
        _sortArray(nums, 0, nums.size() - 1);
        return nums;    
    }
};

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值