快速排序题目SelectK问题

力扣75.颜色分类

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

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

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

 

class Solution { //时间复杂度为O(n)//其实,变量 zero 相当于我们在三路快速排序算法中的 lt;//变量 two 相当于我们在三路快速排序算法中的 gt。public void sortColors(int[] nums) {// nums[0...zero] == 0, nums[zero + 1, i] == 1, nums[two, n - 1] == 2// 定义三个指针:zero、i、two,分别表示0的最右边界、当前处理的元素、2的最左边界int zero = -1, i = 0, two = nums.length;while(i < two){// 当前处理元素的指针小于2的最左边界时,继续循环// 如果当前元素为0,将其与zero右边的元素交换,并将zero和i都向右移动一位if(nums[i] == 0){zero++;swap(nums,zero,i);i++;}// 如果当前元素为2,将其与two左边的元素交换,并将two向左移动一位else if (nums[i] == 2){ // 注意此时不需要i右移,因为交换后的元素还需要继续判断two --;swap(nums, i, two);}else{ //如果当前元素是1,不需要操作,直接继续向右遍历i ++;}}}// 交换数组中指定位置的两个元素private void swap(int[] nums, int i, int j){int t = nums[i];nums[i]= nums[j];nums[j] = t;}
}


我们首先来封装一个 selectK 的方法。封装好了这个方法以后,这三个问题都可
以快速求解。
我们的 selectK 的接口是这样的:
// 在 arr[l...r] 的范围里求解整个数组的第 k 小元素并返回
// k 是索引,即从 0 开始计算
int selectK(int[] arr, int l, int r, int k, Random rnd)
因为我们的 partition 过程需要随机选取标定点,所以我们还需要传一个 Random(快排的优化)
类的对象 rnd。
定义好函数签名以后,下面我们来书写相应的逻辑。
首先,selectK 的过程,我们就是要执行一遍 partition。在这里,我使用双路快速
排序的 partition。
注意,因为在这个问题中,我们肯定我们处理的数据类型是 int,所以,在代码
中,我不再使用泛型:

private int partition(int[] arr, int l, int r, Random rnd){// 生成 [l, r] 之间的随机索引int p = l + rnd.nextInt(r - l + 1);swap(arr, l, p);// arr[l+1...i-1] <= v; arr[j+1...r] >= vint i = l + 1, j = r;while(true){while(i <= j && arr[i] < arr[l])i ++;while(j >= i && arr[j] > arr[l])j --;if(i >= j) break;swap(arr, i, j);i ++;j --;
}swap(arr, l, j);return j;
}
private void swap(int[] arr, int i, int j){int t = arr[i];arr[i] = arr[j];arr[j] = t;
}

有了 partition,我们的 selectK 的主题逻辑非常简单。

首先,进行 partition,假设结果是 p。我们只需要将 k 和 p 做比较。

  • 如果 k == p,直接返回 arr[p] 即可;
  • 如果 k < p,在 arr[l, p - 1] 的范围继续找,即调用 selectK(arr, l, p - 1, k, rnd);
  • 如果 k > p,在 arr[p + 1, r] 的范围继续找,即调用 selectK(arr, p + 1, r, k, rnd);

就有了下面的代码:

private int selectK(int[] arr, int l, int r, int k, Random rnd){
int p = partition(arr, l, r, rnd);
if(k == p) return arr[p];
if(k < p) return selectK(arr, l, p - 1, k, rnd);return selectK(arr, p + 1, r, k, rnd);
}

这样,我们就完成了 select K 的过程。是不是非常简单!

下面,我们用我们写的 select K,先来解决 Leetcode 上第 215 号问题:

这个问题是求第 k 大元素,但是我们的 selectK 求得是第 k 小元素。怎么办?
非常简单,我们只需要在调用 select K 之前,将求第 k 大元素的这个 k,转换成
对应求的是第几小元素对应的索引就好了。
按照题目描述,如果 k 是 1,对应就是要找最大元素,那么相应的我们的
select K 的索引,就是 nums.length - 1。(如果10个数,K=1,第一个最大的数,就是SelectK索引为9的那个的元素)
如果 k 是 nums.length,其实就是求最小元素,那么相应的我们的 selectK 的
索引,就是 0。  (如果10个数,第10个最大的数,就是SelectK索引为0的那个的元素,最小值)
他们之间的转换关系是 nums.length - k。

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

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

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

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

