初识算法 · 分治(2)

目录

前言:

数组中的第K个最大元素

题目解析

算法原理

算法编写

库存管理

题目解析

算法原理

算法编写


前言:

​本文的主题是分治,通过两道题目讲解,一道是数组中的第k个最大元素,一道是最小的k个数。

链接分别为:
215. 数组中的第K个最大元素 - 力扣(LeetCode)

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

题目分为三个部分讲解,一是题目解析,二是算法原理,三是算法编写,那么,话不多说,直接进行主题咯。


数组中的第K个最大元素

题目解析

题目的要求非常简单,让我们找出数组中的第K个大的元素,该题目是上篇文章中快速排序的Top K问题,所以该道题目的基础是颜色分类那道题目和数组分三块的思想。

那么直接进入算法原理部分咯。

算法原理

在前文我们知道,我们利用三个指针,将数组划分成了三个区域,分别是小于K的,等于K的,大于K的,那么我们要在该区域里面查找到第K个最大的元素,其实当我们划分好了区域之后,我们不妨分情况讨论,对于第三个区域,命中第K个数的可能性是最大的。

所以我们首先可以讨论C区域,对于讨论的前提是我们应该知道该区域有多少个元素,如果该区域的元素甚至没有K个,那么肯定就不用在这里找了,我们应该直接去找B区域,所以判断条件应该是C >= K,如果满足该条件,就直接在该区域找,这样,a和b区域的值就直接排掉了,就大大减少了时间复杂度。所以同样的,递归式的在该区域里面查找。

对于第二个区域,因为第二个区域所有的元素都是一样的,如果在该区域查找了,我们直接返回该区域的任何一个值就可以了。

对于第一个区域,也就是a,如果走到了该区域,就说明b和c两个区域都不满足条件,也就是说,k的值应该是大于b + c的,此时我们不妨将题目要求改变一下,它不是要找最大的第K个值吗,但是这个K又比较大,我们就可以将题目转换为,在a区域里面,找k - b - c的最大值,因为a区域里面的值都是小的,里面找K是行不通的,毕竟区间都变化了。

所以该题目我们甚至是可以直接使用快排的模板,然后分情况讨论即可。

算法编写

cpp 复制代码
class Solution 
{
public:
    int GetRandom(vector<int>& v, int left, int right) 
    {
        return v[rand() % (right - left + 1) + left];
    }
    int qsort(vector<int>& v, int left, int right, int k) 
    {
        if (left >= right) return v[left];
        int key = GetRandom(v, left, right);
        int _left = left - 1, _right = right + 1, cur = left;
        while (cur < _right) 
        {
            if (v[cur] < key)
                swap(v[++_left], v[cur++]);
            else if (v[cur] == key)
                cur++;
            else
                swap(v[--_right], v[cur]);
        }
        int b = _right - _left - 1, c = right - cur + 1;
        if (c >= k)
            return qsort(v, _right, right, k);
        else if (b + c >= k) 
            return key;
        else return qsort(v, left, _left, k - c - b);
    }
    int findKthLargest(vector<int>& nums, int k) 
    {
        srand((unsigned int)time(NULL));
        return qsort(nums, 0, nums.size() - 1, k);
    }
};

库存管理

题目解析

题目要求也是很简单,返回最小的k个数即可,对于这种题目,一共有四种题型,分别是找最大的第K个数,找最小的第K个数,找最小的K个数,找最大的K个数。

题目的基本思路都是一样的,我们直接进入算法原理部分吧,

算法原理

其实对于这道题的解法非常多的,可以直接排序,然后返回,时间复杂度是N* LogN,也可以使用大小堆,时间复杂度是N * logK,但是都没有N来的简单。

我们使用快速选择排序算法可以实现N,基本思想还是一样的,数组分为三块,随机选择基准数即可。

那么我们主要是要讨论:

以上三种情况,对于第一种情况,如果a > k的情况,那么我们直接在里面找就可以了。如果是不满足该条件,我们就应该去第二个区间里面查找,此时因为我们已经将最小的数防在了一起,直接返回就可以了。

当以上的两种情况都不满足的话,我们就应该在第三个区间找,此时我们已经找到了a + b个元素,我们只需要找剩下的k - a - b个元素就可以了。

所以只需要将上面的题目稍加改动就可以了。

算法编写

cpp 复制代码
class Solution 
{
public:
    int GetRandom(vector<int>& v, int left ,int right)
    {
        return v[rand() % (right - left + 1) + left];
    }
    void qsort(vector<int>& v, int left, int right, int k)
    {
        if(left >= right) return;
        int _left = left - 1, _right = right + 1, cur = left;
        int key = GetRandom(v, left, right);
        while(cur < _right)
        {
            if(v[cur] < key) swap(v[++_left],v[cur++]);
            else if(v[cur] == key) cur++;
            else swap(v[--_right],v[cur]);
        }
        int a = _left - left + 1, b = (_right - 1) - (_left + 1) + 1;
        if(a > k) qsort(v, left, _left, k);
        else if(a + b >= k) return;
        else qsort(v, _right, right, k - a - b); 
    }
    vector<int> inventoryManagement(vector<int>& nums, int k) 
    {
        srand((unsigned int)time(NULL));
        qsort(nums,0, nums.size() - 1, k);
        return { nums.begin(), nums.begin() + k};
    }
};

感谢阅读!​

相关推荐
fancy16616629 分钟前
力扣top100 矩阵置零
人工智能·算法·矩阵
元亓亓亓1 小时前
LeetCode热题100--240.搜索二维矩阵--中等
算法·leetcode·矩阵
明月看潮生2 小时前
青少年编程与数学 02-019 Rust 编程基础 09课题、流程控制
开发语言·算法·青少年编程·rust·编程与数学
oioihoii2 小时前
C++23 views::slide (P2442R1) 深入解析
linux·算法·c++23
yuhao__z2 小时前
代码随想录算法训练营第六十三天| 图论9—卡码网47. 参加科学大会,94. 城市间货物运输 I
算法·图论
June`3 小时前
专题三:穷举vs暴搜vs深搜vs回溯vs剪枝(全排列)决策树与递归实现详解
c++·算法·深度优先·剪枝
vlln3 小时前
适应性神经树:当深度学习遇上决策树的“生长法则”
人工智能·深度学习·算法·决策树·机器学习
冲帕Chompa4 小时前
图论part09dijkstra算法
算法·图论
·云扬·4 小时前
【PmHub后端篇】PmHub中基于Redis加Lua脚本的计数器算法限流实现
redis·算法·lua
周Echo周4 小时前
20、map和set、unordered_map、un_ordered_set的复现
c语言·开发语言·数据结构·c++·算法·leetcode·list