从LeetCode215看排序算法

目录

LeetCode215 数组的第K个最大元素

 ① 第一反应:java的内置排序Arrays.sort()

② 冒泡排序

③归并排序(先分解再合并)

④快速排序(边分解边排序)

⑤堆排序


LeetCode215 数组的第K个最大元素

给定整数数组 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

 ① 第一反应:java的内置排序Arrays.sort()

arrays.sort的复杂度取决于所使用的排序算法。在java中,Arays类中的sort方法使用的是一种优化的快速排序算法或归并排序算法
对于快速排席算法,其平均时间复杂度为0(nl0gn),其中n是数组的大小。然而,在最坏情况下,快速排序的时间复杂度可以达到O(n^2),这发生在数组已经有序的情况下。
对于归并排序算法,其时间复杂度始终为0(nlog n),不论输入数据的情况如何。
总结起来,Arrays.sort方法的平均时间复杂度为0(nlog n),最坏情况下可能为O(n^2)。


② 冒泡排序

思路:总结来说就是两个for循环。多次遍历数组,每次遍历通过不断比较相邻元素的大小,如果左边大于右边就交换元素顺序,最终会将一个最大(或最小的)元素冒泡到数组的末尾或开头。直到最终没有任何元素需要交换(end一直--)。

举个例子,假设我们有一组数字:3, 38, 5, 44, 15, 47, 36, 26, 27, 2, 46, 4, 19, 50, 48。

下面是冒泡排序的执行过程:
1.第一轮比较后,最大的数字 50 被冒泡到了数组末尾,数组变为:3, 5, 38, 15, 44, 36, 26, 27, 2, 46, 4, 19, 47, 48, 50

2.第二轮比较后,第二大的数字 48 被冒泡到了倒数第二的位置,数组变为:3, 5, 15, 38, 36, 26, 27, 2, 44, 4, 19, 46, 47, 48, 50

3.经过多轮比较和交换后,所有数字按照从小到大的顺序排列完成。

第k大只要找到第k个泡泡即可,无需向后比较对整个数组进行排序

class Solution {
    public int findKthLargest(int[] nums, int k) {
        return bubbleSort(nums, k);
    }

    int bubbleSort(int[] nums, int k){
        int n = nums.length;
        int count = 0;
        for(int i=0;i<n-1;i++){
            for(int j=0;j<n-i-1;j++){
                if(nums[j] > nums[j+1]){
                    int tmp =nums[j];
                    nums[j] = nums[j+1];
                    nums[j+1] = tmp;
                }
            }
            count++;
            if(count == k){
                break;
            }
        }
        return nums[n-k];
    }
}

时间复杂度:最坏情况:O(N^2)
      最好情况:O(N)
空间复杂度:O(1)
 


③归并排序(先分解再合并)

思路:通过分治法将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。与快速排序相比,快速排序是将序列划分成两个子序列,再递归使子序列有序;而归并排序是先使子序列有序,再进行合并。

运算符小妙用:

偶数&1 结果为0;奇数&1 结果为1;

左移相当于乘以2^n;右移相当于除以2^n,所以通常会用>>1来代替除以2。

不用第三个变量交换两个整数:

    void swap(int x , int y)
    {
         x ^= y;
         y ^= x;
         x ^= y;
    }

不断从中间划分子数组,递归合并

public class MergeSort {   
    public static int[] mergeSort(int[] nums, int l, int h) {
        if (l == h)
            return new int[] { nums[l] };
         
        int mid = l + (h - l) / 2;
        int[] leftArr = mergeSort(nums, l, mid); //左有序数组
        int[] rightArr = mergeSort(nums, mid + 1, h); //右有序数组
        int[] newNum = new int[leftArr.length + rightArr.length]; //新有序数组
         
        int m = 0, i = 0, j = 0; 
        while (i < leftArr.length && j < rightArr.length) {
            newNum[m++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++];
        }
        while (i < leftArr.length)
            newNum[m++] = leftArr[i++];
        while (j < rightArr.length)
            newNum[m++] = rightArr[j++];
        return newNum;
    }

 LeetCode 4:寻找两个正序数组的中位数

这道题就用到了归并排序

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
 
