这是悦乐书的第294次更新,第312篇原创

01 看题和准备

今天介绍的是LeetCode算法题中Easy级别的第162题(顺位题号是697)。给定一个由正整数组成的非空数组,该数组的度数被定义为任意元素出现次数最多的次数。你的任务是找到一个(连续的)nums子数组的最小可能长度,它与nums具有相同的度数。例如:

输入:[1,2,2,3,1]

输出:2

说明:输入数组的度数为2,因为元素1和2都出现两次。在具有相同程度的子阵列中:[1,2,2,3,1],[1,2,2,3],[2,2,3,1],[1,2,2],[2,2,3],[2,2],最短的长度是2.所以返回2。



输入:[1,2,2,3,1,4,2]

输出:6



注意

  • 数组长度将介于1到50,000之间。

  • 数组中的元素是0到49,999之间的整数。

本次解题使用的开发工具是eclipse,jdk使用的版本是1.8,环境是win7 64位系统,使用Java语言编写和测试。

02 第一种解法

按照题目的意思,我们需要先把出现次数最多的元素找出来,然后再找到该元素第一次出现和最后一次出现的索引位置之间的距离,如果存在多个相同最多次数的元素,还需要比较他们之间的最小值。

因此,第一步,将数组元素存入HashMap,得到最大次数;第二步,将出现最多次数的单个或多个元素添加进数组;第三步,找到新数组中每位元素出现的起始位置,计算距离长度,取其中的较小者。

  1. public int findShortestSubArray(int[] nums) {
  2. if (nums == null || nums.length == 0) {
  3. return 0;
  4. }
  5. Map<Integer,Integer> map = new HashMap<Integer, Integer>();
  6. int degree = 0;
  7. for (int num : nums) {
  8. map.put(num, map.getOrDefault(num, 0)+1);
  9. // 比较出现次数,取其中较大者
  10. degree = Math.max(degree, map.get(num));
  11. }
  12. // 将最多出现次数相同的元素放入新的数组
  13. int[] occur = new int[nums.length];
  14. int index = 0;
  15. for (Integer key : map.keySet()) {
  16. if (map.get(key) == degree) {
  17. occur[index++] = key;
  18. }
  19. }
  20. int min = Integer.MAX_VALUE;
  21. // 遍历新数组,算出出现次数最多的元素在nums中的索引之差
  22. for (int i=0; i< index; i++) {
  23. // 使用双指针,一前一后遍历nums,找到该元素的索引之差
  24. int start = 0, end = nums.length-1;
  25. // 申明一个变量,存储索引之差
  26. int len = Integer.MAX_VALUE;;
  27. while (start <= end) {
  28. if (occur[i] == nums[start] && occur[i] == nums[end]) {
  29. len = end - start +1;
  30. break;
  31. } else if (occur[i] == nums[start] && occur[i] != nums[end]){
  32. end--;
  33. } else if(occur[i] != nums[start] && occur[i] == nums[end]) {
  34. start++;
  35. } else {
  36. end--;
  37. start++;
  38. }
  39. }
  40. // 取两者之间的最小值
  41. min = Math.min(min, len);
  42. }
  43. return min;
  44. }

03 第二种解法

我们也可以不使用新数组来存那些出现最多的元素,将HashMap的value类型改为数组即可。依旧使用数组中的元素作为key,value变成了一个包含三个元素的数组,存储次数、首次出现索引、最后一次出现索引,依旧是在第一次循环中就得到degree的值,然后遍历HashMap的value,找到元素索引间隔最小的那个。

  1. public int findShortestSubArray2(int[] nums) {
  2. if (nums == null || nums.length == 0) {
  3. return 0;
  4. }
  5. int degree = 0;
  6. // 以nums中的元素为key,以一个含有3个元素的数组为value
  7. // 该数组第一个元素为当前元素出现的次数,第二个元素为其第一次出现的位置,第三个元素为其最后一次出现的位置
  8. Map<Integer,int[]> map = new HashMap<Integer, int[]>();
  9. for (int i=0; i<nums.length; i++) {
  10. if (map.containsKey(nums[i])) {
  11. int[] temp = map.get(nums[i]);
  12. // 更新该元素出现次数
  13. temp[0]++;
  14. // 更新该元素最后一次出现的位置(索引)
  15. temp[2] = i;
  16. } else {
  17. map.put(nums[i], new int[]{1, i, i});
  18. }
  19. // 更新degree,取两者之间较大值
  20. degree = Math.max(degree, map.get(nums[i])[0]);
  21. }
  22. int min = Integer.MAX_VALUE;
  23. for (int[] values : map.values()) {
  24. if (values[0] == degree) {
  25. min = Math.min(min, values[2] - values[1] + 1);
  26. }
  27. }
  28. return min;
  29. }

