查找与排序

查找
  • 查找与排序都在程序设计中常被用到的算法。查找相对而言简单,一般都是顺序查找,二分查找,哈希表查找,和二叉排序树查找。其中二分查找是我必须熟悉的一种。
  • 哈希表和二叉排序树主要点在于他的数据结构而不是算法。哈希表主要的优点是我们利用他能在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值
  • 输入重复数字的数组

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

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

  1. js数组查找最接近_在JavaScript数组中找到最小元素的位置

    在JavaScript数组中找到最小元素的位置 注*  之前有篇文章介绍过数据遍历的性能比较: for in 比for loop慢至少20倍 ,这是另外一篇比较数组查找性能的例子,通过对手工/inde ...

  2. Python__数据结构与算法——查找与排序

    查找和排序是最基本的算法,在很多脚本中都会用到查找和排序.尽管 Python 提供的用于查找和排序的函数能够满足绝大多数需求,但还是有必要了解最基本的查找和排序算法,以便在有特殊需求的情况下,可以自己 ...

  3. 数据结构与算法-查找和排序

    查找算法: 顺序查找 对待查找数据没有要求,从头到尾逐一比较,在小规模的查找中较为常见,查找效率较低 时间复杂度:O(n) 二分查找(折半查找) 待查找的数据必须有序,从数据中间位置开始比较查找,如果 ...

  4. 输出一个为递增排序数组的旋转数组中的最小元素——8

    把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为数组{1, 2,3, 4, 5}的一个旋转, ...

  5. java旋转数组查找某一个值_旋转数组中查找某个元素

    在一个排序的数组中,如{1,2,3,4,5,6,7},经过旋转后得到{4,5,6,7,1,2,3},当然也可以得到原数组{1,2,3,4,5,6,7},在该旋转后的数组中查找某个元素. 旋转后的数组可 ...

  6. python数字排序 循环_【python-leetcode448-循环排序】找到所有数组中消失的数字

    问题描述: 给定一个范围在  1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次. 找到所有在 [1, n] 范围之间没有出现在数组中的数字 ...

  7. 【数据结构与算法】之深入解析“删除有序数组中的重复项”与“移除元素”的求解思路与算法示例

    删除有序数组中的重复项 一.题目要求 给你一个升序排列的数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度.元素的相对顺序应该保持 一致 . 由于在某些语言中不 ...

  8. 数据结构与算法:选择排序

    数据结构与算法:选择排序 雪柯 大工生物信息 提笔为写给奋进之人 已关注 8 人赞同了该文章 引用自算法图解,作者[美] Aditya Bhargava 译袁国忠 特别备注:本书非原创,但部分内容自己 ...

  9. python定义链表节点_Python数据结构与算法之链表定义与用法实例详解【单链表、循环链表】...

    本文实例讲述了Python数据结构与算法之链表定义与用法.分享给大家供大家参考,具体如下: 本文将为大家讲解: (1)从链表节点的定义开始,以类的方式,面向对象的思想进行链表的设计 (2)链表类插入和 ...

最新文章

  1. 因0x764fb11c的错误状态_《最强大脑》国际赛王易木又被质疑作弊,因背反答案露出了马脚?...
  2. C++读取mysql中utf8mb4编码表数据乱码问题及UTF8转GBK编码
  3. 机器人局部避障的动态窗口法(dynamic window approach) (转)
  4. Processing 字体变形
  5. mysql租车管理系统_基于java实现租车管理系统
  6. 真正零基础Python入门:手把手教你从变量和赋值语句学起
  7. gridview 万能分页代码
  8. expect学习笔记及实例详解【转】
  9. vue+echarts 实时跟新数据 仪表盘多个渲染
  10. Cmake构建_选择debug与release的库
  11. U-Net及使用keras搭建U-Net分割网络以及改进和问题纪实
  12. ABBYY FineReader PDF for Mac(多功能PDF转换工具)
  13. Win10蓝屏原因分析记录
  14. 代码比较工具DiffMerge的下载和使用
  15. DEL计算机英语翻译,哥德尔计算机,G·del computer,音标,读音,翻译,英文例句,英语词典...
  16. git 查看自己秘钥_Git秘钥问题
  17. 【学习记录】QT5界面设计的踩坑记录
  18. ClickHouse函数操作大全
  19. Python学习之路21-序列构成的数组
  20. spark考试练习题

热门文章

  1. Android studio之编译出现 Error:null value in entry: outputDirectory=null
  2. Linux命令行编辑的快捷键
  3. 我让代码生了个孩子继承了他爸爸谁知他爸爸继承了他爷爷(16)
  4. 【必懂C++】第一个程序当然是HelloWorld呀 01
  5. 【C语言简单说】十三:变量的生命周期
  6. amap vueamap 与_在vue中使用高德地图vue-amap
  7. 一根火柴可以将一瓶大可乐吊起来吗?
  8. 年轻人不讲武德有多可怕?
  9. 成年人改变生活的方式,都是从它开始
  10. 限时秒杀┃月销10000+件,风靡全国的steam科学实验套装