数据结构与算法--数字在排序数组中出现次数

数字在排序数组中出现次数

  • 题目:统计一个数字在一个排序数组中出现的次数。例如,输入数组{1,2,3,3,3,3,3,4,5} 和数字3,由于3 在数组中出现的次数是5,因此返回5

简单方案一

  • 既然输入的数组是有序的,那么最简单的方式是一次遍历,统计出需要的数字出现的个数,时间复杂度是O(n),实现方法如下:
*** 查询有序数组中数字k 出现的次数** @author liaojiamin* @Date:Created in 16:08 2021/6/24*/
public class GetNumberOfK {public static void main(String[] args) {int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 9, 33, 44, 55, 56, 56, 56, 56, 56, 57};System.out.println(countK(array, 0));}/*** 方法一,遍历统计 O(n)*/public static Integer countK(int[] array, int k) {if (array == null || array.length <= 0) {return -1;}int count = 0;for (int i = 0; i < array.length; i++) {if (array[i] == k) {count++;}}return count;}}

方法二二分查找

  • 有序数组,而且是查询,那么时间效率最高的就是二分查找了,分析流程如下:
    • 如上案例中二分查找找出其中一个3 的位置,标记为position
    • 此时可能前后都还存在3,那么从position向前遍历,查找之前的3,得到firstK
    • 从position向后遍历,查找之后的3,得到lastK
    • 那么k出现的次数n = lastK - firstK + 1
  • 如上分析有如下代码:
/*** 查询有序数组中数字k 出现的次数** @author liaojiamin* @Date:Created in 16:08 2021/6/24*/
public class GetNumberOfK {public static void main(String[] args) {int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 9, 33, 44, 55, 56, 56, 56, 56, 56, 57};System.out.println(binarySearchK(array, 0));}/*** 方法二:二分查找找出k,得到k后,左右遍历k,直到找到,firstK和lastK* O(n)*/public static Integer binarySearchK(int[] array, int k) {Integer positionK = binarySearch(array, 0, array.length - 1, k);if (positionK < 0) {return -1;}Integer firstK = positionK;Integer lastK = positionK;for (int i = positionK; i < array.length; i++) {if (array[i] == k) {lastK = i;}}for (int i = positionK; i >= 0; i--) {if (array[i] == k) {firstK = i;}}return lastK - firstK + 1;}public static Integer binarySearch(int[] array, int left, int right, int k) {if (array == null || left < 0 || right > array.length - 1 || left > right) {return -1;}int middle = (left + right) / 2;if (array[middle] == k) {return middle;}if (array[middle] > k) {return binarySearch(array, left, middle - 1, k);}if (array[middle] < k) {return binarySearch(array, middle + 1, right, k);}return -1;}
}
  • 如上算法因为k出现的次数可能是n次,那么我们向前向后遍历的次数可能就是n, 那么时间复杂度还是O(n),并没有达到优化的目的。此算法中实际主要消耗在如何确定重复数字的第一个k与最后一个k的位置上。

方案三纯二分查找

  • 方案二中既然可以通过二分查找找到其中一个3 ,那么我们是否能通过二分查找找到firstK和lastK

  • 分析如下:

    • 先查找第一个k, 标记位置为position
    • 当地position-1 个位置的值也是k的时候,我们认为k之前还有重复的数字k存在,依然用二分查找继续找 left ~ k-1 位置中的k
    • 持续以上步骤,直到position-1 位置不是k为止,我们得到firstK = position
    • 同理,如果position+1位置也是k,那么我们递归position+1 ~ right的数组中二分查找k,得到lastK
    • 如上我们用纯二分查找的方式找出了lastK,firstK
  • 经如上分析有如下代码:

