今天是大年初七,祝大家新年快樂!萬事如意!恭喜發財!
同時也是今年第一篇文章:LeetCode 219 題解
說說LeetCode
作爲大名鼎鼎的面試刷題網站,最近也出了中文版,如果之前沒有了解過的童鞋,建議去網站看看,裏面有各大互聯網公司的算法面試題,包括谷歌,Fackbook,微軟,亞馬遜等等,近年來國內的互聯網公司也越來越重視算法和數據結構了,特別是後端,經常看到高級工程師 職位以上的jd都寫明,算法水平需要到LeetCode Hard程度,前端稍微好一點,但是也需要LeetCode Easy 水平,因此無論是爲了鞏固基礎,還是找工作跳槽,我們都需要不斷練習算法,那麼比較好的方式自然就是找一個靠譜的平臺刷題了。
值得一提的是,現在中文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。
解答
思路:
- 根據題目可知:我們需要一個數組和一個整形,返回值是Boolean類型的。
public class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
boolean isTrue = false;
return isTrue;
}
}
- 然後我們要找出是否存在滿足題目條件的兩個數,這裏我的想法是使用一個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;
}
}
- 考慮邊界條件,雖然這樣做就可以達到題目的要求了,但是提交的時候沒能通過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;
}
思路:
同樣是通過遍歷數組,
- 如果i>k,那麼說明前面的值已經不滿足|i-j| <= k 的條件,可以移除 i-k-1的值
- 然後再判斷,如果發現,咦,有一個數已經在集合裏面了,我沒辦法加進去, 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 ? e2==null : 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;
}
通過這個方法就可以判斷當前元素是否已經在集合裏面了。
其實這個解法的思路和我的解法是大同小異的,但是代碼寫得很巧妙,值得學習的地方有好幾個:
-
通過set.add()的方法來判斷,不需要 i - hashMap.get(nums[i]) <= k
-
通過set.remove(nums[i-k-1]) 來移除不滿足條件的數字,而不是像我的方法,通過add,再一個個判斷,減少了工作量
-
除了學習算法思路以外,也可以學習到集合的一些源碼和實現,也就是數據結構的知識
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
總結
今年立下的目標就是鞏固基礎,包括設計模式,算法與數據結構,學習第三方框架源碼等,每天都要進步一點點,量變引起質變!與大家共勉!