数据结构与算法--查找与排序另类用法-旋转数组中的最小数字

查找与排序

查找
  • 查找与排序都在程序设计中常被用到的算法。查找相对而言简单,一般都是顺序查找,二分查找,哈希表查找,和二叉排序树查找。其中二分查找是我必须熟悉的一种。
  • 哈希表和二叉排序树主要点在于他的数据结构而不是算法。哈希表主要的优点是我们利用他能在O(1)的时间查找某个元素,是效率最高的查找方式。但是缺点是需要额外空间来实现哈希表
  • 二叉排序树查找算法对应的数据结构是二叉搜索树(或者叫二叉查找树),之前我们已经着重讨论过这种数据结构原理以及自己的实现。
排序
  • 排序比查找要复杂,例如经常选择一种排序算法的时候经常会对各种排序算法进行比较:插入排序,冒泡排序,归并排序,快速排序等不同算法的优劣。而这些都是必须掌握的排序算法,我们必须能从空间福再度,时间复杂度等方面去分析他们的优缺点。其中快速排序是重中之重。可见的几种排序算法在之前的章节中也用动图的方式给出来详细的解释,实现。
实际案例
  • 快排是重要的排序算法,但是在具体场景下我们需要选择最优最合适的算法,例如下情况:
    • 实现一个排序算法,实际复杂度,空间复杂度必须不超过O(n),对公司所有员工年龄进行排序。
    • 分析上题中,重点空间复杂度,实际复杂度O(n)
    • 排序对象,员工年龄,我们假设员工都是100 岁以下,量级也不大,一个公司最多 也就10万
    • 这种情况,数组区间范围是固定的,而且基数不大最理想的排序算法是计数排序
另类用法:旋转数组中的最小数字
  • 题目:将数组最开始的若干个元素搬到数组的末尾,我们称为数组的旋转。输入一个递增数组的旋转,输出旋转数组的最小元素,例如数组{3,4,1,5,1,2}是{1,2,3,4,5}的一个旋转,明显最小值是1,
分析
  • 直观来看找最小值一次遍历就能搞定,时间复杂度O(n),但是这个并没有利用这个数组的特性,已排序,旋转后两部分有序肯定有更优解

  • 旋转后,两部分数组都有序,并且递增,必然有序部分后面大于前面

  • 然后分界处必然是最小值的特点

  • 由上部分分析我们自然想到二分查找寻找最小值。

  • 流程如下:

    • 定义指针min,max分别指向数组两端,按题意,第一个元素应该大于等于 最后一个元素,因为旋转过。
    • 接着找中间元素mid =(max+ min)/2, 如果中间元素大于min,则min到mid之间处于递增,则最小值必然在中间元素后面
    • 此时我们将min指针移动到mid位置
    • 同样如果中间元素mid 小于min,则表示最小值在mid或者mid的左边,
    • 此时我们将max指针移动到mid位置
    • 依次对min,max之间的数组部分进行如上流程,直到 max - min = 1 为止,此时最大,最小是相邻,则找出最小值
  • 如下实际案例{3,4,5,1,2},

    • min指针指向第0个元素 3 ,max指向最后一个2,中间元素5
    • 5 > 3,min移动到mid位置,也就是min指向5
    • 再次,中间元素变为1,1<5,此时,最小值在min右边
    • 将max移动到mid位置,也就是max指向1 ,
    • 此时max - min = 1,得到最小值max位置。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码实现
/*** @author liaojiamin* @Date:Created in 11:39 2021/3/16*/
public class FindRotateMin {public static int findMin(int[] array){if(array == null || array.length <= 0){return -1;}if(array.length == 1){return array[0];}if(array.length == 2){return array[0]> array[1] ? array[0] : array[1];}int index1 = 0;int index2 = array.length -1;int indexMin = index1;while (array[index1] >= array[index2]){if(index2 - index1 == 1){indexMin = index2;break;}indexMin = (index2 + index1)/2;if(array[indexMin] >= array[index1]){index1 = indexMin;}else if(array[indexMin] <= array[index1]){index2 = indexMin;}}return indexMin;}public static void main(String[] args) {int[] array = {3,4,5,0,1,2};System.out.println(array[findMin(array)]);}
}
  • 问题:上述代码中我们每次判断都会有等于的情况,当index1, index2,两个相同的时候,并且他们中介的数字indexMin也相同,这个时候,我们符合第一个判断,将indexMin赋值给了index1,此时默认最小数字在后面,其实不一定对,如下反例
  • 数组{1,0,1,1,1} 和数组{1,1,1,0,1} 都可以看成递增排序{0,1,1,1,1}的旋转,但是下图中最小值分别在左边和右边:

在这里插入图片描述

  • 如上情况,首尾数字,中介位置数字都是1 ,但是却有两种不同的最小值位置,因此这种特殊情况:当两个指针数字以及中间数字都一样的时候,无法判断最小值的位置,我们不得不采取遍历的方式。
  • 修改代码如下
/*** 二分排序另类用法* Created by jiamin5 on 2021/3/15.*/
public class FindRotateMin {public static int finMin(int[] array){if(array.length <= 0){return -1;}if(array.length == 1){return array[0];}if(array.length == 2){return array[1];}int index1 = 0;int index2 = array.length -1;int indexMin = index1;while (array[index1] >= array[index2]){if(index2 == index1 +1){indexMin = index2;break;}indexMin = (index1+index2)/2;if(array[index1] == array[index2] && array[indexMin] == array[index1]){return findMinList(array, index1, index2);}if(array[index1] <= array[indexMin]){index1 = indexMin;}else if(array[indexMin] <= array[index2]){index2 = indexMin;}}return array[indexMin];}public static int findMinList(int array[], int index1, int index2){int result = array[index1];for (int i = index1; i <= index2; i++){if(array[i] < result){result = array[i];}}return result;}public static void main(String[] args) {int[] array = {4,5,6,7,8,0,1,1,1,2,2,2,3,3,3,3,4,4};System.out.println(finMin(array));}
}
测试用例
  • 输入旋转数组,数组中没有重复数字
  • 边界值测试,只有一个,两个数字的数组
  • 输入特殊null值
  • 输入重复数字的数组

上一篇:数据结构与算法–利用栈实现队列
下一篇:数据结构与算法–再谈递归与循环(斐波那契数列)

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

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

相关文章

[MySQL基础]MySQL常见命令介绍

show databases; use 库名; show tables; show tables from 库名 select database(); create table 名字( id int, name varchar(20)); desc 表名; select * from 表名; insert into 表名 (a,b,…,f) values(1,2,3,…,7); update 库名 set name‘lilei’ where id1; delete f…

如何选择好公司

点击蓝字关注&#xff0c;回复“职场进阶”获取职场进阶精品资料一份前几天写了一篇文章&#xff1a;怎么判断自己在不在一家好公司。附带了一个投票调查&#xff0c;结果如下图&#xff1a;调研结果有点点扎心&#xff0c;有点点出乎我的意料。61%的小伙伴&#xff0c;都认为自…

数据结构与算法--再谈递归与循环(斐波那契数列)

再谈递归与循环 在某些算法中&#xff0c;可能需要重复计算相同的问题&#xff0c;通常我们可以选择用递归或者循环两种方法。递归是一个函数内部的调用这个函数自身。循环则是通过设置计算的初始值以及终止条件&#xff0c;在一个范围内重复运算。比如&#xff0c;我们求累加…

同步异步多线程这三者关系,你能给面试官一个满意的回答吗?

前几天一位朋友去面试&#xff0c;面试官问了他同步&#xff0c;异步&#xff0c;多线程之间是什么关系&#xff0c;异步比同步高效在哪&#xff1f;多线程比单线程高效在哪&#xff1f;由于回答的不好&#xff0c;让我帮他捋一下&#xff0c;其实回答这个问题不难&#xff0c;…

分布式事务框架seata

seata 前两篇文中总结了一下分布式事务已经现阶段常用的解决方案&#xff0c;现在来讨论一下现有的分布式事务框架seata&#xff0c;点击此处是seata的官网seata致力于微服务框架下提供高性能和简单易用的分布式事务服务。它提供了AT&#xff0c;TCC&#xff0c;Saga &#xf…

[一起读源码]走进C#并发队列ConcurrentQueue的内部世界 — .NET Core篇

在上一篇《走进C#并发队列ConcurrentQueue的内部世界》中解析了Framework下的ConcurrentQueue实现原理&#xff0c;经过抛砖引玉&#xff0c;得到了一众大佬的指点&#xff0c;找到了.NET Core版本下的ConcurrentQueue源码&#xff0c;位于以下地址&#xff1a;https://github.…

Java语法基础50题训练(上)

题目1: 有两只老虎&#xff0c;一只体重为180kg&#xff0c;一只体重为200kg&#xff0c;请用程序实现判断两只老虎的体重是否相同。 代码如下: public class OperatorTest {public static void main (String[] args) {int w1 180;int w2 200;boolean ans w1 w2?true:f…

EFCore.Sharding(EFCore开源分表框架)

简介本框架旨在为EF Core提供Sharding(即读写分离分库分表)支持,不仅提供了一套强大的普通数据操作接口,并且降低了分表难度,支持按时间自动分表扩容,提供的操作接口简洁统一.源码地址:EFCore.SHarding引言读写分离分库分表一直是数据库领域中的重难点,当数据规模达到单库极限的…