        int totalLength = nums1.length + nums2.length;
        int[] nums = new int[totalLength];
        int i = 0, j = 0;
        int index = 0;
        while (index <= totalLength /2) {
            if (i < nums1.length && (j >= nums2.length || nums1[i] < nums2[j])) {
                nums[index] = nums1[i++];
            } else{
                nums[index] = nums2[j++];
            }
            if (index == totalLength / 2) {
                //nums数组长度为偶数
                if ((totalLength & 1) == 0) {
                    return (nums[index] + nums[index - 1]) / 2.0;
                } else {
                    //nums数组长度是奇数
                    return 1.0 * nums[index];
                }
            }
            index++;
        }
        return 0.0;
    }
}

时间复杂度:O(nlogn)(稳定,因为每次都是从中间划分)

空间复杂度:递归造成栈空间的使用,最好O(nlogn),最坏O(n)


④快速排序(边分解边排序)

思路:通过分治法将一个数组分成较小的子数组,然后递归地对每个子数组进行排序。

移动左右指针,左指针向右移动,直到找到一个大于等于分界值的元素;右指针向左移动,直到找到一个小于等于分界值的元素。交换这两个元素的位置,然后再次移动左右指针,直到左指针和右指针指向同一个元素,再递归左右子数组。

快速排序找到第k个最大的,就是排序后递增子数组的倒数第k个(序号为n-k)

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int n = nums.length;
        return quickSelect(nums, 0, n-1, n-k);
    }

    public int quickSelect(int[] nums, int l, int r, int k){
        if(l == r)  return nums[k];
        int x = nums[l], i = l-1, j = r+1;
        while(i < j){
            do i++;  while(nums[i] < x);
            do j--;  while(nums[j] > x);
            if(i < j){
                int tmp = nums[i];
                nums[i] = nums[j];
                nums[j] = tmp;
            }
        }
        //这个时候i==j==x,要寻找的坐标<=j则说明第k大元素在分界元素左边
        if(k <= j)  return quickSelect(nums, l, j, k);
        else return quickSelect(nums, j+1, r, k);
    }
}

快排的时间复杂度我们可以认为是O(nlogn),但当遇到原数组本身有序的情况下,其时间复杂度就会退化至O(n^2),这个其实很好理解,举个例子就明白了:

最优情况下,即每趟选择key时都恰好选择到数组的中间值时(第n层可以确定2^{n-1}个数字位置),快排的时间复杂度如下图完全(满)二叉树:


在最坏的情况下,这个树是一个完全的斜树,只有左半边或者右半边,即每趟选择key时都恰好选择到数组最大或最小的值时(即每一层都只能确定一个数字位置)。这时候我们的比较次数就变为∑n−1i=1(n−i)=(n−1)+(n−2)+⋯+1=n∗(n−1)2=O(n^2)

时间复杂度:最好O(nlogn),最坏O(n^2)

空间复杂度:递归造成栈空间的使用,最好O(nlogn),最坏O(n)


⑤堆排序

java提供了PriorityQueue,可以构建小顶堆

class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> queue = new PriorityQueue<>(); //小顶堆
        for(int num : nums){
            queue.add(num);
            if(queue.size() > k){
                queue.poll();
            }
        }
        return queue.peek();
    }
}

自己构建堆 

class Solution {
    public int findKthLargest(int[] nums, int k) {
        //-------------1.首先,构建最大堆[6,5,4,3,2,1]----------------
        //建大堆:要从堆的最后一个非叶子节点开始向下调整
        for (int i = nums.length/2-1; i >= 0; i--) {
            adjustHeap(nums,i,nums.length);
        }
        //---2.每次把最大的换到最后一个位置,调整堆,交换后不把最后一个数看作堆里的数据-------
        for(int i = nums.length-1;i >= nums.length-k ;i--){
            swap(nums,0,i);
            adjustHeap(nums,0,i);    //选出次小的数
        }
        return nums[nums.length-k];
    }
        //向下调整算法
        public static void adjustHeap(int[] nums,int node,int tail){
        int left = node*2+1;
        int right = node*2+2;
        //-------------大的往上浮,小的往下浮--------------------
        int max = node;
        if(left<tail&&nums[left]>nums[max]){
            max=left;
        }
        if(right<tail&&nums[right]>nums[max]){
            max=right;
        }
        //---------max是父节点和左右子节点中最大的数-------------------
        //max!=node证明左右子节点有比父节点大的数,需要进行交换
        if(max!=node){
            swap(nums,max,node);
            adjustHeap(nums,max,tail);
        }
    }
 