/*** 查询有序数组中数字k 出现的次数** @author liaojiamin* @Date:Created in 16:08 2021/6/24*/
public class GetNumberOfK {public static void main(String[] args) {int[] array = new int[]{1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 9, 33, 44, 55, 56, 56, 56, 56, 56, 57};System.out.println(binarySearchAllK(array, 0));}/*** 方法三,还是二分查找,分别找出firstK, lastK*/public static Integer binarySearchAllK(int[] array, int k) {if (array == null || array.length <= 0) {return -1;}int firstK = binarySearchFirstK(array, 0, array.length - 1, k);int lastK = binarySearchLastK(array, 0, array.length - 1, k);if (firstK < 0 && lastK < 0) {return -1;}return lastK - firstK + 1;}/*** 二分查找第一个k*/public static Integer binarySearchFirstK(int[] array, int left, int right, int k) {if (array == null || left < 0 || right > array.length - 1 || left > right) {return -1;}int middle = (left + right) / 2;if (array[middle] == k) {if (middle - 1 >= left && array[middle - 1] == k) {return binarySearchFirstK(array, left, middle - 1, k);} else {return middle;}}if (array[middle] < k) {return binarySearchFirstK(array, middle + 1, right, k);}if (array[middle] > k) {return binarySearchFirstK(array, left, middle - 1, k);}return -1;}/*** 二分查找最后一个k*/public static Integer binarySearchLastK(int[] array, int left, int right, int k) {if (array == null || left < 0 || right > array.length - 1 || left > right) {return -1;}int middle = (left + right) / 2;if (array[middle] == k) {if (middle + 1 <= right && array[middle + 1] == k) {return binarySearchLastK(array, middle + 1, right, k);} else {return middle;}}if (array[middle] > k) {return binarySearchLastK(array, left, middle - 1, k);}if (array[middle] < k) {return binarySearchLastK(array, middle + 1, right, k);}return -1;}
}
  • 如上实现中firstK,lastK都是使用二分查找在数组中查找,并且二分查找的总量不会大于整个数组的量n,他们两次查询的时间复杂度都是O(logn),因此总的时间复杂度就是O(logn),达到了我们优化的目的。

上一篇:数据结构与算法–最小的k个数
下一篇:数据结构与算法–二叉树的深度问题

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

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

相关文章

【值得收藏】首次披露Facebook移动端软件的持续部署 | IDCF

&#xff08;图片来源于网络&#xff09;摘要持续部署是指软件更新一旦准备好就立即发布的实践方法&#xff0c;在业界越来越多地被采用。移动端软件的更新频率普遍落后于基于云端的服务&#xff0c;原因有很多。比如&#xff0c;移动端软件只能定期发布版本&#xff1b;用户可…

数据结构与算法--二叉树的深度问题

二叉树的深度 题目&#xff1a;输入一颗二叉树的根&#xff0c;求该树的深度。从根节点到叶子节点一次进过的节点形成的一条路径&#xff0c;最长的路径的长度为树的深度。如下图中二叉树的额深度4&#xff0c;因为从根节点A到叶子节点的路径中有4个节点A B E J 问题中定义了一…

进击谷歌:多线程下程序执行顺序怎么稳定不乱?

点击上方蓝字 关注我们面试官您好&#xff0c;我是来面试的您好&#xff0c;我是这次的面试官&#xff0c;先介绍一下自己把我是女孩&#xff0c;blala ....那问一个多线程的问题吧&#xff0c;在一个多线程的环境中&#xff0c;怎么能保证一系列方法的执行顺序呢&#xff1f;…

[Java基础]Set集合概述和特点

