【排序汇总】这里记录一切与搜索排序相关的内容~(更新ing)

news2024/11/15 23:29:51

目录

  • 经典算法
    • 快速排序
      • 核心思想
      • cpp代码
    • 二分查找
      • 核心思想
      • cpp代码
  • 具体题目
    • 荷兰旗问题-颜色分类 (leetcode75)
      • 思路
      • cpp代码
    • 数组中的第K个最大元素 (leetcode215)
      • 思路:快速选择
      • cpp代码

经典算法

快速排序

经典面试手撕题,刚好明天又要面试百度了,先复习一下~

核心思想

快速排序算法的核心其实就是“分而治之”。

给定一个数组int a = {2, 6, 3, 8, 1, 5, 4},我们首先选择一个基准元素,将问题分割成两个子问题将比基准元素小的值放左边,将比基准元素大的值放右边,那么我们需要排序的整体数组就变成了两个更短的数组,进而我们分别对左右两边的子数组继续干上面相同的事情,直到分割到最后的子数组中只有一个元素,这样的子数组必定是有序的,进而我们的整个数组也就排序好了。实际上我们分析的就是一个递归过程

那么“分”的思路我们想好了,该如何“”呢?

从上面的分析我们可以得出,要写一个快速排序算法,我们需要知道当前处理子数组的左右边界/index,也就是int leftint right

假定我们每一次对子数组进行处理的时候,基准元素都是左边界第一个数,我们将它拿出来key = a[left],将第一个位置看做成一个“坑”来存放之后需要调整到前面来的数。

那么我们首先从后往前去找比key小的数,将它放在a[left]里,这样这个坑就完成了它的使命,但是由于我们将后面的a[right]中的数拿出来,这里又变成了一个坑,那么我们下面就要反过来从前往后去找比key大的数,将它填在a[right]里。依此类推,这就是一个填坑游戏,哈哈~

cpp代码

具体cpp代码如下:

#include <iostream>
#include <vector>
using namespace std;

void quickSort(int left, int right, vector<int>& a){
	// 递归终止条件
	if(left >= right){
		return;
	}
	
	int l = left, r = right;
	int key = a[l];
	while(l < r){
		// 从后往前找比key小的数 
		while(l < r && a[r] >= key){
			r--;
		}
		if(l < r){
			a[l++] = a[r];
		}
		// 从前往后找比key大的数
		while(l < r && a[l] <= key){
			l++;
		} 
		if(l < r){
			a[r--] = a[l];
		} 
	}
	// 放置key的位置 
	a[l] = key;
	// 继续递归处理左右两边子数组
	quickSort(left, l-1, a);
	quickSort(l+1, right, a); 
}

int main() {
    vector<int> a = {10, 7, 2, 6, 5, 11, 8};
    quickSort(0, a.size()-1, a);
    for(int i = 0; i < a.size(); ++i){
    	cout << a[i] << " ";
	}
	cout << endl;
    return 0;
}

二分查找

哈哈哈昨天刚写完快速排序,今天面试面试官反倒让我写了二分查找,这就来更新!

题目🔗

核心思想

对于一个有序数组,其索引范围是[left, right],我们想查询一个元素target是否存在:

首先查询当前中间元素nums[mid]的大小:
- 如果nums[mid] < target,则说明targetnums[mid]右边,进而去(mid, right]中找
- 如果nums[mid] > target,则说明targetnums[mid]左边,进而去[left, mid)中找。

依据上面的分析,实际上就是一个循环的过程,直到我们找到这个target

cpp代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right){
        	// 找到中间元素索引
            int mid = (left + right) / 2;
            if(nums[mid] < target){
            	// 当中间元素小于target
                left = mid + 1;
            }
            else if(nums[mid] > target){
            	// 当中间元素大于target
                right = mid - 1;
            }
            // 当中间元素等于target,直接返回索引
            else return mid;
        }
        return -1;
    }
};

