【分支-快速排序】

news2024/9/17 1:40:07

【分支-快速排序】

  • 1. 颜色分类
    • 1.1 题目来源
    • 1.2 题目描述
    • 1.3 题目解析
  • 2. 排序数组
    • 2.1 题目来源
    • 2.2 题目描述
    • 2.3 题目解析
  • 3. 数组中的第K个最大元素
    • 3.1 题目来源
    • 3.2 题目描述
    • 3.3 题目解析
  • 4. 库存管理 III
    • 4.1 题目来源
    • 4.2 题目描述
    • 4 .3 题目解析

1. 颜色分类

1.1 题目来源

75. 颜色分类

1.2 题目描述

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

  1. 示例 1:
    输入:nums = [2,0,2,1,1,0]
    输出:[0,0,1,1,2,2]
  2. 示例 2:
    输入:nums = [2,0,1]
    输出:[0,1,2]

提示:
n == nums.length
1 <= n <= 300
nums[i] 为 0、1 或 2

1.3 题目解析

方法一:使用快速排序

这里就是简单的一个快排模板了.

class Solution {
public:
    void QuickSortHoare(vector<int>& a, int left, int right)
    {
        if (left >= right)
            return;

        int l = left, r = right;
        int key = left;

        while (l < r)
        {
            while (l < r && a[r] >= a[key]) // 这里要注意了一定要写等号,也必须是r先--在l++
                r--;
            while (l < r && a[l] <= a[key])
                l++;
            swap(a[l], a[r]);
        }
        swap(a[left], a[l]);
        QuickSortHoare(a, left, l - 1);
        QuickSortHoare(a, l + 1, right);
    }
    void sortColors(vector<int>& nums) 
    {
        QuickSortHoare(nums, 0, nums.size() - 1);
    }
};

方法二:三指针

我们可以将整个数组分成三部分呢,第一部分全部是0,第二部分全部都是1,第三部分全部都是2。于是我们可以定义三个指针,left,cur,right,left代表第一部分的最右边,right代表第三部分的最左边,cur指针用于遍历整个数组。这样的话我们就可以得到一个范围,即[left,l]为第一部分,[l + 1, r - 1]是第二部分,[r, right]是第三部分。

这里的解题思路可以参考移动零。