练习代码如下: package test21;import java.util.HashSet; import java.util.Set;public class SetDemo {public static void main(String[] args){Set<String> set new HashSet<String>();set.add("hello");set.add("world");set.add("…

深圳本次核酸检普筛怎么将个人信息和结果对应上??

前言 最近深圳疫情比较严重&#xff0c;好在上午新闻公布本次普筛都是阴性&#xff0c;期间我检查了三次&#xff0c;基本上每周测一次的样子&#xff0c;基本的检测非常快&#xff0c;只是需要筛查的人数太多&#xff0c;因此才有几公里的排队出现&#xff0c;期间也发现了一…

借助Redis完成延时任务

背景 相信我们或多或少的会遇到类似下面这样的需求&#xff1a;第三方给了一批数据给我们处理&#xff0c;我们处理好之后就通知他们处理结果。大概就是下面这个图说的。本来在处理完数据之后&#xff0c;我们就会马上把处理结果返回给对方&#xff0c;但是对方要求我们处理速度…

数据结构与算法--数组中出一次的数字

数组中出现一次的数字 题目&#xff1a;一个整型数组里面除了一个数字以外&#xff0c;其他数字都出现了两次。找出这个出现一次的数字&#xff0c;时间复杂度O(n)&#xff0c;空间复杂度O(1) 如上题中最简单的方法就是一次循环统计&#xff0c;之后在循环判断出值出现一次的数…

[Java基础]HashSet集合概述和特点

HashSet集合概述和特点: 练习代码如下: package HashSetPackage;import java.util.HashSet;public class HashSetDemo {public static void main(String[] args){HashSet<String> hs new HashSet<String>();hs.add("hello");hs.add("world")…

多亏我缓存技术过硬!疫情防控项目上线,我只用了5天!

先介绍下背景&#xff0c;我是武汉某O2O电商公司开发组长&#xff0c;疫情震中的我被老板要求7天之内上线《疫情防控热点图》项目&#xff0c;几个组员回老家断网&#xff0c;最终就2个人完成开发上线&#xff0c;满足了10w用户的高频访问。时间和人力都紧张&#xff0c;不能按…

数据结构与算法--有序数组中找出和为s的两个数字

有序数组中找和为s的两个数字 题目&#xff1a;输入一个递增排序的数组array&#xff0c; 和一个数字s&#xff0c; 在数组中找出两个数&#xff0c;使得这两个数的和是s&#xff0c;如果有多对&#xff0c;输出一对即可。 最简单方案 双循环&#xff0c;每次获取一个数据&a…

ABP框架使用拦截器动态配置租户过滤器

前言最近项目要求在ABP框架中根据TenantId是否为空来配置是否禁用租户过滤器。ABP自身给我我们禁用租户过滤器的两种方法官方文档https://aspnetboilerplate.com/Pages/Documents/Data-Filters方法一&#xff1a;使用工作单元using (_unitOfWorkManager.Current.DisableFilter(…

[Java基础]LinkedHashSet集合概述和特点

练习代码如下: package LinkedHashSetPack;import java.util.LinkedHashSet;public class LinkedHashSetDemo {public static void main(String[] args){LinkedHashSet<String> linkedHashSet new LinkedHashSet<String>();linkedHashSet.add("hello")…

数据结构与算法--翻转单词顺序

翻转单词顺序 题目&#xff1a;输入一个英文句子&#xff0c;翻转句子中的单词顺序&#xff0c;但是单词内的字符顺序不变&#xff0c;例如&#xff1a;I am a software engineer -> engineer software a am I 方案一&#xff1a;空间换时间 空间换时间方法&#xff0c;还…

在.NET Core中用最原生的方式读取Nacos的配置

背景 之前老黄写过一篇《ASP.NET Core结合Nacos来完成配置管理和服务发现》简单介绍了如何让.NET Core程序接入Nacos&#xff0c;之前的SDK里面更多的是对Nacos的Open API进行了封装以及对服务注册和发现的封装。配置这一块当时并没有过多的处理&#xff0c;用起来有时感觉不会…

[Java基础]TreeSet集合概述和特点

练习代码如下: package TreeSetPack;import java.util.TreeSet;public class TreeSetDemo {public static void main(String[] args){TreeSet<Integer> ts new TreeSet<Integer>();ts.add(10);ts.add(40);ts.add(30);ts.add(50);ts.add(20);ts.add(30);for (Inte…

数据结构与算法--判断扑克牌是否顺子

扑克牌的顺子 题目&#xff1a;从扑克牌中随机抽取N张牌&#xff0c;判断是否顺子&#xff0c;即这N张牌是不是连续的。扑克牌中2 ~ 10 为数字&#xff0c;11代表j&#xff0c;12代表k&#xff0c;13代表K&#xff0c;并且大小王可以代表任意数字。 抽象概念 将扑克牌抽象成计…

.NET Core下的开源分布式任务调度系统ScheduleMaster-v2.0低调发布

从1月份首次公开介绍这个项目到现在也快4个月了&#xff0c;期间做了一些修修补补整体没什么大的改动。2.0算是发布之后第一个大的版本更新&#xff0c;带来了许多新功能新特性&#xff0c;也修复了一些已知的bug&#xff0c;在此感谢在博客、Issue和QQ群中提出各种意见的朋友&…

[Java基础]自然排序Comparable的使用

代码如下: package ComparablePack;public class Student implements Comparable<Student>{private String name;private int age;public Student() {}public Student(String name, int age) {this.name name;this.age age;}public String getName() {return name;}pu…

数据结构与算法--我们来玩丢手绢(约瑟夫环问题)

我们来玩丢手绢 昨天我们打扑克&#xff0c;今天我们丢手绢丢手绢我们都知道这个游戏&#xff0c;他的由来由约瑟夫 &#xff08;Josephus&#xff09;提出来的 据说著名犹太历史学家Josephus有过以下的故事&#xff1a;在罗马人占领乔塔帕特后&#xff0c;39 个犹太人与Jose…