具体题目

荷兰旗问题-颜色分类 (leetcode75)

题目🔗

荷兰国旗是由红白蓝三种颜色条纹拼接而成的,如下图所示。
在这里插入图片描述
如果我们给定若干条这样的条纹并且随机拼接(下图情况),请你把他们按照荷兰国旗颜色进行排序。
在这里插入图片描述
具体题目描述如下
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

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

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

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

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

提示
n == nums.length
1 <= n <= 300
nums[i]012

思路

这题是不是和快排很像?我们如果把小于基准元素的值放在左边,把等于基准元素的值放在中间,把大于基准元素的值放在右边,就完美解决了。

但是如何实现“把等于基准元素的值放在中间”呢?

因为这题只是进行一趟排序,所以没有递归的过程,那么我们可以用一个cur指针来遍历数组中的元素,同样,我们也有leftright,分别记录中间和左边、中间和右边两个区间的边界。

那么当我们的cur碰到比key大的元素,就把它和right前一个数进行交换,并且right--。同理,当cur碰到比key小的元素,就把它和left后一个数进行交换,并且left++, cur++

重点是,当cur碰到和key相等的元素时,就跳过,将它留在中间区域,这样就实现了“把等于基准元素的值放在中间”。

可能有细心的小伙伴就发现了,欸这里的right--怎么没有cur++呢?这是因为我们在交换的时候可能会把后面的另一个大数给交换回来,如果我们进行cur++,就跳过了这次比较,有漏网之鱼了哦。

cpp代码

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

数组中的第K个最大元素 (leetcode215)

题目🔗

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

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

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

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

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

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

思路:快速选择

其实回看每一轮快速排序,就已经确定基准元素的位置,那么我们就可以把快排简化成,去确定第k-1个位置的数值(这里我们是从大到小进行排列)。

这里我们要考虑基准元素的选取问题,为了避免当选择边界作为基准,对于已经有序的区间而出现时间复杂度退化的情况,我们选取中间元素作为基准,也即int mid = left + (right - left) / 2;,同时将它和边界最右侧的元素进行互换swap(nums[mid], nums[right]),保证它在边界处不会被覆盖,这样我们的基准元素就变为了nums[right]

我们用int lint r分别从左右两侧进行判断,l从左侧找比nums[right]小的数,然后r从右侧找比nums[right]大的数,最后将两数位置交换,变成有序的状态。

那么最后的基准元素nums[right]应该放哪呢
我们结束循环的条件是l == r,且最后一定是以l的while循环结果结束,那么这个时候r一定是指向比nums[right]小的数,因为在[r, right)区间中,所有数都是满足比nums[right]小的。现在l == r,说明lr都指向比nums[right]小的数,那我们直接把nums[right]num[l]交换就可以了。

然后我们通过判断这一轮确定下来的基准元素位置和k的大小,再去选择性的进行下一次排序确定,最后当某一轮确定的基准元素位置和k相等时,我们就可以返回结果了

cpp代码

class Solution {
private:
    int quickSortKthElement(vector<int>& nums, int k, int left, int right){
        // 选择中间元素作为基准元素,避免有序情况下的退化
        int mid = left + (right - left) / 2;
        swap(nums[mid], nums[right]);   // 将基准元素放在最右边,防止被覆盖
        int l = left, r = right;
        while(l < r){
            while(l < r && nums[l] >= nums[right]) l++; // 循环直到找到左边部分比基准元素小的
            while(l < r && nums[r] <= nums[right]) r--; // 循环直到找到右边部分比基准元素大的
            if(l < r){
                swap(nums[l], nums[r]); // 交换大小元素
            }
        }
        swap(nums[l], nums[right]); // 最后将基准元素放在l的位置
        if(l == k - 1) return nums[l];
        else if(l > k -1) return quickSortKthElement(nums, k, left, l - 1);
        else return quickSortKthElement(nums, k, l + 1, right);
    };
public:
    int findKthLargest(vector<int>& nums, int k) {
        return quickSortKthElement(nums, k, 0, nums.size() - 1);
    }
};

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

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

