重复值问题

题目:Contains Duplicate

Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.

Input:

  • 数组 :: int[]

Output:

  • 数组是否有重复的数 :: boolean

Intuition:

最最直接的想法是用set,因为这是set最最明显的性质了。如果某个数无法加入set中那么就是duplicates了。注意set里的search与insert都是constant time。

Code:

TC: O(n) SC: O(n)

public boolean containsDuplicate(int[] nums) {
  Set<Integer> set = new HashSet<>();
  for (int n: nums){
    if (set.contaiAns(n)){
      return true;
    }
    set.add(n);
  }
  return false;
}

题目:Contains Duplicate II

Given an array of integers and an integer k, find out whether there are two distinct indices i and j in the array such that nums[i] = nums[j] and the absolute difference between i and j is at most k.

Input:

  • 数组 :: int[]
  • 两duplicates的index差最多为k :: int

Output:

  • 数组是否有重复的数 :: boolean

Intuition:

沿用之前题目的使用set的思想。但此时,我们不仅要往set里放值,而且还要往外拿。为什么?因为当set里的值的index与当前值的index大于k时,他对于解就没有价值了,那么干啥还要留着他捏?所以我们保持一个大小为k的Hashset就够了。另外remove() 的时间复杂度也是constant的。

Code:

TC:O(n) SC: O(min(n, k))

public boolean ContainsDuplicateII(int[] nums, int k){
  Set<Integer> set = new HashSet<>();
  for (int n: nums) {
    if (set.contains(n)){
      return true;
      }
      set.add(n);
      //Sliding window
      if (set.size() > k) {
            set.remove(nums[i - k]);
      }
    }
    return false;
}

题目:Contains Duplicate III

Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.

Input:

  • 数组 :: int[]
  • 两duplicates的index差最多为k :: int
  • 两duplicates的值差最多为t :: int

Output:

  • 数组是否有重复的数 :: boolean

Intuition:

这回不仅在index做了限制,连值上也做了限制。那最直接的想法就是在确保一个条件满足的情况下,去检查另一个条件是否满足。
如果用treeset的话,因为已经是sorted的情况,那么就检查某一个值的相邻最近的值(ceiling和floor)满不满足值差最多为t的条件。注意Treeset的sort复杂度是nlg(n), 增删改查的复杂度是lg(n).同样的使用sliding window的思路。

Code

TC:O(nlog(min(n,k))) SC:O(nlog(min(n,k)))

public boolean ContainsDuplicatesIII(int[]nums, int k, int t){
  Set<Integer> treeset = new TreeSet<>();
  for (int i = 0; i < nums.length; i++){
    //check ceiling
    int ceiling = set.ceiling(nums[i]);
    if (ceiling != null && ceiling - t <= nums[i]){
      return true;
    }
    
    //check floor
    int floor = set.floor(nums[i]);
    if(floor != null && floor + t >= nums[i]){
      return true
    }
    set.add(nums[i]);
    //sliding window
    if(set.size() > k){
      set.remove(nums[i - k]);
    }
  }
  return false;
 }

有没有O(n)的解法呢?想想看在O(n)内可以完成sort的算法是什么?桶排序对不对?当然我们这题没有必要完全sort整个数组,只不过利用了每个桶中数值都在设定范围内这一特性。

我们设桶的size为t,那么可以再k范围内扔进一个桶的数一定能满足条件。另外需要考虑的两个地方就是这个桶两边的桶,也可能还有值差小于t的情况,要分别检查下~

要注意的tricky的地方在于,对于负数,桶的选择要先加1除以桶的size再减一。为什么这么做呢? 举个🌰,在Java里,-3/5是0,而它应该是在index为-1的桶中。那么就需要这么做修正下。当然如果用python等别的语言不存在这个顾虑就不用考虑这个情况了。

Code

TC:O(nlog(min(n,k))) SC:O(nlog(min(n,k)))

public boolean ContainsDuplicatesIII(int[] nums, int k, int t){
  Map<Long, Long> map = new HashMap<>();
  int size = t + 1 // in case t == 0, we need to add extra 1
  for (int i = 0; i< nums.length; i++){
    int idx = getIdx(nums[i], size);
    //duplicates are in the same bucket
    if(map.containsKey(idx)){
      return true;
    }
    //duplicates are in neighbour buckets
    if (map.containsKey(idx + 1) && Math.abs(nums[i] - map.get(idx + 1))){
      return ture;
    }
    if (map.containsKey(idx - 1) && Math.abs(nums[i] - map.get(idx - 1))){
      return ture;
    }
    map.put(idx, (long)(nums[i]));
    if(map.size() > k){
      map.remove(getIdx(nums[i - k], size));
    }
  }
}

public int getIdx(int x, int size){
  if(x < 0){
    return (x - 1) / size + 1;
  }
  return x / size;
}

Reference

https://leetcode.com/problems/contains-duplicate/
https://leetcode.com/problems/contains-duplicate-ii/solution/
https://leetcode.com/problems/contains-duplicate-iii/solution/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容