分布式事务 -- seata框架AT模式实现原理

Seata AT 模式 上一节中我们提到AT模式是基于XA事务模型演变过来的&#xff0c;所以他的整体机制也是一个改进版本的两阶段提交协议。 第一阶段&#xff1a;业务数据和回滚日志记录在同一个本地事务中提交&#xff0c;释放本地锁和链接资源第二阶段&#xff1a;提交异步化&…

[Java基础]数据输入

Scanner使用的基本步骤: 1.导包: import java.util.Scanner;2.创建对象: Scanner sc new Scanner(System.in);3.接收数据: int i sc.nextInt();代码如下: import java.util.Scanner;public class OperatorTest {public static void main (String[] args) {//创建对象Scan…

k8s中流量分离以及资源隔离实战

源宝导读&#xff1a;明源云客的终端用户越来越多&#xff0c;也涌现出线上流量活动的场景&#xff0c;大量的访问和接口请求导致服务器出现较高负载。本文将介绍云客团队为了缓解服务器压力&#xff0c;通过K8S进行分流与资源隔离的实践过程。一、背景PaaS和B2C的主要客户云客…

怎样实现WPF Prism Module的国际化和本地化?

English | 简体中文上一篇有简单介绍主工程的国际化&#xff0c;使用的资源字典(XAML)实现的。这几天我添加了几个Prism模块(Module)&#xff0c;发现子模块使用资源字典的方式实现国际化和本地化不好做&#xff0c;没有找到比较好的参考文章&#xff0c;所以换了一种方式&…

dotNET Core 3.X 使用 Jwt 实现接口认证

在前后端分离的架构中&#xff0c;前端需要通过 API 接口的方式获取数据&#xff0c;但 API 是无状态的&#xff0c;没有办法知道每次请求的身份&#xff0c;也就没有办法做权限的控制。如果不做控制&#xff0c;API 就对任何人敞开了大门&#xff0c;只要拿到了接口地址就可以…

数据结构与算法--代码鲁棒性案例分析

代码鲁棒性 鲁棒是robust的音译&#xff0c;就是健壮性。指程序能够判断输入是否符合规范&#xff0c;对不合要求的输入能够给出合理的结果。容错性是鲁棒的一个重要体现。不鲁棒的代码发生异常的时候&#xff0c;会出现不可预测的异常&#xff0c;或者程序奔溃。由于鲁棒性非…

【半译】两个gRPC的C#库:grpc-dotnet vs Grpc.Core

grpc-dotnet 是在2019年随着 .NET Core 3.0 一起发布的一个gPRC官方库。在ASP.NET Core 的 gRPC项目模板里面就使用了这个库。.NET Core 3.0之前难道不可以使用gRPC吗&#xff1f;目前&#xff0c;gRPC 在.NET上有两种官方实现&#xff1a;Grpc.Core&#xff1a;这个是原来的gR…

[Java基础]String对象的特点(易错点)

String对象的特点: 1.通过new创建的字符串对象&#xff0c;每一次new都会申请一个内存空间&#xff0c;虽然内容相同&#xff0c;但是地址值不同。 2.以""方式给出的字符串&#xff0c;只要字符串相同(顺序和大小写)&#xff0c;无论在程序代码中出现几次&#xff0…

数据结构与算法--解决问题的方法- 二叉树的的镜像

解决问题的思路 工作中遇到的问题可能用到的数据结构由很多&#xff0c;并且各种数据结构都不简单&#xff0c;我们不可能光凭借想象就能得到问题的解法&#xff0c;因此画图是在家具问题过程中用来帮助自己分析&#xff0c;推理的常用手段。很多问题比较抽象&#xff0c;不容…

使用dnSpy调试asp.net core源码

环境&#xff1a;window 10vs2019 16.5.1dnspy v6.1.4.netcore3.1参考&#xff1a;.Net反编译技术详解及4个反编译工具介绍一、关于dnSpydnSpy是近几年的新秀&#xff0c;功能远比ILSpy强大&#xff0c;甩.net Reflector几条街&#xff0c;被汉化、破解、逆向方面的人才奉为神器…

数据结构与算法--解决问题的方法-顺时针打印矩阵

顺时针打印矩阵 题目输入一个矩阵&#xff0c;按照从外向里顺时针的顺序依次打印每一个数字。例如下案例&#xff1a; 如上图矩阵&#xff0c;顺时针打印&#xff1a;1,2,3,4,8,12,16,15,14,13,9,5,6,7,1,10 以上问题看起来比较复杂&#xff0c;但是又没有涉及到复杂的数据结…