【优选算法】(第二十二篇)

news/2024/10/9 18:09:28/

目录

颜⾊分类(medium)

题目解析

讲解算法原理

编写代码

快速排序(medium)

题目解析

讲解算法原理

编写代码


颜⾊分类(medium)

题目解析

1.题目链接:. - 力扣(LeetCode)

2.题目描述

给定⼀个包含红⾊、⽩⾊和蓝⾊、共n个元素的数组nums,原地对它们进⾏排序,使得相同颜⾊的元素相邻,并按照红⾊、⽩⾊、蓝⾊顺序排列。
我们使⽤整数0、1和2分别表⽰红⾊、⽩⾊和蓝⾊。
必须在不使⽤库的sort函数的情况下解决这个问题。
⽰例1:
输⼊:nums=[2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

讲解算法原理

解法(快排思想-三指针法使数组分三块):
算法思路:
类⽐数组分两块的算法思想,这⾥是将数组分成三块,那么我们可以再添加⼀个指针,实现数组分三块。
设数组⼤⼩为 n ,定义三个指针 left, cur, right :◦ left :⽤来标记 0 序列的末尾,因此初始化为 -1 ;◦ cur :⽤来扫描数组,初始化为 0 ;
◦ right :⽤来标记 2 序列的起始位置,因此初始化为 n 。在 cur 往后扫描的过程中,保证:
◦ [0, left] 内的元素都是 0 ;
◦ [left + 1, cur - 1] 内的元素都是 1 ;
◦ [cur, right - 1] 内的元素是待定元素;
◦ [right, n] 内的元素都是 2 。
算法流程:
a. 初始化 cur = 0,left = -1, right = numsSize ;
b. 当 cur < right 的时候(因为 right 表⽰的是 2 序列的左边界,因此当 cur 碰到
right 的时候,说明已经将所有数据扫描完毕了),⼀直进⾏下⾯循环:
根据 nums[cur] 的值,可以分为下⾯三种情况:
i. nums[cur] == 0 ;说明此时这个位置的元素需要在 left + 1 的位置上,因此交
换 left + 1 与 cur 位置的元素,并且让 left++ (指向 0 序列的右边界),
cur++ (为什么可以 ++ 呢,是因为 left + 1 位置要么是 0 ,要么是 cur ,交换
完毕之后,这个位置的值已经符合我们的要求,因此 cur++ );
ii. nums[cur] == 1 ;说明这个位置应该在 left 和 cur 之间,此时⽆需交换,直接
让 cur++ ,判断下⼀个元素即可;
iii. nums[cur] == 2 ;说明这个位置的元素应该在 right - 1 的位置,因此交换
right - 1 与 cur 位置的元素,并且让 right-- (指向 2 序列的左边界),cur 不变(因为交换过来的数是没有被判断过的,因此需要在下轮循环中判断)
c. 当循环结束之后:
[0, left] 表⽰ 0 序列;
[left + 1, right - 1] 表⽰ 1 序列;
[right, numsSize - 1] 表⽰ 2 序列。

编写代码

c++算法实现:

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

java算法实现:

class Solution {public void swap(int[] nums, int i, int j){int t = nums[i];nums[i] = nums[j];nums[j] = t;}public void sortColors(int[] nums) {int left = -1, right = nums.length, i = 0;while(i < right){if(nums[i] == 0) swap(nums, ++left, i++);else if(nums[i] == 1) i++;else swap(nums, --right, i);}}
}

快速排序(medium)

题目解析

1.题目链接:. - 力扣(LeetCode)

由于⼒扣的测试⽤例在不断加强,所以这⾥的数组划分三块的思想搭配随机选择基准元素的⽅法是⽐较优秀的。

2.题目描述

给你⼀个整数数组nums,请你将该数组升序排列。⽰例1:
输⼊:nums=[5,2,3,1]输出:[1,2,3,5]
⽰例2:
输⼊:nums=[5,1,1,2,0,0]输出:[0,0,1,1,2,5]

讲解算法原理

解法(数组分三块思想+随机选择基准元素的快速排序):

算法思路
我们在数据结构阶段学习的快速排序的思想可以知道,快排最核⼼的⼀步就是Partition(分割数据):将数据按照⼀个标准,分成左右两部分。
如果我们使⽤荷兰国旗问题的思想,将数组划分为左中右三部分:左边是⽐基准元素⼩的数据,中间是与基准元素相同的数据,右边是⽐基准元素⼤的数据。然后再去递归的排序左边部分和右边部分即可(可以舍去⼤量的中间部分)。
在处理数据量有很多重复的情况下,效率会⼤⼤提升。
算法流程:
随机选择基准算法流程:函数设计:intrandomKey(vector<int>&nums,intleft,intright)

a. 在主函数那⾥种⼀颗随机数种⼦;
b. 在随机选择基准函数这⾥⽣成⼀个随机数;c. 由于我们要随机产⽣⼀个基准,因此可以将随机数转换成随机下标:让随机数%上区间⼤⼩,然后加上区间的左边界即可。
快速排序算法主要流程:
a. 定义递归出⼝;
b. 利⽤随机选择基准函数⽣成⼀个基准元素;
c. 利⽤荷兰国旗思想将数组划分成三个区域;
d. 递归处理左边区域和右边区域。

编写代码

c++算法实现:

class Solution
{
public:vector<int> sortArray(vector<int>& nums) {srand(time(NULL)); // 种下⼀个随机数种⼦qsort(nums, 0, nums.size() - 1);return nums;}// 快排void qsort(vector<int>& nums, int l, int r){if(l >= r) return;// 数组分三块int key = getRandom(nums, l, r);int i = l, left = l - 1, right = r + 1;while(i < right){if(nums[i] < key) swap(nums[++left], nums[i++]);else if(nums[i] == key) i++;else swap(nums[--right], nums[i]);}// [l, left] [left + 1, right - 1] [right, r]qsort(nums, l, left);qsort(nums, right, r);}int getRandom(vector<int>& nums, int left, int right){int r = rand();return nums[r % (right - left + 1) + left];}
};

java算法实现:

class Solution
{public int[] sortArray(int[] nums) {qsort(nums, 0, nums.length - 1);return nums;}public void qsort(int[] nums, int l, int r){if(l >= r) return;// 数组分三块int key = nums[new Random().nextInt(r - l + 1) + l];int left = l - 1, right = r + 1, i = l;while(i < right){if(nums[i] < key) swap(nums, ++left, i++);else if(nums[i] == key) i++;else swap(nums, --right, i);}// [l, left] [left + 1, right - 1] [rigth, r]qsort(nums, l, left);qsort(nums, right, r);}public void swap(int[] nums, int i, int j){int t = nums[i];nums[i] = nums[j];nums[j] = t;}
}


http://www.ppmy.cn/news/1536753.html

相关文章

React第十章(useState)

useState useState 是一个 React Hook&#xff0c;允许函数组件在内部管理状态。 组件通常需要根据交互更改屏幕上显示的内容&#xff0c;例如点击某个按钮更改值&#xff0c;或者输入文本框中的内容&#xff0c;这些值被称为状态值也就是(state)。 使用方法 useState 接收…

everyday_question dq20240731

网卡的作用是什么&#xff1f; 网卡&#xff08;Network Interface Card&#xff0c;NIC&#xff09;&#xff0c;也称为网络适配器&#xff0c;是计算机硬件的一部分&#xff0c;用于实现计算机与网络之间的连接和数据传输。以下是网卡的一些主要作用&#xff1a; 网络连接&a…

RabbitMQ入门1—queue参数之type

RabbitMQ 队列的 type 参数&#xff0c;这个参数是在 RabbitMQ 3.8.0 及以后版本引入的&#xff0c;它允许指定队列的存储和行为模式。type 参数有以下几种可选值&#xff1a; 1. classic 描述&#xff1a;这是 RabbitMQ 的传统队列类型&#xff0c;也是默认类型。如果不指定…

幂等性接口实现

1、什么是幂等性 幂等&#xff08;idempotence&#xff09;&#xff0c;这个词源自数学&#xff0c;幂等性是数学中的一个概念&#xff0c;常见于抽象代数中。表达的是N次变换与1次变换的结果相同。简单来说&#xff0c;就是如果方法调用一次和调用多次产生的效果是相同的&…

YOLO11改进|卷积篇|引入空间通道重组卷积ScConv

目录 一、【SCConv】卷积1.1【SCConv】卷积介绍1.2【SCConv】核心代码 二、添加【SCConv】卷积2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【SCConv】卷积 1.1【SCConv】卷积介绍 SCConv 模块提供了一种新的视角来看待CNNs的特征提取…

Python Django ORM 的工作原理

在 Web 开发中&#xff0c;处理数据库是非常常见的需求&#xff0c;尤其是在构建动态应用程序时。Django 作为一个流行的 Python Web 框架&#xff0c;提供了一套强大的工具帮助开发者轻松管理数据库。Django 的 ORM&#xff08;对象关系映射&#xff0c;Object-Relational Map…

SpringBoot中,接口签名,通用方案,以确保接口的安全性

1. 为什么需要接口签名&#xff1f; 接口签名目的&#xff1a;防止第三方伪造请求。请求伪造&#xff1a;未经授权的第三方构造合法用户的请求来执行不希望的操作。转账接口示例&#xff1a;展示了如果接口没有安全措施&#xff0c;第三方可以轻易伪造请求&#xff0c;例如将资…

【深度学习】损失函数

损失函数&#xff08;Loss Function&#xff09;是机器学习和深度学习模型中的一个核心概念&#xff0c;它用于衡量模型的预测输出与真实标签之间的差异。通过优化&#xff08;最小化&#xff09;损失函数&#xff0c;模型可以不断调整其内部参数&#xff0c;提升预测性能。不同…