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

news2024/9/21 5:40:02

目录

  • 经典排序算法
    • 快速排序
      • 核心思想
      • 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;
}

具体排序相关题目

荷兰旗问题-颜色分类 (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/2038180.html

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

相关文章

ContentProvider:在Android中实现进程间数据共享

目录 一&#xff0c;ContentProvider 二&#xff0c;Uri和UriMatcher工具类 1&#xff0c;Uri 2&#xff0c;UriMatcher 三&#xff0c;自定义ContentProvider 1&#xff0c;准备数据源 2&#xff0c;创建ContentProvider子类 3&#xff0c;在Manifest文件中注册ContentP…

100个智能体实战技巧 | 如何让Bot一眼记住你

今天介绍一个智能体实用技巧&#xff0c;让Bot可以一眼认出你并和你主动打招呼。 要实现这个功能&#xff0c;需要用到智能体里的变量 操作步骤 点号开始编辑变量&#xff0c;扣子默认已经有5个变量&#xff0c;不过这些我们暂时用不上这些 点” 新增“&#xff0c;创建一个新…

基于WAMP环境的简单用户登录系统实现(v3版)(持续迭代)

目录 版本说明 实现环境&#xff1a; 流程逻辑框图&#xff1a; 数据库连接 登录页面&#xff1a;login.html 登录处理实现&#xff1a;doLogin.php 用户欢迎页面&#xff1a;welcome.php 密码修改页面&#xff1a;change_password.html 修改处理&#xff1a;doChangePa…

【Python学习-UI界面】PyQt5 小部件1-Label

QLabel 对象可用作显示不可编辑的文本、图像或动态GIF影片的占位符。 它还可以用作其他小部件的助记键。 标签可以显示普通文本、超链接或富文本。 1、普通文本 直接双击输入即可 2、添加超链接 选中对应Label&#xff0c;右键选择多信息文本&#xff0c;添加链接&#xff0c…

全网最详细haproxy配置

Haproxy是法国人Willy Tarreau开发的一款高性能的TCP和HTTP负载均衡器&#xff0c;具有广泛的功能和特性&#xff0c;使其在负载均衡和反向代理领域备受推崇。以下是对Haproxy的详细介绍&#xff1a; 一、基本概述 定义&#xff1a;Haproxy是一个开源的高性能的反向代理或者说…

15个提升学术写作的 ChatGPT 高效技巧

不束手无策地面对空白页面这里有 15 个充满灵感的 ChatGPT 提示&#xff0c;帮助你找到研究灵感、建有力论据、撰写条理清晰的文章&#xff0c;突破创作的障碍&#xff0c;提高学术写作的效率。 学术写作充满挑战。要创作出优秀的文章&#xff0c;必须探索新思维&#xff0c;并…

Python OpenCV 影像处理:边缘检测

►前言 上篇介绍使用OpenCV Python findContours() 函数用于在二值化影像中寻找连通的白色区域&#xff0c;并返回一系列点的集合来表示找到的轮廓。本篇将介绍基于计算影像的梯度&#xff0c;通过在影像中找到梯度值的变化来识别边缘&#xff0c;边缘检测通常用于预处理步骤&…

XXL-JOB分布式定时任务框架快速入门

文章目录 前言定时任务分布式任务调度 1、XXL-JOB介绍1.1 XXL-JOB概述1.2 XXL-JOB特性1.3 整体架构 2、XXL-JOB任务中心环境搭建2.1 XXL-JOB源码下载2.2 IDEA导入xxljob工程2.3 初始化数据库2.4 Docker安装任务管理中心 3、XXL-JOB任务注册测试3.1 引入xxl-job核心依赖3.2 配置…

rust 编译时报错:type annotations needed for Box

如下图所示&#xff1a; 解决方法&#xff1a; 升级time的版本&#xff1a; cargo update -p time

【Python基础】Python入门基础教程(非常详细){附带源码}

引言 Python 是一种广泛使用的高级编程语言&#xff0c;因其简洁的语法和强大的功能库而受到开发者的喜爱。本教程将带你从零开始&#xff0c;逐步掌握 Python 的基础知识&#xff0c;并通过附带的源码和表格来加深理解。 点击免费领取《CSDN大礼包》&#xff1a;Python入门到…

c语言基础知识详解,c语言入门必看

在线书籍&#xff1a;54笨鸟 前言 C 语言是一门抽象的、面向过程的语言&#xff0c;C 语言广泛应用于底层开发&#xff0c;C 语言在计算机体系中占据着不可替代的作用&#xff0c;可以说 C 语言是编程的基础&#xff0c;也就是说&#xff0c;不管你学习任何语言&#xff0c;都…

最详细!教你学习haproxy七层代理

一、工作原理 &#xff08;1&#xff09;包括 监听端口&#xff1a;HAProxy 会在指定的端口上监听客户端的请求。 例如&#xff0c;它可以监听常见的 HTTP 和 HTTPS 端口&#xff0c;等待客户端连接。请求接收&#xff1a;当客户端发起请求时&#xff0c;HAProxy 接收到请求。…

Gin框架接入pyroscope完美替代pprof实现检测内存泄露

传统检测内存泄露可以看一下我这篇文章Gin框架接入Prometheus,grafana辅助pprof检测内存泄露-CSDN博客 pyroscope被Grafana收购,GPT来总结一下pyroscope的强大之处&#x1f436; pyroscope github地址 pyroscope与grafana的安装 docker compose安装&#xff0c;这里我们其实…

GET和POST这两种常用的HTTP请求方法的区别

GET和POST是HTTP协议中最常用的两种请求方法&#xff0c;它们在使用场景、安全性、数据传输等方面有很大的不同。让我从以下几个方面来比较GET和POST&#xff1a; 1.「用途和语义」 「GET」: 主要用于获取资源 应该是幂等的&#xff0c;即多次请求应该返回相同的结果 通常用…

超详细!!!electron-vite-vue开发桌面应用之开启调试工具(二)

云风网 云风笔记 云风知识库 上篇已经初步搭建完项目&#xff0c;这次配置比较重要的一部分&#xff0c;那就是开启调试工具&#xff0c;这是开发项目比较重要且基础的部分 vite.config.ts配置更新 main: {// Shortcut of build.lib.entry.entry: electron/main.ts,onstart(ar…

2003-2023年高铁数据高铁开通时间数据

2003-2023年高铁数据高铁开通时间数据 1、时间&#xff1a;2003-2023年 2、来源&#xff1a;整理自高铁航线数据库&#xff08;Chinese High-speed Rail and Airline Database&#xff0c;CRAD&#xff09; 3、指标&#xff1a;高铁站名称、开通时间、所在省份、所在城市、所…

通过网关将数据上传到两台eqmx服务器上

我们是通过WAN 来读取数据。 线连接以后打开 然后要配置上去服务器 在这里遇到的问题是我自己搭emqx服务器的时候&#xff0c;没有固定ip地址&#xff0c;这个ip地址要通过ipconfig来获取&#xff0c;然后将其设置为静态IP地址&#xff0c;才可以的。让后emqx服务器还要重新启…

美股开户:新手投资者的完整入门教程

炒美股是许多投资者心中的梦想&#xff0c;但对于新手小白来说&#xff0c;如何开户炒美股可能会显得有些复杂和困难。本文将为您提供一份完整的入门教程&#xff0c;详细介绍从选择券商到完成开户的步骤&#xff0c;帮助您顺利进入美股市场。 选择合适的券商 在开户之前&…

【Linux基础】Linux中的开发工具(1)--yum和vim

目录 ✈️前言一&#xff0c;Linux 软件包管理器 yum1. 什么是软件包2. 如何安装软件3. 如何卸载软件 二&#xff0c;Linux编辑器-vim使用1. vim的基本概念1.1 命令/正常/普通模式1.2 插入模式1.3 底行模式 三&#xff0c;vim命令模式命令集1. 移动光标2. 删除字符3. 复制4. 替…

后端调优——分布式锁选型——入门

文章目录 引言正文分布式锁的定义分布式锁的具体应用场景如何实现分布式锁主动轮询型分布式锁实现思路一、MySQL分布式锁二、Redis分布式锁 监听回调型分布式锁Etcd分布式锁Zookeeper分布式锁 锁的对比 总结 引言 最近面试&#xff0c;一直被问到分布式锁&#xff0c;然后仅仅…