所以我们就可以得到三个部分:

  1. 如果nums[cur] == 0 ,就swap(nums[cur], nums[left + 1],同时将left和cur都进行++
  2. 如果nums[cur] == 1,则cur直接进行++
  3. 如果num[cur] == 2,则swap(nums[cur], nums[right - 1]),同时right进行–,这个时候cur不需要进行++,因为right - 1下标对应的数据是还没有进行判断的,有可能是0,有可能是1,也有可能是2,是不确定的,所以还需要进行判断。
class Solution {
public:
    void sortColors(vector<int>& nums) {
        int n = nums.size();
        int left = -1 , right = n;
        int cur = 0;
        
        while (cur < right)
        {
            if (nums[cur] == 0)
            {
                swap(nums[left + 1], nums[cur]);
                left++;
                cur++;
            }
            else if (nums[cur] == 1)
            {
                cur++;
            }
            else
            {
                swap(nums[right - 1],nums[cur]);
                right--;
            }
        }
    }
};

2. 排序数组

2.1 题目来源

912. 排序数组

2.2 题目描述

给你一个整数数组 nums,请你将该数组升序排列。

  1. 示例 1:
    输入:nums = [5,2,3,1]
    输出:[1,2,3,5]
  2. 示例 2:
    输入:nums = [5,1,1,2,0,0]
    输出:[0,0,1,1,2,5]

提示:
1 <= nums.length <= 5 * 104
-5 * 104 <= nums[i] <= 5 * 104

2.3 题目解析

方法一:快排模板

直接使用快排模板,这里需要注意了int key = a[(left + right) >> 1];必须写成key直接拿到值,不能使用通过拿到下标的方式int key = (left + right) >> 1,然后后序使用while (a[r] > a[key])这样通过索引的方式进行判断,因为可能在整个whiel(l < r)的阶段中key所对应下标的值会发生改变。只有一开始拿到索引对应的值后继续使用方可。

class Solution {
public:
    void _sort(vector<int>& a, int left, int right)
    {
        if (left >= right) return;
        
        int l = left, r = right;
        int key = a[(left + right) >> 1];
        while (l <= r)
        {
            while (a[r] > key)
                r--;
            while (a[l] <key)
                l++;
            if (l <= r)
            {
                swap(a[l], a[r]);
                l++;
                r--;
            }
        }
        _sort(a, left, r);
        _sort(a, l, right);
    }
    vector<int> sortArray(vector<int>& nums) {
        _sort(nums, 0, nums.size() - 1);
        return nums;
    }
};

方法二:使用三指针+随机取key值

向上面那样如果直接使用快排的模板的话,如果是全部都是相同的数,或者这个数组本身就是一个有序的话,那么直接使用快排模板的话时间复杂度将会达到O(N^2)所以我们可以对快排进行优化。同样的我们也可以划分为三部分,第一部分是小于key(基准值)的,第二部分是等于key的,第三部分是大于key的。于是我们可以定义三个指针,left,cur,right,left代表第一部分的最右边,right代表第三部分的最左边,cur指针用于遍历整个数组。这样我们递归只需要对范围为[left, l]和[r, right]范围之间进行递归了。[l+ 1, r - 1]这个区间的范围是不用在进行递归了。而至于key的选取的话,我们之前都是采用第一个或者最后一个或者中间为基准值,这里我们使用使用随机选取的方式。

于是我们就可以得出这样的结论:

  1. 如果nums[cur] < key,则执行swap(nums[left + 1], nums[cur]),同时对left和cur进行++
  2. 如果nums[cur] == key,则只需要对cur进行++即可。
  3. 如果nums[cur] > key,则执行swap(nums[right - 1], nums[cur]),同时只需要对right–即可,cur不需要进行操作,因为被交换过去的nums[right - 1]是还没进行处理的,所以还需要进一步处理。

所以上述这个优化可以将时间复杂度优化接近到NlogN的时间复杂度。

class Solution {
public:
    void _sort(vector<int>& nums, int left, int right)
    {
        if (left >= right) return;

        int l = left - 1, r = right + 1; // 这样处理可以提高代码复用度
        int key = nums[rand() % (right - left + 1) + left];
        int cur = left;
        while (cur < r)
        {
            if (nums[cur] < key)
            {
                swap(nums[l + 1], nums[cur]);
                l++;
                cur++;
            }
            else if(nums[cur] == key)
            {
                cur++;
            }
            else
            {
                swap(nums[r - 1], nums[cur]);
                r--;
            }
        }
        _sort(nums, left, l);
        _sort(nums, r, right);
    }
    vector<int> sortArray(vector<int>& nums) {
        _sort(nums, 0, nums.size() - 1);
        return nums;
    }
};

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

3.1 题目来源

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

3.2 题目描述

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

  1. 示例 1:
    输入: [3,2,1,5,6,4], k = 2
    输出: 5
  2. 示例 2:
    输入: [3,2,3,1,2,4,5,5,6], k = 4
    输出: 4

提示:
1 <= k <= nums.length <= 105
-104 <= nums[i] <= 104

3.3 题目解析

方法一:使用快排模板:

class Solution {
public:
    void _sort(vector<int>& nums, int left, int right)
    {
        if (left >= right) return;
        int l = left, r = right;
        int key = nums[(left + right) >> 1];
        while (l <= r)
        {
            while (nums[r] > key)
                r--;
            while (nums[l] < key)
                l++;
            if (l <= r)
            {
                swap(nums[l], nums[r]);
                l++;
                r--;
            }
        }
        _sort(nums, left, r);
        _sort(nums, l, right);
    }
    int findKthLargest(vector<int>& nums, int k) 
    {
        _sort(nums, 0, nums.size() - 1);
        return nums[nums.size() - k];
    }
};

方法二:使用三指针数据分三块+随机选取基准值

这里其实和上面几题是一样的方法,也是将数组分成三份,第一部分小于key,第二部分等于key,第三部分大于key。使用三个指针来操作,left,cur,right。left代表第一部分的最右边,right代表第三部分的最左边,cur指针用于遍历整个数组。我们假设第一部分也就是[left, l]的长度是a,第二部分也就是[l + 1, r - 1]的长度是b,第三部分也就是[r, right]的长度是c。现在我们要找到第k大的元素。所以就有一下结论

在这里插入图片描述
所以我们可以得出一下结论:

  1. 如果c >= k,则直接在[r, right]中查找就可以了
  2. 如果 c + b >= k,则直接就是返回[l + 1, r - 1] 中的任意一个值就行。
  3. 如果上述1和2都不满足则需要在[left, l]中进行查找,而这个时候要查找的因该是第(k- b - c)大的数了。
class Solution {
public:
    int _sort(vector<int>& nums, int left, int right, int k)
    {
        int l = left - 1, r = right + 1;
        int key = nums[rand()%(right - left + 1) + left];
        int cur = left;
        while (cur < r)
        {
            if(nums[cur] < key)
            {
                swap(nums[l + 1], nums[cur]);
                l++;
                cur++;
            }
            else if (nums[cur] == key)
            {
                cur++;
            }
            else
            {
                swap(nums[r - 1], nums[cur]);
                r--;
            }
        }
        if (right - r + 1 >= k)
        {
            return _sort(nums, r, right, k);
        }
        else if (right - l >= k)
        {
            return nums[l + 1];
        }
        else
        {
            int c = right - r + 1;
            int b = r - l - 1;
            return _sort(nums, left, l, k - b - c);
        }
    }

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

4. 库存管理 III

4.1 题目来源

159. 库存管理 III

4.2 题目描述

仓库管理员以数组 stock 形式记录商品库存表,其中 stock[i] 表示对应商品库存余量。请返回库存余量最少的 cnt 个商品余量,返回 顺序不限。

  1. 示例 1:
    输入:stock = [2,5,7,4], cnt = 1
    输出:[2]
  2. 示例 2:
    输入:stock = [0,2,3,6], cnt = 2
    输出:[0,2] 或 [2,0]

提示:
0 <= cnt <= stock.length <= 10000
0 <= stock[i] <= 10000

4 .3 题目解析

这题其实也是使用一样的方法,使用三指针数据分三块+随机选取基准值。

class Solution {
public:
    void _sort(vector<int>& nums, int left, int right)
    {
        if (left >= right) return;
        int l = left - 1, r = right + 1;
        int key = nums[rand() % (right - left + 1) + left];
        int cur = left;
        while (cur < r)
        {
            if (nums[cur] < key)
            {
                swap(nums[l + 1], nums[cur]);
                l++;
                cur++;
            }
            else if (nums[cur] == key)
            {
                cur++;
            }
            else
            {
                swap(nums[r - 1], nums[cur]);
                r--;
            }
        }
        _sort(nums, left, l);
        _sort(nums, r, right);
    }
    vector<int> inventoryManagement(vector<int>& stock, int cnt) 
    {
        vector<int> v;
        if (cnt == 0) return v;
        _sort(stock, 0, stock.size() - 1);
        for (int i = 0; i < cnt; i++)
        {
            v.push_back(stock[i]);
        }
        return v;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2117135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS基础学习笔记

1.引入方式 内部脚本 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> <…

为什么要使用大模型RAG一体机

使用大模型RAG&#xff08;Retrieval-Augmented Generation&#xff09;一体机&#xff0c;如AntSKPro AI 离线知识库一体机&#xff0c;有以下几个原因和优势&#xff1a; 提高效率&#xff1a;RAG模型结合了检索&#xff08;Retrieval&#xff09;和生成&#xff08;Generati…

鸿蒙(API 12 Beta6版)GPU加速引擎服务【自适应VRS】

XEngine Kit提供自适应VRS功能&#xff0c;其通过合理分配画面的计算资源&#xff0c;视觉无损降低渲染频次&#xff0c;使不同的渲染图像使用不同的渲染速率&#xff0c;能够有效提高渲染性能。 接口说明 以下接口为自适应VRS设置接口&#xff0c;如要使用更丰富的设置和查询…

windows10-VMware17-Ubuntu-22.04-海康2K摄像头兼容问题,求解(已解决)

文章目录 1.webrtc camera测试2.ffmpeg 测试3.Ubuntu 自带相机4.解决办法 环境&#xff1a;windows10系统下&#xff0c;VMware的Ubuntu-22.04系统 问题&#xff1a;摄像头出现兼容问题&#xff0c;本来是想开发测试的&#xff0c;Ubuntu方便些。买了海康2K的USB摄像头&#xf…

人机交互与现代战争

人机交互技术在现代战争中的应用越来越广泛&#xff0c;它可以帮助士兵更好地完成任务&#xff0c;提高作战效能&#xff0c;减少人员伤亡。人机交互与认知在军事应用方面的进展有很多&#xff0c;比如&#xff1a; &#xff08;1&#xff09;虚拟现实和增强现实技术&#xff1…

PAT甲级-1085 Perfect Sequence

题目 题目大意 在一组数中找到一个完美数列&#xff0c;满足M < mp&#xff0c;M是该数列的最大值&#xff0c;m是最小值&#xff0c;p是题目给定的一个常数。 思路 模拟或者二分法。二分法可用upper_bound()函数实现。 知识点 upper_bound() 和 lower_bound() 函数在&…

C高级编程 第十六天(树 二叉树)

1.树 1.1结构特点 非线性结构&#xff0c;有一个直接前驱&#xff0c;但可能有多个直接后继有递归性&#xff0c;树中还有树可以为空&#xff0c;即节点个数为零 1.2相关术语 根&#xff1a;即根结点&#xff0c;没有前驱叶子&#xff1a;即终端结点&#xff0c;没有后继森…

02-java实习工作一个多月-经历分享

一、描述一下最近不写博客的原因 离我发java实习的工作的第一天的博客已经过去了一个多月了&#xff0c;本来还没入职的情况是打算每天工作都要写一份博客来记录一下的&#xff08;最坏的情况也是每周至少总结一下的&#xff09;&#xff0c;其实这个第一天的博客都是在公司快…

笔记整理—内核!启动!—kernel部分(2)从汇编阶段到start_kernel

kernel起始与ENTRY(stext)&#xff0c;和uboot一样&#xff0c;都是从汇编阶段开始的&#xff0c;因为对于kernel而言&#xff0c;还没进行栈的维护&#xff0c;所以无法使用c语言。_HEAD定义了后面代码属于段名为.head .text的段。 内核起始部分代码被解压代码调用&#xff0c…

深入手撕链表

链表 分类概念单链表增尾插头插插入 删尾删头删删除 查完整实现带头不带头 双向链表初始化增尾插头插插入 删查完整代码 数组 分类 #mermaid-svg-qKD178fTiiaYeKjl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-qK…

Java 入门指南:JVM(Java虚拟机)—— Java 内存运行时的数据区域

前言 对于 Java 程序员来说&#xff0c;在虚拟机自动内存管理机制下&#xff0c;不再需要像 C/C程序开发程序员这样为每一个 new 操作去写对应的 delete/free 操作&#xff0c;不容易出现内存泄漏和内存溢出问题。 由于程序员把内存控制权利交给 Java 虚拟机&#xff0c;一旦…

【CSS in Depth 2 精译_025】4.3 弹性布局的方向

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

NISP 一级 | 2.3 身份认证

关注这个证书的其他相关笔记&#xff1a;NISP 一级 —— 考证笔记合集-CSDN博客 0x01&#xff1a;身份认证基本方法 身份认证是用户登录系统或网站面对的第一道安全防线&#xff0c;如输入账号口令来登录。身份认证是在网络中确认操作者身份的过程。身份认证一般依据以下三种情…

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html Thread Index和Thread ID之间有什么关系呢&#xff1f;&#xff08;线程架构参考这里&#xff1a;CUDA C Programming Guide (nvidia.com)open in new window&#xff09; 1维的Thread Index&am…

ORCAD出BOM--位号在同一个Excel格子里

所有相同属性的器件都在同一个格子里 Tools\ Bill of Materials, 注意勾选Open in excel. 勾选Open in excel, 所有相同属性的器件都在同一个格子里 不勾选Open in excel, 5个相同属性的器件都在同一个格子里

代码随想录Day 39|打家劫舍问题,leetcode题目:198.打家劫舍、213.打家劫舍Ⅱ、337.打家劫舍Ⅲ

提示&#xff1a;DDU&#xff0c;供自己复习使用。欢迎大家前来讨论~ 文章目录 题目题目一&#xff1a;198.打家劫舍解题思路&#xff1a; 题目二&#xff1a;213.打家劫舍II解题思路&#xff1a; 题目三&#xff1a; 337.打家劫舍 III解题思路暴力递归记忆化递推动态规划 总结…

Linux基础2-权限2(操作权限,粘滞位,umask,目录文件的rwx权限)

上篇内容&#xff1a;Linux基础2-权限1(用户&#xff0c;权限是什么&#xff1f;)-CSDN博客 目录 一. 权限的操作&#xff08;命令&#xff09; 1.1 chmod 1.2 chown 1.3 chgrp 二. 粘滞位 三. umask&#xff08;遮掩码&#xff09; 四. 目录文件的 r w x 权限 一. 权限…

数据库的操作:SQL语言的介绍

一.前言 SQL是一种结构化查询语言。关系型数据库中进行操作的标准语言。 二.特点 ①对大小写不敏感 例如&#xff1a;select与Select是一样的 ②结尾要使用分号 没有分号认为还没结束; 三.分类 ①DDL&#xff1a;数据定义语言&#xff08;数据库对象的操作&#xff08;结…

服务器重装系统,数据备份 容器备份

文章目录 1.前言2.docker备份2.1 容器备份2.2 镜像备份2.3 数据卷备份 3.docker安装4.jdk安装5.导入镜像6.导入容器 本文档只是为了留档方便以后工作运维&#xff0c;或者给同事分享文档内容比较简陋命令也不是特别全&#xff0c;不适合小白观看&#xff0c;如有不懂可以私信&a…

【最新华为OD机试E卷-支持在线评测】计算疫情扩散时间(200分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-E/D卷的三语言AC题解 💻 ACM金牌🏅️团队| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,…