[Algorithm][分治 - 快速排序][颜色分类][排序数组][数组中的第K个最大元素][库存管理] + 快速排序原理 详细讲解


0.原理讲解

  • 快排思路:「数组分三块」+「随机选择基准元素」
  • 本质类似二叉树的前序遍历

1.颜色分类

1.题目链接


2.算法原理详解

  • 思路快排思想 + 三指针 -> 数组分三块
  • 遍历数组
    • i:遍历数组
    • left:标记 0 0 0区域的左侧
    • right:标记 2 2 2区域的右侧
  • 区域划分
    • [0, left]:全是 0 0 0
    • [left + 1, i - 1]:全是 1 1 1
    • [i, right - 1]:待扫描的元素
    • [right, n - 1]:全是 2 2 2
      请添加图片描述

3.代码实现

void SortColors(vector<int>& nums) 
{
    int i = 0, left = -1, right = nums.size(); // 三指针
    while(i < right)
    {
        if(nums[i] == 0)
        {
            swap(nums[++left], nums[i++]);
        }
        else if(nums[i] == 1)
        {
            i++;
        }
        else // nums[i] == 2
        {
            // 此处i无需往后迭代,因为此处元素仍属于未扫描
            swap(nums[--right], nums[i]);
        }
    }
}

2.排序数组

1.题目链接


2.算法原理详解

  • 快排思路:「数组分三块」+「随机选择基准元素」
    • 数组分三块:三指针
    • 随机选择基准元素nums[rand() % (right - left + 1) + left]
  • 将数组划分为 左 中 右 三部分:
    • 左边⽐基准元素⼩, 中间与基准元素相同,右边⽐基准元素⼤
    • 然后再去递归的排序左边部分和右边部分即可(可以舍去⼤量的中间部分)
    • 在处理数据量有很多重复的情况下,效率会⼤⼤提升
  • 快排流程
    • 定义递归出口
    • 随机选择基准元素
    • 数组分三块
    • 递归处理左右区间

3.代码实现

vector<int> SortArray(vector<int>& nums) 
{
    srand(time(nullptr)); // 种下随机数种子
    QuickSort(nums, 0, nums.size() - 1);
    return nums;
}

void QuickSort(vector<int>& nums, int l, int r)
{

    if(l >= r)
    {
        return ;
    }

    // 数组分三块
    int key = nums[rand() % (r - l + 1) + l];
    int i = l, 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 // nums[i] > key
        {
            swap(nums[--right], nums[i]);
        }
    }

    // 递归左右区间
    // [l, left] [left + 1, right - 1] [right, r]
    QuickSort(nums, l, left);
    QuickSort(nums, right, r);
}

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

1.题目链接


2.算法原理详解

  • TOPK问题可以用**「堆排序」「快速选择」两个算法实现,此处以「快速选择」**实现
    • 堆排序: O ( N ∗ l o g N ) O(N*logN) O(NlogN)
    • 快速选择: O ( N ) O(N) O(N)
  • 在快排中,把数组「分成三块」之后:
    • 可以计算每⼀个区间内元素的「个数」,进⽽推断出要找的元素是在「哪⼀个区间」⾥⾯
    • 那么直接去「相应的区间」去寻找最终结果就好了
  • 快速选择:快排 + 逻辑修改
    请添加图片描述

3.代码实现

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

int QuickSort(vector<int>& nums, int l, int r, int k)
{
    if(l == r)
    {
        return nums[l];
    }

    // 数组分三块
    int key = nums[rand() % (r - l + 1) + l];
    int i = l, 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 // nums[i] > key
        {
            swap(nums[--right], nums[i]);
        }
    }

    // 分情况讨论
    int c = r - right + 1, b = right - left - 1;
    if(c >= k)
    {
        return QuickSort(nums, right, r, k);
    }
    else if(b + c >= k)
    {
        return key;
    }
    else
    {
        return QuickSort(nums, l, left, k - b - c);
    }
}

4.库存管理 III

1.题目链接


2.算法原理详解

  • 本题有三种方法,但是此处实现**「快速选择」**
    • 排序: O ( N ∗ l o g N ) O(N*logN) O(NlogN)
    • 堆: O ( N ∗ l o g K ) O(N*logK) O(NlogK)
    • 快速选择: O ( N ) O(N) O(N)
  • 思路:随机选择基准元素 + 数组分三块
  • 在快排中,把数组「分成三块」之后,可以通过计算每⼀个区间内元素的「个数」,进⽽推断出最⼩的k个数在哪些区间⾥⾯
    • 可以直接去「相应的区间」继续划分数组即可
      请添加图片描述

3.代码实现

vector<int> InventoryManagement(vector<int>& nums, int k) 
{
    srand(time(nullptr));
    QuickSort(nums, 0, nums.size()- 1, k);
    return {nums.begin(), nums.begin() + k};
}

void QuickSort(vector<int>& nums, int l, int r, int k)
{
    if(l >= r)
    {
        return;
    }

    int key = nums[rand() % (r - l + 1) + l];
    int i = l, 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 // nums[i] > key
        {
            swap(nums[--right], nums[i]);
        }
    }

    // [l, left] [left + 1, right - 1] [right, r]
    // 分情况讨论
    int a = left - l + 1, b = right - left - 1;
    if(a > k)
    {
        QuickSort(nums, l, left, k);
    }
    else if(a + b >= k)
    {
        return;
    }
    else
    {
        QuickSort(nums, right, r, k - a - b);
    }
}
  • 24
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DieSnowK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值