相关文章

固态硬盘用mbr还是GPT?固态硬盘分区类型用mbr还是GPT分析

固态硬盘用mbr还是GPT&#xff1f;答&#xff1a;固态硬盘分区类型用mbr还是gpt其实取决于你对分区要求及引导模式。我们知道现在的引导模式有uefi和legacy两种引导模式&#xff0c;如果采用的是uefi引导模式&#xff0c;分区类型对应的就是gpt分区(guid)&#xff0c;如果引导模…

Java基础——注释

在开发中注释是必不可少的&#xff0c;帮助我们更好的标记阅读代码&#xff0c;下面介绍几种常用的注释方式。 一、注释种类 1. 单行注释 使用//一行代码来进行注释&#xff0c;只能注释一行内容 2. 多行注释 使用斜杠星号的方式 /*注释多行代码*/&#xff0c;注释多行代…

计算机毕业设计 《计算机基础》网上考试系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Idea启动Tomcat控制台中文乱码

Idea配置Tomcat后启动&#xff0c;控制台显示中文乱码 网上搜索资料会发现有要改server.xml URIEncodingUTF-8的&#xff0c;有要改idea文件夹下idea64.exe.vmoptions添加-Dfile.encodingUTF-8的&#xff0c;有要在idea里Tomcat配置中VM Options指定-Dfile.encodingUTF-8的。其…

指令及指令系统

1.指令的基本格式 1.1指令系统 指令(机器指令)是指示计算机执行某种操作的命令。一台计算机的所有指令的集合构成该机的指令系统&#xff0c;也称指令集。 指令系统是指令集体系结构(ISA)中最核心的部分&#xff0c;ISA完整定义了软件和硬件之间的接口&#xff0c;是机器语…

7.1 多态案例

一、案例1&#xff1a;计算器类 1.1 普通方式实现 #include <iostream> #include <string> using namespace std;class Calculator { public:int num1;int num2;int result(string oper){if (oper "")return num1 num2;else if (oper "-"…

法线纹理贴图计算(切线空间世界空间)

效率&#xff1a; 在切线空间中计算&#xff0c;效率更高&#xff0c;因为可以在顶点着色器中就完成对光照、视角方向的矩 阵变换&#xff0c;计算量相对较小。( 矩阵变换在顶点着色器中计算) 在世界空间中计算&#xff0c;效率较低&#xff0c;由于需要对法线贴图进行采样&a…

【区块链+金融服务】区块链在仓储融资的创新应用 | FISCO BCOS应用案例

释放数据要素价值&#xff0c;FISCO BCOS 2024 应用案例征集 在仓储融资业务中&#xff0c;对质押物的有效监管至关重要&#xff0c;但仓储融资一般涉及到监管方、仓储方和金融机构等多套系统&#xff0c; 金融机构的系统与仓储系统不直连&#xff0c;难以实时获取质押物库存情…

【YOLOv5/v7改进系列】替换Neck为Gold-Yolo特征融合网络

一、导言 Gold-YOLO是一种高效的物体检测模型&#xff0c;它通过一种新的机制——Gather-and-Distribute&#xff08;GD&#xff09;机制来增强多尺度特征融合的能力&#xff0c;从而在保证实时性能的同时提高了检测精度。下面是对Gold-YOLO的主要特点和创新点的概述&#xff…

谈一谈TVM编译工程师的修炼手册

首先提一下TVM TVM 被称为编译器&#xff0c;是因为它在深度学习模型的优化和执行过程中执行了类似传统编译器的许多工作。与传统编译器将高级语言代码&#xff08;如 C&#xff09;编译为机器代码类似&#xff0c;TVM 将深度学习模型表示&#xff08;如 ONNX&#xff09;转化…