04 第三种解法

对于第二种解法,我们可以再简化下,只使用一个循环来处理。

  1. public int findShortestSubArray3(int[] nums) {
  2. if (nums == null || nums.length == 0) {
  3. return 0;
  4. }
  5. int degree = 0;
  6. int min = Integer.MAX_VALUE;
  7. // 以nums中的元素为key,以一个含有2个元素的数组为value
  8. // 该数组第一个元素为当前元素出现的次数,第二个元素为其最后一次出现的位置
  9. Map<Integer,int[]> map = new HashMap<Integer, int[]>();
  10. for (int i=0; i<nums.length; i++) {
  11. if (!map.containsKey(nums[i])) {
  12. map.put(nums[i], new int[]{0, i});
  13. }
  14. // 出现次数累加
  15. map.get(nums[i])[0]++;
  16. // 对degree进行处理
  17. if (degree < map.get(nums[i])[0]) {
  18. degree = map.get(nums[i])[0];
  19. min = i - map.get(nums[i])[1] + 1;
  20. } else if (degree == map.get(nums[i])[0]) {
  21. min = Math.min(min, i - map.get(nums[i])[1] + 1);
  22. }
  23. }
  24. return min;
  25. }

05 第四种解法

我们也可以使用两个HashMap,而不使用数组。第一个HashMap的value存每个元素出现的次数,第二个HashMap的value存每个元素出现的初始位置索引。

在循环中,每次去比较第一个HashMap的value,如果比degree大,就更新degree的值,同时算出该元素起始索引和结束索引之间的距离;如果和degree相等,就在两者之间取较小值。

  1. public int findShortestSubArray4(int[] nums) {
  2. if (nums == null || nums.length == 0) {
  3. return 0;
  4. }
  5. int degree = 0;
  6. int min = Integer.MAX_VALUE;
  7. Map<Integer, Integer> map = new HashMap<Integer, Integer>();
  8. Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
  9. for (int i=0; i<nums.length; i++) {
  10. map.put(nums[i], map.getOrDefault(nums[i], 0)+1);
  11. if (!map2.containsKey(nums[i])) {
  12. map2.put(nums[i], i);
  13. }
  14. if (degree < map.get(nums[i])) {
  15. degree = map.get(nums[i]);
  16. min = i - map2.get(nums[i]) + 1;
  17. } else if (degree == map.get(nums[i])) {
  18. min = Math.min(min, i - map2.get(nums[i]) + 1);
  19. }
  20. }
  21. return min;
  22. }

06 小结

算法专题目前已日更超过四个月,算法题文章162+篇,公众号对话框回复【数据结构与算法】、【算法】、【数据结构】中的任一关键词,获取系列文章合集。

以上就是全部内容,如果大家有什么好的解法思路、建议或者其他问题,可以下方留言交流,点赞、留言、转发就是对我最大的回报和支持!