    public static void swap(int[] nums, int index1, int index2){
        int tmp = nums[index1];
        nums[index1]=nums[index2];
        nums[index2]=tmp;
    }
}

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

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

相关文章

LLM(大语言模型)解码时是怎么生成文本的?

Part1配置及参数 transformers4.28.1 源码地址&#xff1a;transformers/configuration_utils.py at v4.28.1 huggingface/transformers (github.com) 文档地址&#xff1a;Generation (huggingface.co) 对于生成任务而言&#xff1a;text-decoder, text-to-text, speech-…

详解MySQL中的递归查询

MySQL中的递归查询主要通过WITH RECURSIVE语句来实现&#xff0c;这在处理具有层级关系或树形结构的数据时非常有用。下面将通过一个具体的例子来详细解释如何在MySQL中使用递归查询。 示例场景 假设我们有一个部门表&#xff08;departments&#xff09;&#xff0c;其中包含…

Zynq系列FPGA实现SDI编解码转SFP光口传输(光端机),基于GTX高速接口,提供6套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐本博已有的 SDI 编解码方案本方案在Xilinx-Kintex7上的应用 3、详细设计方案设计原理框图输入Sensor之-->OV5640摄像头输入Sensor之-->HDMIVDMA图像缓存RGB转BT1120GTX 解串与串化SMPTE SD/HD/3G SDI IP核BT1120转RGBHDMI输…

Rust 通过 Deref trait 将智能指针当作常规引用处理

通过 Deref trait 将智能指针当作常规引用处理 实现 Deref trait 允许我们重载 解引用运算符&#xff08;dereference operator&#xff09;*&#xff08;与乘法运算符或通配符相区别&#xff09;。通过这种方式实现 Deref trait 的智能指针可以被当作常规引用来对待&#xff…

基于IDEA的Lombok插件安装及简单使用

lombok介绍 Lombok能以注解形式来简化java代码&#xff0c;提高开发效率。开发中经常需要写的javabean&#xff0c;都需要花时间去添加相应的getter/setter&#xff0c;也许还要去写构造器、equals等方法&#xff0c;而且需要维护。而Lombok能通过注解的方式&#xff0c;在编译…

Qt中文个数奇数时出现问号解决

Qt中文个数奇数时出现问号解决 目录 Qt中文个数奇数时出现问号解决问题背景问题场景解决方案 问题背景 最近在开发一个小工具&#xff0c;涉及到一些中文注释自动打印&#xff0c;于是摸索如何把代码里面的中文输出到csv文件中&#xff0c;出现了乱码&#xff0c;按照网上的攻…

供应链管理(SCM):如何在颜值和体验上发力

要在供应链管理系统&#xff08;SCM&#xff09;中在颜值和体验上发力&#xff0c;让用户感觉耳目一新&#xff0c;可以采取以下措施&#xff1a; 界面设计优化&#xff1a; 对供应链管理系统的界面进行优化&#xff0c;注重界面的美观、简洁和易用性。采用现代化的设计风格、…

Python酷库之旅-第三方库Pandas(026)

目录 一、用法精讲 65、pandas.bdate_range函数 65-1、语法 65-2、参数 65-3、功能 65-4、返回值 65-5、说明 65-6、用法 65-6-1、数据准备 65-6-2、代码示例 65-6-3、结果输出 66、pandas.period_range函数 66-1、语法 66-2、参数 66-3、功能 66-4、返回值 6…

Gooxi受邀参加第三届中国数据中心服务器与设备峰会

7月2-3日&#xff0c;第三届中国数据中心服务器与设备峰会在上海召开&#xff0c;作为国内最聚焦在服务器领域的专业峰会&#xff0c;吸引了来自全国的行业专家、服务器与机房设备厂家&#xff0c;企业IT用户&#xff0c;数据中心业主共同探讨AIGC时代下智算中心设备的设计之道…

【Linux】03.权限