深度相机,通过2d检测得到目标坐标系的3d检测框

算法流程图如下 1. 输入同步&#xff1a; 订阅三个主题&#xff1a; 深度图像 (depth_image)。相机信息 (depth_info)。2D目标检测 (detections)。 使用 message_filters.ApproximateTimeSynchronizer 来同步这些输入&#xff0c;以确保处理的消息是对应的。 2. 计算2D边界…

GET新知识-如何通过Ubuntu和Windows进行文件交互

知识记录篇改求助篇了呜呜呜~~~ &#xff0c;到最后一步passwd咋样都无法链接了。 1.通过下载open SSH进行交互 输入Linux命令: sudo apt install openssh-server 然后就会出现这个&#xff0c;输入Y确认&#xff0c;即可安装成功 2.在Windows上也安装open SSH&#xff0c;具体…

CAN总线详解-理论知识部分

目录 CAN总线简介 CAN总线硬件电路 CAN电平标准 CAN收发器 ​编辑 CAN物理层特性 CAN总线帧格式 数据帧 数据帧格式 数据帧发展历史 遥控帧 错误帧 过载帧 帧间隔 位填充 波形实例 CAN总线接收方数据采样 接收方数据采样遇到的问题 位时序 硬同步 再同步 波…

月销量不足1000的新能源车,都是什么人在买?

近日&#xff0c;盐城经济技术开发区人民法院决定受理高合汽车母公司华人运通&#xff08;江苏&#xff09;技术有限公司预重整申请。 由此&#xff0c;高合汽车正式破产重整。无独有偶&#xff0c;恒大汽车附属公司广东恒大新能源汽车和智能汽车也被申请破产重整。 高合和恒…

使用API有效率地管理Dynadot域名,对拍卖的域名进行出价

前言 Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮箱&…

python实现每天定时发送邮件

文章目录 步骤 1: 安装所需的库步骤 2: 编写发送电子邮件的 Python 脚本步骤 3: 配置电子邮件发送服务步骤 4: 运行脚本进一步扩展 要编写一个用于自动发送每日电子邮件报告的 Python 脚本&#xff0c;并配置它在每天的特定时间发送电子邮件&#xff0c;使用 smtplib 和 emai…

高可用集群keepalived的应用以及部署

1.高可用集群 1.1.集群类型 LB&#xff1a;Load Balance 负载均衡 LVS/haproxy/nginx&#xff08;http/upstream,stream/upstream&#xff09; HA : High Point of Failure 高可用集群 数据库、Redis SPoF&#xff1a;single point Of failure 解决单点故障 HPC&#xff1a;…

数据库管理-第228期 Oracle全球分布式数据库-初探(20240812)

数据库管理228期 2024-08-12 数据库管理-第228期 Oracle全球分布式数据库-初探&#xff08;20240812&#xff09;1 概念2 关于全球分布式数据库3 分布式分区4 Oracle全球分布式数据库的优势总结 数据库管理-第228期 Oracle全球分布式数据库-初探&#xff08;20240812&#xff0…

如何在Shopify开发中高度还原Figma设计稿

### 一、理解设计意图&#xff1a;设计与开发的有效沟通#### 1. 早期沟通的重要性在开发工作开始之前&#xff0c;开发人员应与设计师进行详细的沟通&#xff0c;确保对设计意图有深刻理解。关键点包括&#xff1a;- **色彩和字体**&#xff1a;了解设计师对品牌色彩和字体的选…

从0开始搭建vue + flask 旅游景点数据分析系统(十一):登录、注册页面、未登录拦截、注销逻辑

这一期已经到了系列教程的尾声了&#xff0c;下面来搭建登录、注册页面&#xff0c;处理登录拦截和注销的逻辑 1 建表 先把数据库表用户相关的数据库表建立一下&#xff1a; CREATE TABLE tb_user (id int NOT NULL AUTO_INCREMENT COMMENT id,realname varchar(255) CHARAC…