每日一恋 - LeetCode 217 & 219 & 220 . Contains Duplicate(存在重复元素)
LeetCode 217 题目描述:
给定一个整数数组,判断是否存在重复元素。
如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。
示例 1:
输入: [1,2,3,1] 输出: true
示例 2:
输入: [1,2,3,4] 输出: false
示例 3:
输入: [1,1,1,3,3,4,3,2,4,2] 输出: true
解题:
根据题目意思,使用查找表就可以解决,如果待查数字在查找表中不存在,就加入到查找表中,如果存在,则直接返回true;若遍历完成之后,还没有找到则返回false。
public boolean containsDuplicate(int[] nums) { if (nums == null || nums.length <= 1) return false; HashSet<Integer> set = new HashSet<Integer>(); for ( int i = 0 ; i < nums.length ; i ++ ) { if (set.contains(nums[i])) return true; set.add(nums[i]); } return false; }
另外有一点需要指出的是,这里使用 long 整数类型,是因为 int 类型在
nums[i] + t时可能会出现整形越界。
时间复杂度: O(n)O(n)
空间复杂度: O(n)O(n)
LeetCode 219 题目描述:
给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的绝对值最大为 k。
示例 1:
输入: nums = [1,2,3,1], k = 3 输出: true
示例 2:
输入: nums = [1,0,1,1], k = 1 输出: true
示例 3:
输入: nums = [1,2,3,1,2,3], k = 2 输出: false
解题:
根据题目意思,可能会想到使用暴力解法 O(n2)O(n2) ,枚举 ii 和 jj,对于每一个 nums[i] == nums[j] 数据对,再检查 ii 和 jj 的差是不是不超过 kk。
但是仔细一想,题目告诉我们了 ii 和 jj 的差的绝对值最大为 kk,很明显就是滑动窗口的思路,配合查找表来解决。滑动窗口的最大大小是 kk,假设左区间为 ll ,那么右区间是 l+kl+k。在右移的过程中,我们只要在这个区间里寻找有没有两个相同的数字,如果有就返回true;如果没有则将待测元素加入集合中。
如果某次遍历发现集合的大小已经到达了 k+1k+1,说明活动窗口的左边界需要向右移动。
public boolean containsNearbyDuplicate(int[] nums, int k) { if (nums == null || nums.length <= 1) return false; if (k <= 0) return false; HashSet<Integer> set = new HashSet<Integer>(); for ( int r = 0 ; r < nums.length ; r ++ ) { if (set.contains(nums[r])) return true; set.add(nums[r]); if (set.size() == k + 1) set.remove(nums[r-k]); } return false; }
另外有一点需要指出的是,这里使用 long 整数类型,是因为 int 类型在
nums[i] + t时可能会出现整形越界。
时间复杂度: O(n)O(n)
空间复杂度: O(k)O(k)
LeetCode 220 题目描述:
给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。
示例 1:
输入: nums = [1,2,3,1], k = 3, t = 0 输出: true
示例 2:
输入: nums = [1,0,1,1], k = 1, t = 2 输出: true
示例 3:
输入: nums = [1,5,9,1,5,9], k = 2, t = 3 输出: false
解题:
TreeSet(Java)数据结构使用红黑树实现,是平衡二叉树的一种。
该数据结构支持如下操作:
floor()方法返set中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null。
ceiling()方法返回set中大于等于给定元素的最小元素;如果不存在这样的元素,则返回 null。
根据题目要求,很明显要使用滑动窗口和查找表来解决。滑动窗口的最大大小是 k,其中两个元素的最大差值为 t。那么LeetCode 197题的基础上,将判断窗口是否包含该元素的 if 判断修改为:寻找区间内存在差值最大不超过 t 的元素,如果找到则返回 true;如果没找到则向查找表中添加该元素,然后维护滑动窗口的大小。
其中寻找差值在某一个范围内这一操作,使用一个有序的TreeSet数据结构会更加适合,它支持 ceiling 和 floor 两个操作,
set.ceiling((long)nums[i] - (long)t)表示查找大于等于
(long)nums[i] - (long)t的最小的元素,这个元素小于等于
(long)nums[i] + (long)t)的话,就是题目中两个数的差的绝对值最大值为 t 这样的情况。
大家可以假设当前元素
nums[i]为 5,t 为 3,如果集合中元素是{1, 9, 10},那么
set.ceiling((long)nums[i] - (long)t)找到的就是 9,大于了
(long)nums[i] + (long)t),说明没有找到。如果集合中元素是{1, 3, 9}或者{1, 6, 9},就会相应的找到 3 或者 6,满足小于等
(long)nums[i] + (long)t)这个条件,说明是符合题意的。
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { TreeSet<Long> set = new TreeSet<Long>(); for ( int i = 0 ; i < nums.length ; i ++ ) { if (set.ceiling((long) nums[i] - (long)t) != null && set.ceiling((long)nums[i] - (long)t) <= (long)nums[i] + (long)t) // 整形越界 return true; set.add((long)nums[i]); if (set.size() == k + 1) { set.remove((long) nums[i - k]); } } return false; }
另外有一点需要指出的是,这里使用 long 整数类型,是因为 int 类型在
nums[i] + t时可能会出现整形越界。
时间复杂度: O(nlogk)O(nlogk)
空间复杂度: O(k)O(k)
如果文章里有说得不对的地方请前辈多多指正~ 希望与君共勉~
阅读更多- 每日一恋 - LeetCode 82 & 83. Remove Duplicates from Sorted List(删除排序链表中的重复元素)
- leetcode 287. Find the Duplicate Number 数组重复元素查询 + 环的存在判定 + 快慢指针 + 很妙的想法
- 【LeetCode-面试算法经典-Java实现】【219-Contains Duplicate II(包含重复元素II)】
- leetcode 217|219|220 contains duplicate 1|2|3
- leetcode解题之219 # Contains Duplicate II Java版 (数组中出现重复元素)
- leetcode 220. 存在重复元素 III
- 【LeetCode-面试算法经典-Java实现】【217-Contains Duplicate(包含重复元素)】
- leetcode 217.存在重复元素
- LeetCode - 217/219/220 - Contains Duplicate
- LeetCode-存在重复元素
- 存在重复元素 - LeetCode
- 存在重复元素 II - LeetCode
- 每日一题之LeetCode移除元素 删除有序数组重复元素
- Leetcode 80. Remove Duplicates from Sorted Array II(从已排序数组中移除重复元素)
- leetcode 217 Contains Duplicate 数组中是否有重复的数字
- c++面试题:判断数组是否存在重复元素
- 对集合的存在的元素(存在重复的元素)进行字典排序
- 判断一个int数组中的元素是否存在重复
- 每天一道LeetCode-----有序数组循环右移n位后,寻找最小值,数组中可能包含重复元素
- LeetCode Single Number (找不不重复元素)