LeetCode 219.Contains Duplicate II

今天是大年初七,祝大家新年快樂!萬事如意!恭喜發財!

同時也是今年第一篇文章:LeetCode 219 題解

說說LeetCode

作爲大名鼎鼎的面試刷題網站,最近也出了中文版,如果之前沒有了解過的童鞋,建議去網站看看,裏面有各大互聯網公司的算法面試題,包括谷歌,Fackbook,微軟,亞馬遜等等,近年來國內的互聯網公司也越來越重視算法和數據結構了,特別是後端,經常看到高級工程師 職位以上的jd都寫明,算法水平需要到LeetCode Hard程度,前端稍微好一點,但是也需要LeetCode Easy 水平,因此無論是爲了鞏固基礎,還是找工作跳槽,我們都需要不斷練習算法,那麼比較好的方式自然就是找一個靠譜的平臺刷題了。

英文網站:https://leetcode.com/

中文網站:https://leetcode-cn.com/

值得一提的是,現在中文LeetCode【力扣】 還支持同步英文網站的賬號數據,但是就個人而言,英語過得去的還是建議上英文,因爲裏面的功能比中文網多一點,而且最重要的是,Discuss裏面的人數也會多一些,經常能看到NB的解法,還是很有幫助的。

那麼爲什麼刷題還要寫文章記錄下來呢?

其實這篇文章的題目我在兩年前就已經做過了,但是今天重新看,發現還是需要花很多時間去想解法,一方面當然是因爲沒有堅持做算法題,思維跟不上,另外一方面就是當時做完就算了,沒有進一步思考,除了自己的這個解法,是否還有更好的方法。

因此我選擇了把思考和改進的過程記錄下來,當然大家用筆記類的工具記錄,或者放到Github上都可以,目的都是爲了鍛鍊自己的思維,提高算法水平罷了。

我當時的提交記錄:

在這裏插入圖片描述

我打敗了58%的人,那麼前面的算法是怎麼樣的呢?

之前使用的是Java,那麼如果換成C,C++,Python等語言,結果又是怎麼樣呢?

除了算法之外,是不是也有一些編程語言的技巧呢?

通過進一步的思考,我們會發現越來越多可以深入學習的地方。

因此,我決定把一部分題目寫成博客,初衷就是爲了方便自己,如果正好也能給予他人一點幫助的話,那就更好了。

219.Contains Duplicate II

難度: Easy 分類:Array

題目

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.

Example 1:

Input: nums = [1,2,3,1], k = 3
Output: true

Example 2:

Input: nums = [1,0,1,1], k = 1
Output: true

Example 3:

Input: nums = [1,2,3,1,2,3], k = 2
Output: false

翻譯:

給定一個數組和一個整數k,找出是否存在兩個不同下標i和j,滿足nums[i] = nums[j],並且這兩個數字的絕對值不大於k。

解答

思路:

  1. 根據題目可知:我們需要一個數組和一個整形,返回值是Boolean類型的。
public class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        boolean isTrue = false;

        return isTrue;
    }
}
  1. 然後我們要找出是否存在滿足題目條件的兩個數,這裏我的想法是使用一個HashMap來存儲下標,然後遍歷找出滿足條件的數組下標
public class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        boolean isTrue = false;
        // Setp 2
		HashMap<Integer,Integer> hashMap = new HashMap<>();
		// 通過遍歷數組,把數組的值存到HashMap中,再找後面是否存在值一樣,而且下標差值<=k的數,有的話返回			  true
        for(int i=0;i<nums.length;i++){
            if(hashMap.containsKey(nums[i]) && i - hashMap.get(nums[i]) <= k){
                isTrue = true;
            }else {  
                hashMap.put(nums[i], i);  
            }  
        }
        return isTrue;
    }
}
  1. 考慮邊界條件,雖然這樣做就可以達到題目的要求了,但是提交的時候沒能通過test cast,原因是沒有考慮到當數組大小<=1的情況,加上這個條件,最終我的提交結果爲:
public class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        boolean isTrue = false;
        // Step 3
        if(nums.length<=1){
            return isTrue;
        }
        HashMap<Integer,Integer> hashMap = new HashMap<>();
        for(int i=0;i<nums.length;i++){
            if(hashMap.containsKey(nums[i]) && i - hashMap.get(nums[i]) <= k){
                isTrue = true;
            }else {  
                hashMap.put(nums[i], i);  
            }  
        }
        return isTrue;
    }
}

這個解答的時間是:11ms,打敗了58%的人,那麼有沒有更簡單更好的解答呢?

思考

這個是LeetCode Discuss上的解答,經過我在LeetCode上Run Code,Runtime爲 0 ms

public boolean containsNearbyDuplicate(int[] nums, int k) {
        Set<Integer> set = new HashSet<Integer>();
        for(int i = 0; i < nums.length; i++){
            if(i > k) set.remove(nums[i-k-1]);
            if(!set.add(nums[i])) return true;
        }
        return false;
 }

思路:

同樣是通過遍歷數組,

  1. 如果i>k,那麼說明前面的值已經不滿足|i-j| <= k 的條件,可以移除 i-k-1的值
  2. 然後再判斷,如果發現,咦,有一個數已經在集合裏面了,我沒辦法加進去, set.add() 返回的是 false,那麼這個數就是符合題目要求的,存在這樣的數,因此我們直接 return true

我們來看看HashSet的源碼:

/**
     * Adds the specified element to this set if it is not already present.
     * More formally, adds the specified element <tt>e</tt> to this set if
     * this set contains no element <tt>e2</tt> such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.
     *
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     * element
     */
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

通過這個方法就可以判斷當前元素是否已經在集合裏面了。

其實這個解法的思路和我的解法是大同小異的,但是代碼寫得很巧妙,值得學習的地方有好幾個:

  1. 通過set.add()的方法來判斷,不需要 i - hashMap.get(nums[i]) <= k

  2. 通過set.remove(nums[i-k-1]) 來移除不滿足條件的數字,而不是像我的方法,通過add,再一個個判斷,減少了工作量

  3. 除了學習算法思路以外,也可以學習到集合的一些源碼和實現,也就是數據結構的知識

C++ 解法 - Runtime: 8 ms

class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        unordered_set<int> st;
        for (int i = 0; i < nums.size(); i++) {
            if (i > k) {
                st.erase(nums[i - k - 1]);
            }
            if (!st.insert(nums[i]).second) {
                return true;
            }
        }
        return false;
    }
};

Python解法 - Runtime: 24 ms

def containsNearbyDuplicate(self, nums, k):
    dic = {}
    for i, v in enumerate(nums):
        if v in dic and i - dic[v] <= k:
            return True
        dic[v] = i
    return False

總結

今年立下的目標就是鞏固基礎,包括設計模式,算法與數據結構,學習第三方框架源碼等,每天都要進步一點點,量變引起質變!與大家共勉!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章