您的位置:首页 > 大数据 > 人工智能

每日一恋 - LeetCode 217 & 219 & 220 . Contains Duplicate(存在重复元素)

2018-08-10 20:11 267 查看

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)

如果文章里有说得不对的地方请前辈多多指正~ 希望与君共勉~

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: