这是悦乐书的第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,得到最大次数;第二步,将出现最多次数的单个或多个元素添加进数组;第三步,找到新数组中每位元素出现的起始位置,计算距离长度,取其中的较小者。

public int findShortestSubArray(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
Map<Integer,Integer> map = new HashMap<Integer, Integer>();
int degree = 0;
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0)+1);
// 比较出现次数,取其中较大者
degree = Math.max(degree, map.get(num));
}
// 将最多出现次数相同的元素放入新的数组
int[] occur = new int[nums.length];
int index = 0;
for (Integer key : map.keySet()) {
if (map.get(key) == degree) {
occur[index++] = key;
}
}
int min = Integer.MAX_VALUE;
// 遍历新数组,算出出现次数最多的元素在nums中的索引之差
for (int i=0; i< index; i++) {
// 使用双指针,一前一后遍历nums,找到该元素的索引之差
int start = 0, end = nums.length-1;
// 申明一个变量,存储索引之差
int len = Integer.MAX_VALUE;;
while (start <= end) {
if (occur[i] == nums[start] && occur[i] == nums[end]) {
len = end - start +1;
break;
} else if (occur[i] == nums[start] && occur[i] != nums[end]){
end--;
} else if(occur[i] != nums[start] && occur[i] == nums[end]) {
start++;
} else {
end--;
start++;
}
}
// 取两者之间的最小值
min = Math.min(min, len);
}
return min;
}

03 第二种解法

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

public int findShortestSubArray2(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int degree = 0;
// 以nums中的元素为key,以一个含有3个元素的数组为value
// 该数组第一个元素为当前元素出现的次数,第二个元素为其第一次出现的位置,第三个元素为其最后一次出现的位置
Map<Integer,int[]> map = new HashMap<Integer, int[]>();
for (int i=0; i<nums.length; i++) {
if (map.containsKey(nums[i])) {
int[] temp = map.get(nums[i]);
// 更新该元素出现次数
temp[0]++;
// 更新该元素最后一次出现的位置(索引)
temp[2] = i;
} else {
map.put(nums[i], new int[]{1, i, i});
}
// 更新degree,取两者之间较大值
degree = Math.max(degree, map.get(nums[i])[0]);
}
int min = Integer.MAX_VALUE;
for (int[] values : map.values()) {
if (values[0] == degree) {
min = Math.min(min, values[2] - values[1] + 1);
}
}
return min;
}

04 第三种解法

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

public int findShortestSubArray3(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int degree = 0;
int min = Integer.MAX_VALUE;
// 以nums中的元素为key,以一个含有2个元素的数组为value
// 该数组第一个元素为当前元素出现的次数,第二个元素为其最后一次出现的位置
Map<Integer,int[]> map = new HashMap<Integer, int[]>();
for (int i=0; i<nums.length; i++) {
if (!map.containsKey(nums[i])) {
map.put(nums[i], new int[]{0, i});
}
// 出现次数累加
map.get(nums[i])[0]++;
// 对degree进行处理
if (degree < map.get(nums[i])[0]) {
degree = map.get(nums[i])[0];
min = i - map.get(nums[i])[1] + 1;
} else if (degree == map.get(nums[i])[0]) {
min = Math.min(min, i - map.get(nums[i])[1] + 1);
}
}
return min;
}

05 第四种解法

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

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

public int findShortestSubArray4(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int degree = 0;
int min = Integer.MAX_VALUE;
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();
for (int i=0; i<nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i], 0)+1);
if (!map2.containsKey(nums[i])) {
map2.put(nums[i], i);
}
if (degree < map.get(nums[i])) {
degree = map.get(nums[i]);
min = i - map2.get(nums[i]) + 1;
} else if (degree == map.get(nums[i])) {
min = Math.min(min, i - map2.get(nums[i]) + 1);
}
}
return min;
}

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. python 菱形继承问题究极版

    如果只是正常的菱形继承,经典类(python2中最后一个父类不继承object类)是深度优先,即会从左边父类开始一路走到底 新式类(最后一个父类继承了object类)是广度优先,即从左边父类开始继承, ...

  2. WebView 讲义

    http://reezy.me/p/20170515/android-webview/  (比较全面) 参考 https://developer.android.com/reference/andro ...

  3. springBoot(12)---整合Swagger2

    Spingboot整合Swagger2 随着互联网技术的发展,一般开发都是前后端分离,那么前端和后端的唯一联系,变成了API接口:API文档变成了前后端开发人员联系的纽带,变得越来越重要,没有API ...

  4. 对vue源码的初步认识和理解

    根据vue的官网介绍,可以得知vue是一个mvvm框架,且是响应式的.为了更深入了理解其内涵,本人以及理解实现了一个简单的mvvm学习的demo.下面分享给大家,欢迎大家一起讨论. 一.mvvm至少包 ...

  5. 微信小程序使用nginx方向代理实现内嵌非业务域名

    通过上一篇文章简单介绍了一下微信小程序的新组件<web-view>,实现了在小程序中内嵌业务域名的功能.但是boss要的小程序中不仅想内嵌业务域名,还想要打开一些非业务域名(无法操作web ...

  6. RabbitMQ学习笔记(一) Hello World

    RabbitMQ是做什么的? RabbitMQ可以类比现实生活中的邮政服务. 现实中邮件服务处理的是邮件,发件人写好信件投入邮箱,邮递员收取信件存入邮局,邮局根据信件地址,分配邮递员投递信件到指定地点 ...

  7. Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)

    剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...

  8. [转载] Relearning to Learn - 学会学习

    学会学习 说明: 本文是在阅读了下述博客后, 所作的梳理与总结, 原文链接是: 学会学习 阅读和理解是不够的, 你还需要记住你学的内容. 可通过把知识讲给不懂的人听, 抓住细节, 讲清讲透, 从而加深 ...

  9. 【Vue笔记】-- 详解vue生命周期

    针对于Vue的生命周期进行详细的说明,方面加深对各个方法的引用. 引言: 前几天重新回顾vue官网时,看到vue的生命周期,想着自己用vue开发了快一年了,就总结总结vue知识,再次加深自己对vue的 ...

  10. SpringBoot入门教程(九)定时任务Schedule

    在日常项目运行中,我们总会有需求在某一时间段周期性的执行某个动作.比如每天在某个时间段导出报表,或者每隔多久统计一次现在在线的用户量.在springboot中可以有很多方案去帮我们完成定时器的工作,有 ...