一、权限的概念 Linux下有两种用户&#xff1a;超级用户&#xff08;root&#xff09;、普通用户。 超级用户&#xff1a;可以在 linux 系统下做任何事情&#xff0c;不受限制普通用户&#xff1a;在linux下做有限的事情超级用户的命令提示符是“#”&#xff0c;普通用户的命…

Linux驱动开发-04LED灯驱动实验(直接操作寄存器)

一、Linux 下LED 灯驱动原理 Linux 下的任何外设驱动&#xff0c;最终都是要配置相应的硬件寄存器。驱动访问底层的硬件除了使用内存映射将物理地址空间转化为虚拟地址空间&#xff0c;去进行读写修改&#xff0c;还可以通过各种子系统函数去进行操作 1.1 地址映射 MMU 全称…

JavaWeb后端学习

Web&#xff1a;全球局域网&#xff0c;万维网&#xff0c;能通过浏览器访问的网站 Maven Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建Java项目的工具 作用&#xff1a; 依赖管理&#xff1a;方便快捷的管理项目以来的资源&#xff08;jar包&#xff09;&am…

vue2学习笔记5 - 表单类元素的单向数据绑定和双向数据绑定

前言 上一节我们学到&#xff0c;可以通过v-bind:指令&#xff0c;将标签体属性值通过js表达式绑定到vue实例中的某data上&#xff0c;读取该data数据&#xff0c;并通过vue模板中指定的页面元素&#xff0c;展示在页面上。 但是&#xff0c;我们在使用网页表单的时候&#x…

Ctrl+C、Ctrl+V、Ctrl+X 和 Ctrl+Z 的起源

注&#xff1a;机翻&#xff0c;未校对。 The Origins of CtrlC, CtrlV, CtrlX, and CtrlZ Explained We use them dozens of times a day: The CtrlZ, CtrlX, CtrlC, and CtrlV shortcuts that trigger Undo, Cut, Copy, and Paste. But where did they come from, and why do…

文件安全传输系统,如何保障信创环境下数据的安全传输?

文件安全传输系统是一套旨在保护数据在传输过程中的安全性和完整性的技术或解决方案。通常包括以下几个关键组件&#xff1a; 加密&#xff1a;使用强加密算法来确保文件在传输过程中不被未授权访问。 身份验证&#xff1a;确保只有授权用户才能访问或传输文件。 完整性校验…

怎样优化 PostgreSQL 中对复杂的排序规则和排序方向的查询?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 怎样优化 PostgreSQL 中对复杂的排序规则和排序方向的查询一、理解复杂排序规则和排序方向二、优化索引…

css - - - - - 去除图片默认的白色背景(混合模式 mix-blend-mode)

去除图片默认的白色背景&#xff08;mix-blend-mode&#xff09; 1. 需求描述2. 原图展示3. 原代码展示4. 使用混合模式(mix-blend-mode)5.修改后效果 1. 需求描述 图片含有白色地图&#xff0c;想要将其去掉 2. 原图展示 3. 原代码展示 <div><img src*****/> &…

负载箱如何帮助维持电气系统的最佳性能

负载箱在维持电气系统最佳性能方面发挥着至关重要的作用&#xff0c;以下是负载箱如何帮助维持电气系统最佳性能的详细分析&#xff1a; 一、保护电气设备 负载箱能够在电气系统中产生恒定的负载&#xff0c;使电气设备在正常工作状态下运行。这避免了因负载波动过大而导致的…

vue2迁移到vue3注意点

vue2迁移到vue3注意点 1、插槽的修改 使用 #default &#xff0c; 以及加上template 模板 2、 类型的定义&#xff0c;以及路由&#xff0c;vue相关资源&#xff08;ref, reactive,watch&#xff09;的引入等 3、类装饰器 1&#xff09;vue-class-component是vue官方库,作…

【unity实战】使用unity制作一个红点系统

前言 注意&#xff0c;本文是本人的学习笔记记录&#xff0c;这里先记录基本的代码&#xff0c;后面用到了再回来进行实现和整理 素材 https://assetstore.unity.com/packages/2d/gui/icons/2d-simple-ui-pack-218050 框架&#xff1a; RedPointSystem.cs using System.…