LeetCode算法题-Degree of an Array(Java实现)的更多相关文章

  1. LeetCode算法题-Subdomain Visit Count(Java实现)

    这是悦乐书的第320次更新,第341篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第189题(顺位题号是811).像"discuss.leetcode.com& ...

  2. LeetCode算法题-Letter Case Permutation(Java实现)

    这是悦乐书的第315次更新,第336篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第184题(顺位题号是784).给定一个字符串S,将每个字母单独转换为小写或大写以创建另 ...

  3. LeetCode算法题-Jewels and Stones(Java实现)

    这是悦乐书的第313次更新,第334篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第182题(顺位题号是771).字符串J代表珠宝,S代表你拥有的石头.S中的每个字符都是 ...

  4. LeetCode算法题-Reach a Number(Java实现)

    这是悦乐书的第310次更新,第331篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第179题(顺位题号是754).你站在无限数字线的0号位置.在目的地有个target.在 ...

  5. LeetCode算法题-Shortest Completing Word(Java实现)

    这是悦乐书的第309次更新,第330篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第178题(顺位题号是748).从给定的字典单词中查找最小长度单词,其中包含字符串lic ...

  6. LeetCode算法题-Self Dividing Numbers(Java实现)

    这是悦乐书的第305次更新,第324篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第173题(顺位题号是728).自分割数是一个可被其包含的每个数字整除的数字.例如,12 ...

  7. LeetCode算法题-Find Pivot Index(Java实现)

    这是悦乐书的第304次更新,第323篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第172题(顺位题号是724).给定一个整数nums数组,编写一个返回此数组的" ...

  8. LeetCode算法题-To Lower Case(Java实现)

    这是悦乐书的第301次更新,第320篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第169题(顺位题号是709).实现具有字符串参数str的函数ToLowerCase() ...

  9. LeetCode算法题-Count Binary Substrings(Java实现)

    这是悦乐书的第293次更新,第311篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第161题(顺位题号是696).给定一个字符串s,计算具有相同数字0和1的非空且连续子串 ...

随机推荐

  1. ASP.NET Core 2.0 MVC项目实战

    一.前言 毕业后入职现在的公司快有一个月了,公司主要的产品用的是C/S架构,再加上自己现在还在学习维护很老的delphi项目,还是有很多不情愿的.之前实习时主要是做.NET的B/S架构的项目,主要还是 ...

  2. php的四个fetch语句

    先给一个表 man: |---------------| |-name--|-age--| |--AA---|--aa---| |--BB---|--bb---| |--CC---|--cc---| ...

  3. Java生成全局唯一ID代码演示

    看了GitHub上的两个生成唯一ID的算法程序(一个出自百度,一个出自美团),打算运行着试试看,至于原理什么的文档上讲得很详细了,此处不再一一粘贴了,此处只演示代码 https://github.co ...

  4. .NET代码树执行时间计时器

    有很多时候我们需要对代码不同段计算一个执行时间,并希望通过节点树的方式表达现每段代码的执行时长.在.Net下似乎找不到这样一个功能类,所以花了一些时间实现这样一个代码运行计时器.首先看一下简单的需求. ...

  5. Spring Boot分布式系统实践【1】-架构设计

    前言 [第一次尝试去写一个系列,肯定会有想不到的地方,欢迎大家留言指正] 本系列将介绍如果从零构建一套分布式系统.同时也是对自己过去工作的一个梳理过程. 本文先整理出构建系统的主要技术选型,以及技术框 ...

  6. Netty源码分析(四):EventLoopGroup

    无论服务端或客户端启动时都用到了NioEventLoopGroup,从名字就可以看出来它是NioEventLoop的组合,是Netty多线程的基石. 类结构 NioEventLoopGroup继承自M ...

  7. Refit在ASP.NET Core中的实践

    前言 声名式服务调用,己经不算是一个新鲜的话题了,毕竟都出来好些年了. 下面谈谈,最近项目中用到一个这样的组件的简单实践. 目前部分项目用到的是Refit这个组件,都是配合HttpClientFact ...

  8. BUG心得

    在<程序员,你会从 Bug 中学习么?>一文中,我写了我是怎样追踪这些年遇到的最有趣 bug 的.最近我重新浏览了这所有的 194 个条目(历时 13 年),看看我从这些 bug 中学到了 ...

  9. MySQL 8.0版本连接报错:Could not create connection to database server.

    准备搭建一个Spring Boot 组合mybatis的项目,数据库采用的是MySQL 8.0.11按照以往的配置,使用插件mybatis-generator-maven-plugin生成代码时,一直 ...

  10. IOC,DIP,DI,IoC容器

    定义 IOC(Inversion of Control  控制反转),DIP(Dependency Inverson Principle 依懒倒置)都属于设计程序时指导原则,并没有具体的实现.比较常用 ...