算法通关村第十关——快速排序算法

1 快速排序基本过程

快速排序的是将分治法运用到排序问题的典型例子。力扣912题,给你一个整数数组 nums,请你将该数组升序排列。

基本思想:是通过随机标记一个pivot元素将含有n个元素的序列划分为左右两个子序列leftright,其中left的元素都比pivot小,right的元素都比pivot大,然后再次对leftright分别执行快速排序,这样将左右两个子序列排列完后,整个序列也就是有序的了。这里以序列[28,36,35,38,34,25]为例,示意一下一轮快速排序的过程:

在这里插入图片描述

代码如下:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function(nums) {
    quickSort(nums, 0, nums.length - 1);
    return nums;
};

function quickSort(nums, start, end) {
    if (start >= end) {
        return;
    }
    const mid = partition(nums, start, end);
    quickSort(nums, start, mid - 1);
    quickSort(nums, mid + 1, end);
}

function partition(nums, start, end) {
    let pivot = nums[start];
    // 选择第一个数作为pivot,那么left就从第二个数开始进行比较
    let left = start + 1;
    let right = end;
    while (left <= right) {
        // 如果nums[left]一直小于pivot,left就向右移动
        while (left <= right && nums[left] <= pivot) {
            left++;
        }
        // 如果nums[right]一直大于pivot,right就向左移动
        while (left <= right && nums[right] >= pivot) {
            right--;
        }
        // 如果出现 nums[left] > pivot 或者 nums[right] < pivot 的情况,
        // 就交换 nums[left] 和 nums[right]的位置
        if (left < right) {
            [nums[left], nums[right]] = [nums[right], nums[left]];
            left++;
            right--;
        }    
    }
    // 把pivot交换到合适位置
    [nums[start], nums[right]] = [nums[right], nums[start]];
    return right;
}

但是当数组中包含大量重复元素时,会出现性能下降的现象,此时我们可以使用三路快速排序算法。

三路快速排序的基本思想是将数组划分为三个区域:小于、等于和大于 pivot 的区域。这样可以将相同元素聚集在一起,从而减少交换的次数,提高性能。

代码如下:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArray = function(nums) {
    threeWayQuickSort(nums, 0, nums.length - 1);
    return nums;
};

function threeWayQuickSort(nums, start, end) {
    if (start >= end) {
        return;
    }
    // 缩写解释 lt: less than(小于)  gt: greater than(大于)
    // 使用partitionThree函数进行三路划分
    const [lt, gt] = partitionThree(nums, start, end);
    threeWayQuickSort(nums, start, lt - 1);
    threeWayQuickSort(nums, gt + 1, end);
}

function partitionThree(nums, start, end) {
    let pivot = nums[start];
    // lt指向小于pivot的区域的末尾
    let lt = start;
    // gt指向大于pivot的区域的起始
    let gt = end;
    // 用于遍历数组的指针
    let i = start;
    
    while (i <= gt) {
        if (nums[i] < pivot) {
            // 将当前元素交换到小于pivot区域末尾,并扩展小于区域
            [nums[lt], nums[i]] = [nums[i], nums[lt]];
            lt++;
            i++;
        } else if (nums[i] > pivot) {
            // 将当前元素交换到大于pivot区域起始,并扩展大于区域
            [nums[gt], nums[i]] = [nums[i], nums[gt]];
            gt--;
        } else {
            // 相等情况,直接扩展等于区域
            i++;
        }
    }
    // 将pivot元素交换到适当位置
    [nums[start], nums[lt]] = [nums[lt], nums[start]];
    // 返回等于区域的起始和末尾
    return [lt, gt];
}

这段代码中的 partitionThree 函数实现了三路划分,将数组划分为小于、等于和大于 pivot 的三个区域,从而有效处理重复元素。在每次递归中,通过 ltgt 两个指针来维护三个区域的边界。相同元素会被直接放入等于区域,从而避免了不必要的交换操作。这种方法可以显著提高处理包含大量重复元素的数组的性能。

2 数组中第K大的数字

力扣215 题,数组中的第K个最大元素。给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

基于快速排序来解决这个问题,当我们完成快速排序后,序列是一个升序序列,我们只需要在排好序的序列中找到nums.length - k个元素即为最大的第k个元素。同样如果数组里包含海量重复元素那么就可以使用三路快速排序思想,将数组分为小于、等于和大于 pivot 的三个区域,以减少不必要的交换操作和递归。

代码如下:

var findKthLargest = function(nums, k) {
	// 使用快速选择算法,在索引范围 [0, nums.length - 1] 中寻找第 k 个最大元素
    return quickSelect(nums, 0, nums.length - 1, nums.length - k);
};

/**
 * 快速选择函数
 * */