import java.util.Random; //导入Random包
class Solution {public int findKthLargest(int[] nums, int k) {//只有两行,其他的内容全部复用我们上面实现的 selectK,是不是很酷?//我们的SelectK是第K最小元素,所以这里findKthLargest传入下标要处理一下//转换关系是 nums.length - kRandom rnd = new Random();return selectK(nums, 0, nums.length - 1, nums.length - k, rnd);}//有了 partition,我们的 selectK 的主题逻辑非常简单。private int selectK(int[] arr, int l, int r, int k, Random rnd){//首先,进行 partition,假设返回值结果是 p。我们只需要将 k 和 p 做比较。int p = partition(arr, l, r, rnd); //如果 k == p,直接返回 arr[p] 即可;if(k == p) return arr[p]; //如果 k < p,在 arr[l, p - 1] 的范围继续找,即调用 selectK(arr, l, p - 1, k, rnd);if(k < p) return selectK(arr, l, p - 1, k, rnd); //如果 k > p,在 arr[p + 1, r] 的范围继续找,即调用 selectK(arr, p + 1, r, k, rnd);return selectK(arr, p + 1, r, k, rnd);
}private int partition(int[] arr, int l, int r, Random rnd){// 生成 [l, r] 之间的随机索引int p = l + rnd.nextInt(r - l + 1);swap(arr, l, p);// arr[l+1...i-1] <= v; arr[j+1...r] >= vint i = l + 1, j = r;while(true){while(i <= j && arr[i] < arr[l])i ++;while(j >= i && arr[j] > arr[l])j --;if(i >= j) break;swap(arr, i, j);i ++;j --;}swap(arr, l, j);return j;}//数组指定索引,两数交换private void swap(int[] arr, int i, int j){int t = arr[i];arr[i] = arr[j];arr[j] = t;}
}

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

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

相关文章

普发Pfeiffer TPG252 TPG256A SingleGaugeTPG261-262使用说明手侧

普发Pfeiffer TPG252 TPG256A SingleGaugeTPG261-262使用说明手侧

卷积神经网络的结构组成与解释(详细介绍)

文章目录 前言 1、卷积层 2、激活层 3、BN层 4、池化层 5、FC层&#xff08;全连接层&#xff09; 6、损失层 7、Dropout层 8、优化器 9、学习率 10、卷积神经网络的常见结构 前言 卷积神经网络是以卷积层为主的深层网络结构&#xff0c;网络结构包括有卷积层、激活层、BN层、…

模板初阶的学习

目录&#xff1a; 一&#xff1a;泛型模板 二&#xff1a;函数模板 三&#xff1a;类模板 1&#xff1a;泛型模板 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础。 以交换函数为列进行讲解&#xff1a; void Swap(…

微服务中的重要模块

为什么要有微服务&#xff1f; 微服务提高开发效能&#xff0c;避免业务的重复理解&#xff0c;代码重复开发&#xff0c;增加开发效能和代码复用性。 在实际的工作中许多不同的业务有着共同的功能需求&#xff0c;如果我们每遇到一次这种需求就重新去理解构建一次的话会花费大…

【深度学习】【机器学习】用神经网络进行入侵检测,NSL-KDD数据集,基于机器学习(深度学习)判断网络入侵,网络攻击,流量异常【3】

之前用NSL-KDD数据集做入侵检测的项目是&#xff1a; 【1】https://qq742971636.blog.csdn.net/article/details/137082925 【2】https://qq742971636.blog.csdn.net/article/details/137170933 有人问我是不是可以改代码&#xff0c;我说可以。 训练 我将NSL_KDD_Final_1.i…

Day42:动态规划 LeedCode 01背包 416. 分割等和子集

01背包 1.确定dp数组以及下标的含义 dp[i][j]的含义&#xff1a;从下标为[0-i]的物品里任意取&#xff0c;放进容量为j的背包&#xff0c;价值总和最大是多少。 那么可以有两个方向推出来dp[i][j] 2.确定递推公式 不放物品i&#xff1a;由dp[i - 1][j]推出&#xff0c;即背…

十大排序——9.桶排序

这篇文章我们来介绍一下桶排序 目录 1.介绍 2.代码实现 3.总结与思考 1.介绍 桶排序和计数排序一样&#xff0c;都不是基于比较进行排序的。 下面通过一个例子来理解一下桶排序吧。 首先&#xff0c;给你一个无序数组[ 20,18,28,66,25,31,67,30 ]&#xff0c;然后&#…

Maven POM元素解析(二)

一、parent <parent>元素包含定位此项目将从中继承的父项目所需的信息。注意&#xff1a;此元素的子元素不是插值的&#xff0c;必须作为文字值给定。 ElementTypeDescriptiongroupIdString要从中继承的父项目的组id。artifactIdString要从中继承的父项目的项目id。ver…

【Entity Framework】你知道如何处理无键实体吗

【Entity Framework】你知道如何处理无键实体吗 文章目录 【Entity Framework】你知道如何处理无键实体吗一、概述二、定义无键实体类型数据注释 三、无键实体类型特征四、无键实体使用场景五、无键实体使用场景六、无键使用示例6.1 定义一个简单的Blog和Post模型&#xff1a;6…

高分二号卫星(GF-2):中国遥感科技的新高度

​高分二号卫星&#xff08;GF-2&#xff09;是中国在高分辨率地球观测领域的重要成就&#xff0c;其引入了先进的成像技术和灵活的数据获取模式&#xff0c;为地球资源监测、环境保护、城市规划等领域提供了强大的数据支持。本文将深入介绍高分二号卫星的技术特点、成像能力以…

Day 27 39. 组合总和 40.组合总和II 131.分割回文串

组合总和 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明&#xff1a; 所有数字&#xff08;包括 target&#xff09;都是正整数。解集不能…

自定义类型: 结构体 (详解)

本文索引 一. 结构体类型的声明1. 结构体的声明和初始化2. 结构体的特殊声明3. 结构体的自引用 二. 结构体内存对齐1. 对齐规则2. 为啥存在对齐?3. 修改默认对齐值 三. 结构体传参四. 结构体实现位段1. 什么是位段?2. 位段的内存分配3. 位段的应用4. 位段的注意事项 ​ 前言:…

什么是上位机?入门指南

什么是上位机&#xff1f; 上位机&#xff08;SCADA&#xff0c;Supervisory Control and Data Acquisition&#xff09;是一种软件系统&#xff0c;用于监控和控制工业过程中的设备。它通常与传感器、执行器和其他自动化设备一起工作&#xff0c;以实时地监视过程状态、收集数…

【精读文献】Scientific data|2017-2021年中国10米玉米农田变化制图

论文名称&#xff1a;Mapping annual 10-m maize cropland changes in China during 2017–2021 第一作者及通讯作者&#xff1a;Xingang Li, Ying Qu 第一作者单位及通讯作者单位&#xff1a;北京师范大学地理学部 文章发表期刊&#xff1a;《Scientific data》&#xff08…

Token2049主办方遭遇假门票风波,韩国罗马基金会Charles Lee损失50万美元

加密货币——遍地黄金&#xff1f;还是遍地陷阱&#xff1f; 尽管伊朗空袭以色列导致中东局势愈发紧张&#xff0c;但加密社区对当地市场的热情丝毫没有受到影响&#xff0c;不出意外的话&#xff0c;Token 2049这场全球最受瞩目的加密货币盛会将于4月18至19日在迪拜如期举行&…

Buck变换电路

Buck变换电路 Buck变换电路是最基本的DC/DC拓扑电路&#xff0c;属于非隔离型直流变换器&#xff0c;其输出电压小于输入电压。Buck变换电路具有效率高、输出稳定、控制简单和成本低的优点&#xff0c;广泛应用于稳压电源、光伏发电、LED驱动和能量回收系统。 电路原理 Buck变…

PyCharm 2024.1 发布:全面升级,助力高效编程!

PyCharm 2024.1 发布&#xff1a;全面升级&#xff0c;助力高效编程&#xff01; 文章目录 PyCharm 2024.1 发布&#xff1a;全面升级&#xff0c;助力高效编程&#xff01;摘要引言 Hugging Face&#xff1a;模型和数据集的快速文档预览针对 JavaScript 和 TypeScript 的全行代…

力扣101. 对称二叉树(java)

思路&#xff1a; 一、验证 左右子树是否可翻转对称的&#xff1f; 二、分析左右子树情况&#xff1a; 1&#xff09;左右都也空 对称 2&#xff09;左右有一个为空 不对称 3&#xff09;左右都不为空&#xff0c;但数字不同 不对称 4&#xff09;左右都不为空&#xff0c;且数…

C++从入门到精通——类和对象(下篇)

1. 再谈构造函数 1.1 构造函数体赋值 在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值。 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;} private:int _year;int _mont…

实验一: 分析ARP解析过程

1.实验环境 主机A和主机B连接到交换机&#xff0c;并与一台路由器互连 2.需求描述 主机A和主机B连接到交换机&#xff0c;并与一台路由器互连主机A和主机B设置为同一网段&#xff0c;网关设置为路由接口地址查看ARP相关信息&#xff0c;熟悉在PC和Cisco设备上的常用命令 3.推…