算法:分治-快速排序

发布于:2025-08-02 ⋅ 阅读:(11) ⋅ 点赞:(0)

1.颜色分类

思路:定义三个变量,i用来遍历数组,left标记0区域的最右测,right标记2区域的最左侧

分成了4段区间

[0, left]: 全是0。

[left + 1, i - 1]:全是1。

[i, right - 1]:待扫描的元素。

[right, n - 1]:全是2。

用i遍历数组时,num[i] == 0时交换++left和i++的值

num[i] == 1时 i++。

nums[i] == 2时, right--,i不变因为[i, right - 1]区间内是带扫描的元素。

注意:初始化时left = -1, right = nums.size()。因为要保证前面的四段区间

class Solution 
{
public:
    void sortColors(vector<int>& nums) 
    {
        int left = -1, right = nums.size();
        int i = 0;
        while(i < right)
        {
            if(nums[i] == 0)
                swap(nums[++left], nums[i++]);
            else if(nums[i] == 1)
                i++;
            else if(nums[i] == 2)
                swap(nums[--right],nums[i]);
        }       
    }
};

2.排序数组

思路:采用三路划分,用随机数取key

用i遍历时,num[i] < key时交换++left和i++的值。

num[i] == key时 i++。

nums[i] > key时, right--,i不变因为[i, right - 1]区间内是带扫描的元素。

  [l, left]        : 所有 < key 的元素
  [left+1, right-1] : 所有 == key 的元素
  [right, r]       : 所有 > key 的元素
class Solution 
{
public:
    vector<int> sortArray(vector<int>& nums) 
    {
        srand(time(NULL)); 
        qsort(nums, 0, nums.size() - 1);
        return nums;
    }

    void qsort(vector<int> &nums, int l, int r)
    {
        if(r <= l) return;//退出条件

        int x = rand();
        int key = nums[x % (r - l + 1) + l];
        int i = l;
        int left = l - 1, right = r + 1;
        while(i < right)
        {
            if(nums[i] < key)
            {
                swap(nums[++left], nums[i++]);
            }
            else if(nums[i] == key)
            {
                i++;
            }
            else
            {
                swap(nums[--right], nums[i]);
            }
        }
        //[l, left] [left + 1, right - 1] [right, r]
        qsort(nums, l, left);
        qsort(nums, right, r);
    }
};

3.数组中的第k个最大元素

思路:快速选择算法 时间复杂度O(N)

1.随机枢轴选择​:key = nums[rand() % (r - l + 1) + l]

2. 三路划分​:

  • 小于 key 的部分:[l, left]
  • 等于 key 的部分:[left+1, right-1]
  • 大于 key 的部分:[right, r]

3.分情况讨论

  • 如果第 k 大元素在右边部分:c = r - right + 1 >= k
  • 如果在中间部分:b + c >= k(直接返回 key)
  • 否则在左边部分:递归处理左侧子数组

该算法的时间复杂度为 O(N) 主要基于:

  1. 线性时间完成每次划分
  2. 随机枢轴确保平均每次将问题规模减半
  3. 算法只沿一个递归路径深度搜索
  4. 三路划分高效处理重复元素
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
        srand(time(NULL));
        return qsort(nums, 0, nums.size() - 1, k);
    }
    int qsort(vector<int>& nums, int l, int r, int k)
    {
        if(l == r) return nums[l];

        int left = l - 1, right = r + 1, i = l;
        int key = nums[rand() % (r - l + 1) + l];//随机取key
        //三路划分
        while(i < right)
        {
            if(nums[i] < key) swap(nums[++left], nums[i++]);
            else if(nums[i] == key) i++;
            else swap(nums[--right], nums[i]);
        }
        //分类讨论
        int c = r - right + 1, b = right - left - 1;
        if(c >= k) return qsort(nums, right, r, k);
        else if(b + c >= k) return key;
        else return qsort(nums, l, left, k - c - b);

    }
};

4.库存管理

LCR 159. 库存管理 III - 力扣(LeetCode)

思路:快速选择算法,将比cnt小的数都放在key前面,前面的数只保持小于key不保持有序。

总体代码思路和第三题代码相似

class Solution 
{
public:
    vector<int> inventoryManagement(vector<int>& stock, int cnt) 
    {
        srand(time(NULL));
        qsort(stock, 0, stock.size() - 1, cnt);
        vector<int> ret(stock.begin(), stock.begin() + cnt);
        return ret;
    }

    void qsort(vector<int> &stock, int l, int r, int k)
    {
        if(l >= r)
            return ;
        int key = stock[rand() % (r - l + 1) + l];
        int left = l - 1, right = r + 1, i = l;
        while(i < right)
        {
            if(stock[i] < key) swap(stock[++left], stock[i++]);
            else if(stock[i] == key) i++;
            else swap(stock[--right], stock[i]);
        }
        int a = left - l + 1, b = right - left - 1;
        if(a > k) qsort(stock, l, left, k);
        else if(a + b >= k) return;
        else qsort(stock, right, r, k - a -b);
    }
};


网站公告

今日签到

点亮在社区的每一天
去签到