function quickSelect(nums, start, end, targetIndex) {
	// 如果区间中只有一个元素,则该元素就是第 k 个最大元素
    if (start === end) {
        return nums[start];
    }
    // 使用三路快速排序的方式进行划分
    const { left, right } = threeWayPartition(nums, start, end);
    // 如果 targetIndex 在 [left, right] 区间内,则说明第 k 个最大元素就在该区间内
    if (targetIndex >= left && targetIndex <= right) {
        return nums[targetIndex];
    } else if (targetIndex < left) {
    	// 否则,在左侧区域寻找第 k 个最大元素
        return quickSelect(nums, start, left - 1, targetIndex);
    } else {
    	// 在右侧区域寻找第 k 个最大元素
        return quickSelect(nums, right + 1, end, targetIndex);
    }
}

/**
 * 三路快速排序划分函数
 * 
 * */
function threeWayPartition(nums, start, end) {
	// 选取最后一个元素作为 pivot
    const pivot = nums[end];
    let i = start;  // 当前元素索引
    let lt = start; // lt指向小于pivot的区域的末尾
    let gt = end;   // gt指向大于pivot的区域的起始
    
    while (i <= gt) {
        if (nums[i] < pivot) {
        	// 将当前元素交换到小于 pivot 区域
            [nums[i], nums[lt]] = [nums[lt], nums[i]];
            i++;
            lt++;
        } else if (nums[i] > pivot) {
        	// 将当前元素交换到大于 pivot 区域
            [nums[i], nums[gt]] = [nums[gt], nums[i]];
            gt--;
        } else {
        	// 相等的情况,直接跳过
            i++;
        }
    }
    // 返回小于 pivot 区域的右边界和大于 pivot 区域的左边界
    return { left: lt, right: gt };
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

el-table动态合并单元格

el-table使用这个方法合并单元格&#xff0c;:span-method“hbcell” <el-table size"small" :data"table.data" border empty-text"暂无数据" :cell-style"cellStyle" :header-cell-style"tableHeaderColor":span-meth…

Linux 终端命令之文件目录操作,对比Dos相关命令

目录 前言 基础命令&#xff08;文件目录相关的&#xff09; cd命令 【英文帮助】 【对应Dos命令】 pwd命令 【英文帮助】 【对应Dos命令】 ls命令 【英文帮助】 【对应Dos命令】 tree命令 【英文帮助】 【对应Dos命令】 mkdir命令 【英文帮助】 【对应Dos命令…

vscode的远程代码调试

目录 ssh连接 xdebug调试 ssh连接 在vscode中下载该插件 这里用虚拟机测试&#xff0c;这里用虚拟机测试&#xff0c;注意ssh是可以连接的 然后安装好remote后&#xff0c;点击左下角的>< 在弹出的这个上选择connect to host连接一台主机 配置完用户名和IP后再点一次发…

xsschallenge通关(11-15)

level 11 老规矩&#xff0c;先查看源码&#xff0c;做代码审计&#xff1a; <?php ini_set("display_errors", 0); $str $_GET["keyword"]; $str00 $_GET["t_sort"]; $str11$_SERVER[HTTP_REFERER]; $str22str_replace(">&quo…

微软宣布在 Excel 中使用 Python:结合了 Python 的强大功能和 Excel 的灵活性。

文章目录 Excel 中的 Python 有何独特之处&#xff1f;1. Excel 中的 Python 是为分析师构建的。高级可视化机器学习、预测分析和预测数据清理 2. Excel 中的 Python 通过 Anaconda 展示了最好的 Python 分析功能。3. Excel 中的 Python 在 Microsoft 云上安全运行&#xff0c;…

史上最全 App功能测试点分析

1.2测试周期 测试周期可按项目的开发周期来确定测试时间&#xff0c;一般测试时间为两三周&#xff08;即 15个工作日&#xff09;&#xff0c; 根据项目情况以及版本质量可适当缩短或延长测试时间。正式测试前先向主管确认项目排期。 1.3测试资源 测试任务开始前&#xff…

手把手教你搭建一个盲盒小程序,轻松掌握开发技巧

在当今社交媒体时代&#xff0c;微信公众号已成为企业、个人传播和推广的重要工具。而微信公众号盲盒小程序则是一个更为创新和互动的方式&#xff0c;能够吸引更多用户的关注和参与。下面&#xff0c;我们将为大家介绍一下微信公众号盲盒小程序的制作完全攻略。 1. 注册登录【…

MySQL数据库基本操作

目录 一、数据库中常用的数据类型 二、常用命令与操作 1.DDL数据库定义语言 1、登录用户的数据库 2、查看当前服务器中的数据库 3、切换/进入数据库 并 查看数据库中包含的表 4、查看数据库中表的结构 5、创建数据库 7、展示创建数据表时的结构 8、创建表&#xff0c…

根据案例写PLC程序-红绿灯控制

案例&#xff1a; 1、南北方向红灯点亮30s后熄灭&#xff1b; 2、在点亮南北方向红灯的同时点亮东西方向绿灯&#xff0c;并在点亮25s后&#xff0c;以0.5s熄灭0.5s点亮的时间闪烁3次后熄灭&#xff1b; 3、在东西方向绿灯熄灭后&#xff0c;东西方向黄灯点亮2s后熄灭&#xff…

Redis知识点总结

概述 Redis诞生于2009年&#xff0c;全称是Remote Dictionarty Server(远程词典服务器) 只支持单线程 非关联&#xff1a;主要指的是表中没有主外键等概念 Redis是一款内存数据库&#xff0c;主要存储键值对类型的数据 基本用法 注意&#xff1a;该操作是在cli中进行的 首…

pytestx重新定义接口框架设计

概览 脚手架&#xff1a; 目录&#xff1a; 用例代码&#xff1a; """ 测试登录到下单流程&#xff0c;需要先启动后端服务 """test_data {"查询SKU": {"skuName": "电子书"},"添加购物车": {"sk…

Matlab之智能优化算法函数调用

1.句柄函数 句柄函数即我们要求的目标函数&#xff0c;以下三种算法的调用仅是求解最小值&#xff0c;若要求目标函数的最大值&#xff0c;可在返回结果中加负号。 function value Get_Fitness(x,y)value x^2 y^2;% 若要求x^2 y^2最大值可设value -(x^2 y^2); end句柄函数…

跨境新手看过来!各国营销禁忌盘点!别再盲目踩雷了!

本土化是跨境卖家出海制胜的关键因素之一&#xff0c;不管是卖家的产品&#xff0c;还是营销推广策略&#xff0c;都要符合目标市场的习惯&#xff0c;才会有较好的效果。而与此相反的&#xff0c;如果卖家在营销过程中&#xff0c;踩到了营销雷区&#xff0c;那结果也可想而知…

机器视觉应用开发四大软件,那一个对我们从0到1建设你的机器视觉知识体系更好

我们首先要理解什么是知识体系&#xff1a; 我们身处一个知识爆炸时代&#xff0c;我们面对各种课程&#xff0c;各种知识&#xff0c;“自身学习”&#xff0c;“高效记忆”&#xff0c;“批判性思维”&#xff0c;“解决问题的能力”。各种平台课程太多&#xff0c;各种买买…

详解numpy.random.choice函数

文章目录 函数原型参数解析该函数的注意事项例子示例代码示例结果 参考 numpy的random模块中的choice函数用于从给定一维&#xff08;1-D&#xff09;数组中生成随机样本。本博客详细节将该函数的API&#xff0c;并给出示例代码和结果。 函数原型 numpy.random.choice(a, siz…

0825hw

//冒泡排序 void Bubble_sort(Sp p) {for(int i1;i<p->len;i){for(int j0;j<p->len-i;j){if(p->arr[j]>p->arr[j1]){int tp->arr[j];p->arr[j]p->arr[j1];p->arr[j1]t;}}} } //简单选择排序 void Simple_sort(Sp p) {for(int i1;i<p->l…

【android12-linux-5.1】【ST芯片】HAL移植后开机卡死

按照ST的官方readme移植HAL后开机一直卡在android界面&#xff0c;看logcat提示写文件时errorcode&#xff1a;-13。查下资料大致明白13错误码是权限不足&#xff0c;浏览代码在写文件的接口加日志后&#xff0c;发现是需要写iio:device*/buffer/enable这类文件的时候报错的。千…

UG\NX二次开发 使用录制功能录制操作记录时,如何设置默认的开发语言?

文章作者&#xff1a;里海 来源网站&#xff1a;王牌飞行员_里海_里海NX二次开发3000例,C\C,Qt-CSDN博客 简介&#xff1a; NX二次开发使用BlockUI设计对话框时&#xff0c;如何设置默认的代码语言&#xff1f; 效果&#xff1a; 方法&#xff1a; 依次打开“文件”->“实用…

K8s学习笔记3

Kubernetes功能&#xff1a; Kubernetes是一个轻便的可扩展的开源平台&#xff0c;用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中&#xff0c;会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes积累了作为Goog…

npm yarn pnpm npx nvm 命令怎么区分怎么用

npm​​​​​​​ 包管理器&#xff0c;可以用来安装、卸载、更新和管理各种包npm的package.json中文文档 参数 - install&#xff1a;安装一个或多个包。例如&#xff1a;npm install 。 uninstall&#xff1a;卸载一个包。例如&#xff1a;npm uninstall 。 update&#xf…