力扣面试150题-- 存在重复元素 II和最长连续序列
Day 26
题目描述
思路
- 定义一个map用来存放每个元素以及它对应的序号
- 从前向后遍历数组
- 如果该元素存在于map(说明满足了重复元素的条件),用当前元素的序号值减去map中存放的序号值(因为是从前遍历的所以当前元素序号一定大于存放的序号)。
- 满足条件就返回true。
- 不满足条件,就将当前的元素序号替换近map(因为如果后面出现这个元素的重复值,与当前元素的序号值相减比更前面的元素相减更小)。
- 不存在,就将该元素的值放入map中。
- 循环结束,说明没有满足条件的,返回false。
class Solution {public boolean containsNearbyDuplicate(int[] nums, int k) {Map<Integer,Integer>map=new HashMap<>();int j=0;for(int i=0;i<nums.length;i++){if(map.containsKey(nums[i])){j=map.get(nums[i]);if(i-j<=k){return true;}else{map.put(nums[i],i);}}else{map.put(nums[i],i);}}return false;}
}
题目描述
思路
初次思路:考虑到样例中,重复元素只计数一次,于是采取set来存储,思路如下:
- 定义一个TreeSet(原因在于TreeSet可以对于存放元素按值的大小排序)
- 遍历数组,将元素插入到TreeSet
- 遍历TreeSet,取出元素i
- 如果i-1不存在于集合,i+1存在于集合,说明该元素就是起始元素,设置长度sum=1
- 如果i-1存在于集合,i+1也存在于集合,说明这个元素在一段连续区间中,sum++
- 如果i-1存在集合,i+1不存在于集合,说明这是一段连续区间的结尾,sum++进入判断(注:由于TreeSet是按数值大小存放的,所以当找到一个开头和一个结尾,中间所有的元素都是连续的)
- 如果sum>max,就让max等于sum
- 循环结束,返回max
class Solution {public int longestConsecutive(int[] nums) {if(nums.length==0){return 0;}int max=1,sum=0;Set<Integer> map=new TreeSet<>();for(int i=0;i<nums.length;i++){map.add(nums[i]);}for(Integer i:map){if(map.contains(i+1)&&!map.contains(i-1)){//起始点sum=1;}else if(map.contains(i+1)&&map.contains(i-1)){//区间sum++;}else if(map.contains(i-1)&&!map.contains(i+1)){//结束点sum++;if(sum>max){max=sum;}}}return max;}
}
进阶思路:以上做法,虽然通过,但是我的时间复杂度很高,我感觉原因在于TreeSet的插入和遍历效率太低了,看过官方题解后,有以下做法。
- 使用Hashset存放数组元素(去重)
- 遍历HashSet,判断该节点i是否为头节点(及i-1是否存在于hashset)
- 不存在,说明为头节点,循环向后遍历x,直到找到不存在x+1的元素,sum同时增加
- 比较sum和max,将较大的值存放到max
- 如果该节点不是头节点,就不处理
- 最后返回max
class Solution {public int longestConsecutive(int[] nums) {Set<Integer> set = new HashSet<Integer>();for (int num : nums) {set.add(num);}int maxs = 0;for (int num : set) {if (!set.contains(num - 1)) {int tou = num;int len = 1;while (set.contains(tou + 1)) {tou ++;len ++;}maxs = Math.max(maxs, len);}}return maxs;}
}