初识算法 · 分治(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};
    }
};

感谢阅读!​

相关推荐
写代码的小球3 小时前
求模运算符c
算法
大千AI助手6 小时前
DTW模版匹配:弹性对齐的时间序列相似度度量算法
人工智能·算法·机器学习·数据挖掘·模版匹配·dtw模版匹配
YuTaoShao7 小时前
【LeetCode 热题 100】48. 旋转图像——转置+水平翻转
java·算法·leetcode·职场和发展
生态遥感监测笔记8 小时前
GEE利用已有土地利用数据选取样本点并进行分类
人工智能·算法·机器学习·分类·数据挖掘
Tony沈哲8 小时前
macOS 上为 Compose Desktop 构建跨架构图像处理 dylib:OpenCV + libraw + libheif 实践指南
opencv·算法
刘海东刘海东9 小时前
结构型智能科技的关键可行性——信息型智能向结构型智能的转变(修改提纲)
人工智能·算法·机器学习
pumpkin845149 小时前
Rust 调用 C 函数的 FFI
c语言·算法·rust
挺菜的9 小时前
【算法刷题记录(简单题)003】统计大写字母个数(java代码实现)
java·数据结构·算法
mit6.8249 小时前
7.6 优先队列| dijkstra | hash | rust
算法