LeetCode OJ 220.Contains Duplicate 3
2016-04-11 15:48
507 查看
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the difference between nums[i] and nums[j] is at most t and the difference between i and j is at most k.
这个问题在前一个问题的基础上又对nums[i],nums[j]的关系作了约束,要求|nums[i]-nums[j]|<=t && |i-j|<=k;
对于这个问题,在前面代码的基础上,一个很自然的做法是:
这是一个两层的循环,对于每一个nums[i],把它与Map中包含的其他所有元素进行比较,检查是否有满足条件的元素。这个方法很容易理解,但是时间复杂度太高,如果k很大的话,内层循环的迭代次数会很多。导致Time Limit Exceeded。
如何才能对该算法进行改进呢?在参考了别人的代码后,发现了一个很机智的解法,它的时间复杂度是O(n),先把代码贴出来如下:
接下来我们对该算法进行分析。首先我们来看下getID函数的功能。
i>=0时,ID是i/w。举个例子,假设t=2,则w=3。如果nums[] = {0,1,2,3,4,5,6,7}。
nums[0]/w = 0/3 = 0;
nums[1]/w = 1/3 = 0;
nums[2]/w = 2/3 = 0;
nums[3]/w = 3/3 = 1;
nums[4]/w = 4/3 = 1;
nums[5]/w = 5/3 = 1;
nums[6]/w = 6/3 = 2;
这样就把nums[i]按照值的不同划分到了不同的组中。如果存在两个数|nums[i]-nums[j]|<=t,那么这两个数的ID或者相同,或者至多相差1。
同样i<0时,ID是(i+1)/w - 1。同样假设w=3,nums[]={-6,-5,-4,-3,-2,-1}。
nums[0]/w = (-6+1)/3 -1 = -3;
nums[1]/w = (-5+1)/3 -1 = -3;
nums[2]/w = (-4+1)/3 -1 = -2;
nums[3]/w = (-3+1)/3 -1 = -2;
nums[4]/w = (-2+1)/3 -1 = -2;
nums[5]/w = (-1+1)/3 -1 = -1;
这样就把nums[i]按照值的不同划分到了不同的组中。如果存在两个数|nums[i]-nums[j]|<=t,那么这两个数的ID或者相同,或者至多相差1。
可以发现,这两个划分是连续的。ID=···-n,···,-1,0,1,···,n···。
那么对于每一个nums[i],先计算它的ID,然后在Map中判断是否包含此ID,如果包含,那么肯定存在这样的两个数,他们之间的差小于等于t。否则的话判断是否存在与此ID相差为1的ID,即ID-1,ID+1。如果存在的话,判断两个数之间的差是否小于w(即小于等于t)。对于其他的ID,其实是没有必要来判断的。可以看到,提前计算ID的过程使得对于每一个nums[i],不需要像上一个算法中对Map中的每个数进行比较,而最多只需要进行三次比较即可判断出是否有满足条件的元素。
这个问题在前一个问题的基础上又对nums[i],nums[j]的关系作了约束,要求|nums[i]-nums[j]|<=t && |i-j|<=k;
对于这个问题,在前面代码的基础上,一个很自然的做法是:
public class Solution { public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { Map<Integer,Integer> map = new HashMap<>(0); for(int i=0; i<nums.length; i++){ for(int num : map.keySet()){ if(Math.abs(num-nums[i])<t && i-map.get(num)<k) return true; } map.put(nums[i],i); if(map.size()>k) map.remove(nums[i-k]); } return false; } }
这是一个两层的循环,对于每一个nums[i],把它与Map中包含的其他所有元素进行比较,检查是否有满足条件的元素。这个方法很容易理解,但是时间复杂度太高,如果k很大的话,内层循环的迭代次数会很多。导致Time Limit Exceeded。
如何才能对该算法进行改进呢?在参考了别人的代码后,发现了一个很机智的解法,它的时间复杂度是O(n),先把代码贴出来如下:
public class Solution { public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { if (t < 0) return false; Map<Long, Long> d = new HashMap<>(); long w = (long)t + 1; for (int i = 0; i < nums.length; ++i) { long m = getID(nums[i], w); if (d.containsKey(m)) return true; if (d.containsKey(m - 1) && Math.abs(nums[i] - d.get(m - 1)) < w) return true; if (d.containsKey(m + 1) && Math.abs(nums[i] - d.get(m + 1)) < w) return true; d.put(m, (long)nums[i]); if (i >= k) d.remove(getID(nums[i - k], w)); } return false; } private long getID(long i, long w) { return i < 0 ? (i + 1) / w - 1 : i / w; } }
接下来我们对该算法进行分析。首先我们来看下getID函数的功能。
i>=0时,ID是i/w。举个例子,假设t=2,则w=3。如果nums[] = {0,1,2,3,4,5,6,7}。
nums[0]/w = 0/3 = 0;
nums[1]/w = 1/3 = 0;
nums[2]/w = 2/3 = 0;
nums[3]/w = 3/3 = 1;
nums[4]/w = 4/3 = 1;
nums[5]/w = 5/3 = 1;
nums[6]/w = 6/3 = 2;
这样就把nums[i]按照值的不同划分到了不同的组中。如果存在两个数|nums[i]-nums[j]|<=t,那么这两个数的ID或者相同,或者至多相差1。
同样i<0时,ID是(i+1)/w - 1。同样假设w=3,nums[]={-6,-5,-4,-3,-2,-1}。
nums[0]/w = (-6+1)/3 -1 = -3;
nums[1]/w = (-5+1)/3 -1 = -3;
nums[2]/w = (-4+1)/3 -1 = -2;
nums[3]/w = (-3+1)/3 -1 = -2;
nums[4]/w = (-2+1)/3 -1 = -2;
nums[5]/w = (-1+1)/3 -1 = -1;
这样就把nums[i]按照值的不同划分到了不同的组中。如果存在两个数|nums[i]-nums[j]|<=t,那么这两个数的ID或者相同,或者至多相差1。
可以发现,这两个划分是连续的。ID=···-n,···,-1,0,1,···,n···。
那么对于每一个nums[i],先计算它的ID,然后在Map中判断是否包含此ID,如果包含,那么肯定存在这样的两个数,他们之间的差小于等于t。否则的话判断是否存在与此ID相差为1的ID,即ID-1,ID+1。如果存在的话,判断两个数之间的差是否小于w(即小于等于t)。对于其他的ID,其实是没有必要来判断的。可以看到,提前计算ID的过程使得对于每一个nums[i],不需要像上一个算法中对Map中的每个数进行比较,而最多只需要进行三次比较即可判断出是否有满足条件的元素。
相关文章推荐
- 219. Contains Duplicate II
- 【poj 1691】Painting A Board
- 开发错误记录5:Failed to resolve: com
- 调用 webservice 出现:WSDLReader:Loading of the WSDL file failed HRESULT=0×80040154: 没有注册类别 解决方案
- open(\"/dev/graphics/fb0\") failed!
- 自定义View时,用到Paint Canvas的一些温故,讲讲用路径绘画实现动画效果(基础篇 三)
- 自定义View时,用到Paint Canvas的一些温故,讲讲用路径绘画实现动画效果(基础篇 三)
- 配置Mailgraph_ext,使用Extman的图形日志
- LeetCode OJ 219.Contains Duplicate 2
- https请求 CFNetwork SSLHandshake failed (-9807) A connection failure occurred: SSL problem
- LeetCode OJ 217.Contains Duplicate
- Failed reading log event, reconnecting to retry
- Markov Chain(bate)
- 关于 Gradle failed: already disposed module 的问题
- maertSataDmorfnaideMdniF.295
- ZOJ 3780 Paint the Grid Again-贪心模拟/拓扑排序
- AIDL
- 下一代机器学习-在浏览器中训练深度学习模型Next Generation Machine Learning - Training Deep Learning Models in a Browser
- trail particle制作血管
- leetcode 11 Container With Most Water