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;

对于这个问题,在前面代码的基础上,一个很自然的做法是:

 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中的每个数进行比较,而最多只需要进行三次比较即可判断出是否有满足条件的元素。

LeetCode OJ 220.Contains Duplicate 3的更多相关文章

  1. LeetCode OJ 219.Contains Duplicate 2

    Given an array of integers and an integer k, find out whether there are two distinct indices i and j ...

  2. LeetCode OJ 217.Contains Duplicate

    Given an array of integers, find if the array contains any duplicates. Your function should return t ...

  3. 【LeetCode】220. Contains Duplicate III

    题目: Given an array of integers, find out whether there are two distinct indices i and j in the array ...

  4. LeetCode OJ:Contains Duplicate III(是否包含重复)

    Given an array of integers, find out whether there are two distinct indices i and j in the array suc ...

  5. LeetCode OJ:Contains Duplicate(是否包含重复)

    Given an array of integers, find if the array contains any duplicates. Your function should return t ...

  6. LeetCode OJ 题解

    博客搬至blog.csgrandeur.com,cnblogs不再更新. 新的题解会更新在新博客:http://blog.csgrandeur.com/2014/01/15/LeetCode-OJ-S ...

  7. 【LeetCode OJ】Interleaving String

    Problem Link: http://oj.leetcode.com/problems/interleaving-string/ Given s1, s2, s3, find whether s3 ...

  8. 【LeetCode OJ】Reverse Words in a String

    Problem link: http://oj.leetcode.com/problems/reverse-words-in-a-string/ Given an input string, reve ...

  9. LeetCode OJ学习

    一直没有系统地学习过算法,不过算法确实是需要系统学习的.大二上学期,在导师的建议下开始学习数据结构,零零散散的一学期,有了链表.栈.队列.树.图等的概念.又看了下那几个经典的算法——贪心算法.分治算法 ...

随机推荐

  1. GO interface显示类型转换方法

    一共两种,直接看代码 import ( "fmt") func main() { //var i interface{} = "TT" var i interf ...

  2. JAVA多态问题总结(课堂总结)

    面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点.多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据发 ...

  3. Redis哈希相关命令

    hash类型(类似于多维数组)hset key field value 把key中filed域的值设置为value(如果之前存在就覆盖,不存在就添加) hmset key field1 value1[ ...

  4. Weex-语法笔记 一

    p.p1 { margin: 0.0px 0.0px 2.0px 0.0px; font: 14.0px "PingFang SC Semibold"; color: #45454 ...

  5. JavaBean的属性变量名前两个字母大小写问题

    Java属性命名规范! 一般情况下.Java的属性变量名都已小写字母开头,如:userName,showMessage等,但也存在着特殊情况,考虑到一些特定的有意思的英文缩略词如(USA,XML等), ...

  6. JSP脚本元素、指令元素、动作元素

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  7. hbase 无法操作与hadoop的安全模式的原因

    最近使用hbase时,运行zookeeper的机子没有正常关闭zookeeper就关机了,导致开机后整个hbase集群无法使用,表现为master的localhost:60010 无法登录,使用hba ...

  8. Hibernate使用原生SQL(转载)

    本文转载,出处如下:http://bhdweb.iteye.com/blog/801084 HQL尽管容易使用,但是在一些复杂的数据操作上功能有限.特别是在实现复杂的报表统计与计算,以及多表连接查询上 ...

  9. js--事件对象的理解4

    阻止默认行为:1.实例-简易修改右键菜单<script>document.oncontextmenu=function (ev){ var oEvent=ev||event; var oU ...

  10. [妙味DOM]第一课:DOM基础概念、操作

    知识点总结 childNodes.children子节点列表集合.nodeType节点类型.nodeName.nodeValue.attributes属性列表集合 childNodes和childre ...