这是悦乐书的第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内置函数(44)——next

    英文文档: next(iterator[, default]) Retrieve the next item from the iterator by calling its __next__() m ...

  2. 死磕 java集合之TreeMap源码分析(二)- 内含红黑树分析全过程

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 插入元素 插入元素,如果元素在树中存在,则替换value:如果元素不存在,则插入到对应的位置, ...

  3. 【朝花夕拾】Handler篇

    如果您的app中没有使用过Handler,那您一定是写了个假app:如果您笔试题中没有遇到Handler相关的题目,那您可能做了份假笔试题:如果您面试中没被技术官问到Handler的问题,那您也许碰到 ...

  4. HashMap扩容全过程

      1.如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办? 默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如Arr ...

  5. ASP.NET页面之间的几种传值方法

    首先是QueryString方法传值: QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中.如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法 ...

  6. 前端笔记之HTML5&CSS3(上)新特性&音频视频&本地存储&自定义属性

    一.HTML5简介 HTML 5 的第一份正式草案已于2008年1月22日公布.HTML5 仍处于完善之中.然而,大部分现代浏览器已经具备了某些 HTML5 支持. 2014年10月29日,万维网联盟 ...

  7. Jenkins自定义主题

    x下载自定义样式 http://afonsof.com/jenkins-material-theme/ 打开连接 最后点击:DOWNLOAD TOUR THEME! 得到样式文件:jenkins-ma ...

  8. ReentrantLock学习

    对于并发工作,你需要某种方式来防止两个任务访问相同的资源,至少在关键阶段不能出现这种冲突情况.防止这种冲突的方法就是当资源被一个任务使用时,在其上加锁.在前面的文章--synchronized学习中, ...

  9. SLAM入门之视觉里程计(1):特征点的匹配

    SLAM 主要分为两个部分:前端和后端,前端也就是视觉里程计(VO),它根据相邻图像的信息粗略的估计出相机的运动,给后端提供较好的初始值.VO的实现方法可以根据是否需要提取特征分为两类:基于特征点的方 ...

  10. YYModel底层解析- Runtime

    这段时间一直在忙新的需求,没有时间来整理代码,发表自己技术博客,今天我们来看一下YYModel的底层解析以及如何使用,希望对大家有所帮助! 一 概述 概括 YYModel是一个轻量级的JSON模型转换 ...