資料結構演算法 - LeetCode 刷題
資料結構和演算法的課程講解,目前已告一段落,也算是完成了自己的一個心願。因為去年聽某同學抱怨過,說自己去愛奇藝面試,其他問題都答得不錯,面試官問了一個哈夫曼演算法的題沒答出來,後來面試官很明確的說,我們還是想找一個會些演算法基礎的。
如果之前有學過資料結構和演算法,建議大家不定時的去刷刷演算法題,因為從面試的角度來講,目前 BAT 和 TMD 等一線網際網路企業或多或少都會有幾個演算法題,而對應屆畢業生來說演算法的要求度則更高。當然大家面試過程中遇到的演算法題,90%都來自於各大刷題網站。另一方面從開發的角度來講,資料結構和演算法絕對是一門內功,思維方式和嚴謹程度上都會有一個跳躍性的提升。就在前幾天團隊出現了兩個疑難雜症,一個是小米手機的 View 資料丟失的 Bug,一個是直播間高斯模糊演算法的卡頓。解決問題時若我們能站在底層原始碼和演算法的角度去分析問題,絕對會要輕鬆許多。
線上程式設計評測的平臺有很多,比較有名的有 Hihocoder,LintCode,LeetCode。我們一般在 ofollow,noindex">LeetCode 上刷題比較多,目前有九百多道題目。不必每道題都刷,但建議至少把前 200 道刷一遍。不要看標籤,不要看標籤,標籤相當於問題的分類,看了標籤就會往那個方向去想,不利於自主思考。如果目前正處於面試階段建議每天刷兩三題,如果目前是工作狀態可以不定時的刷一刷。LeetCode 的題型都非常簡單明瞭,並不需要複雜的理解,一般都在幾十行以內就可以解決了,如果你寫了上百行程式碼,就肯定說明你想太多了或太複雜,雖然都能用很短的程式碼就能解決,但並不意味著 LeetCode 的題目非常簡單,實際上LeetCode 基本上涉及到了所有常規的演算法型別。
獨立解決一個問題是最好的學習途徑。如果你被某一個地方卡住了,不要急著去網上找答案,不管程式碼寫得有多麼爛先想辦法實現,然後再想想有沒有更好的方案,最後再去參考參考他人的實現方式。切記不是為了簡單的實現,而是去想有沒有更好的解決方案。請看第一題:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
這道題從通過率來看已經比較高了,題目本身也非常簡單,用暴力破解即可:
public int[] twoSum(int[] nums, int target) { for(int i=0;i<nums.length;i++){ for(int j= i + 1;j<nums.length;j++){ if(nums[i]+nums[j] == target){ return new int[]{i,j}; } } } return null; }

單從結果上來看是通過了,但切記不是為了簡單的實現,而是去想有沒有更好的解決方案。就好比現在有一個棘手的問題擺在咋們面前,我們的追求只是簡單去實現,還是應該想想有沒有更好的解決方案呢?再想想:
public int[] twoSum(int[] nums, int target) { Map<Integer,Integer> maps = new HashMap<>(nums.length); for(int i=0;i<nums.length;i++){ int diff = target - nums[i]; if(maps.containsKey(diff)){ return new int[]{maps.get(diff),i}; } maps.put(nums[i],i); } return null; }

從上面來看,該題演算法的複雜度可以優化到 O(n) ,那為何測試結果卻顯示未達最優?我們之前分析 HashMap 的原始碼時,可知其查詢演算法的複雜度,最好的情況是 O(1) 最壞是 O(logN) 。因此我們還可以有更好的解決方案:
public int[] twoSum(int[] nums, int target) { Integer[] filter = new Integer[4096]; int length = nums.length; int diff = 0; for(int i=0;i<length;i++){ diff = target - nums[i]; Integer index = filter[diff&4095]; if(index != null){ return new int[]{index,i}; } filter[nums[i]&4095] = i; } return null; }

Implement atoi which converts a string to an integer.
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned.
Note:
- Only the space character ' ' is considered as whitespace character.
- Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. If the numerical value is out of the range of representable values, INT_MAX (231 − 1) or INT_MIN (−231) is returned.
這題也是鵝廠面試題中的一道高頻演算法題,題目本身並不難,但從通過率上來看是一道極低的題目,主要考察的是我們思考問題的時候是否嚴謹。好比我們在公司完成了一個需求,測試沒問題,灰度也沒問題,但上線就出現問題了。某部分原因也是我們在做需求的時候很多場景沒有考慮到,在公司老大最喜歡說的口頭禪之一就是 “你這樣寫有坑”。
int myAtoi(string str) { long result = 0; int len = str.trim(); int index = 0; // 過濾空格 while(index<len && str[index] == ' '){ index++; } // 正負符號 int negative = 1; if(index<len && str[index] == '+'){ index++; } else if(index<len && str[index] == '-'){ negative = -1; index++; } if(index == len){ return 0; } // 計算結果 while(index<len){ char c = str[index++]; if(c<'0' || c>'9'){ break; } result = result*10 + (c-'0'); // 處理越界的情況 if(negative*result > INT_MAX) return INT_MAX; else if(negative*result < INT_MIN) return INT_MIN; } return result*negative; }
視訊地址:週日晚八點