1. 程式人生 > >九章演算法筆記 1.Introducing Algorithm Interview & Coding Style

九章演算法筆記 1.Introducing Algorithm Interview & Coding Style

Implement strStr

cs3k.com

http://www.lintcode.com/problem/strstr/

Returns the position of the first occurrence of string target in string source, or -1 if target is not part of source.

遇到這道題和麵試官說什麼,有什麼要確認的麼?cs3k.com

 

對效能有要求麼?

–面試常見錯誤1:我知道有個演算法叫KMP

–不應該扯KMP的原因,而應該從最簡單的演算法開始:

1.演算法往往沒那麼難

2.用那麼難得演算法,寫出不來咋辦

3.用簡單的演算法,即使不能寫全,寫到完美,至少能得一部分分

4.所以我們要寫一個O(m+n)的兩個for的傻叉演算法就可以了

面試常見錯誤2:Coding Style cs3k.com

screenshot-from-2017-03-05-21-39-17

–命名風格 s1, s2 神碼鬼?

要用source, target

–if(){

}

一行也要用花括號, c++詳見google coding style

–什麼時候加空格?

1.二元運算子左右各一個space

2.++ — 不加space

3.分號右加左不加

常見錯誤3:沒考慮corner case cs3k.com

screenshot-from-2017-03-05-21-39-17

要體現自己細心靠譜,考慮各種面試官都不一定能想到的情況:

1.檢測空(字串,集合….)

2.檢測下標越不越界:

凡是返回下標的,都要檢查越界不,萬一返回-1呢?會不會返回大於n呢?

3.要有縮排

–如果問比O(n^2)更好的演算法

Rabin-Karp演算法:基於hash function的原理

–主動給出Test case而不是uni test????區別

null和空的情況啦

你真的會面試麼? cs3k.com

–白紙上要寫一遍

lintcode上面的N/A小於3是比較好的,自己動腦debug,不要提交錯了再改

–吃透幾道題?

看答案寫出來的,過一週到兩週要自己再做一遍

–面試不會就說不會麼?

面試官是coworker, 程式設計師要有自己google然後搞定的能力

–面試官為難你?

追問是正常的,不要覺得面試官是傻逼

為什麼要面試演算法?演算法面試難麼? cs3k.com

演算法難,演算法面試不難,因為考察的範圍很窄.

–為啥這些演算法沒啥用還考?為啥不寫project呢?

1.45分鐘內完成一段程式碼

2.主要考察寫程式碼的能力,所以會考不太難想的演算法,但是實現不太容易的演算法

3.主要不是想題,而是寫程式:像貪心法這種沒有太大通用性的,考得很少

刷題的經驗:cs3k.com

–總結類似題目,一道變一類

–給一類題目弄出個模板程式

排列與組合cs3k.com

搜尋的複雜度

–構造每個答案的時間 * 答案的個數

子集這道題為:

=O( n * 2^n)

–permutation  排列

=O(n!  * n)

有時答案個數不確定的時候,假設S是所有答案的個數

= O(S  * n)

問時間複雜度,基本可以和麵試官交流就ok了

找子集問題cs3k.com

http://www.lintcode.com/en/problem/subsets/

Given a set of distinct integers, return all possible subsets.

Example

If S = [1,2,3], a solution is:[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]

img_1194

–從空集出發,怎樣構造?

一層一層去想的,去搜索的,這種叫做寬度優先搜尋

–深搜有什麼好處呢?

1.寬搜需要記錄上一的狀態,而深搜只需要記錄上一狀態。

2.如果面試官要求打印出來就行,又因為print是不佔用空間的,所以深搜空間更優。

深搜

DFS即深度優先搜尋,本質是回溯,是back tracking。

是後悔的過程,是撞了南牆後悔,再回到之前的狀態。

其中{1,3}之後不能加2,是因為不能重複,因為{1,2, 3}和{1, 3, 2}一樣

–避免重複不應該採用的方法為:

記錄所有狀態,然後回去查查,如果重了,就不加。

因為這樣的話,時間複雜度從O(n!)變成O(n^n)

–應該採用的方法為選代表:

{1,2,3} {1,3,2} {2,1,3} {2,3,1} {3,1,2} {3,2,1} 

選代表的原則是:看臉,看誰帥誰順眼選誰

{1,2,3}明顯比較順眼,因為有規則的增序,所以最後的路徑就是如圖上的粉箭頭的指向。

遞迴cs3k.com

遞迴的本質是由大化小

–遞迴需要主要的問題:

遞迴是不是太深?在找子集問題上,不會太深,因為解一共有(2^n)個,如果n太大,解根本解不完。所以n一定是一個很小的數,n不大,遞迴也就不會太深。

–開始new一個空的子集

並且所有函式先解決corner case,做異常檢測。

此題即解決0和null的問題。

–這道題還需要排個序,因為題目有要求

–遞迴的是一個function叫func(A)自己呼叫自己,我們在這裡構造一個helper()函式

這個helper的引數呢,需要subset和可加的nums以及傳答案的results以及為了避免重複而傳進去的最後一個數的index(可以不傳,這裡傳進去比較直觀)

遞迴三要素

1.遞迴的定義:

接受什麼引數,返回什麼值,做了什麼事兒

這裡是找到所有以subset開始的集合,然後丟到result裡面

ps:一行不要超過80到100個字元,所以引數多要分行

2.遞迴的拆解,怎麼拆成更小的?

{1}     拆成 {1, 2}  {1, 3}  {1, 4}

ps:soft copy 要注意,soft copy是reference

subset = [];

results.add(subset);

results.add(subset);

results.add(subset);

subset = 1;

最後results: [1]   [1]   [1]

所以results.add{new一個出來的deep copy}

–函式呼叫後全部刪除:

四大步驟:1. add{new一個空的出來}   2.加一個數  3.呼叫自己的小任務   4.刪這個數

3.遞迴出口(什麼時候不忘下遞迴了,可以直接找到答案退出)

–怎麼看一個題目是深搜

有all possible字樣的

寫程式不是從上往下寫,先寫思路。

重點是bug free和速度

課後小視訊之Subsets IIcs3k.com

看到all 字樣,很容易是深搜

如何去重呢? 錯誤的想法是找到所有的答案,然後再看重複與否, 去掉.

比如[1,1,1,1,1,1] 只有7個子集,但是有寫2^6個答案, 浪費時間

應該開始就不加入重複的

helper應該是private的

[1,2,2′]什麼時候我們應該避免重複呢?

遇到2’的時候,如果2’之前有2,而且2沒有在已有的集合中,此時加2′,就會重複

Screenshot from 2017-03-13 21-55-16.png

課後小視訊之字串查詢之 Rabin Karp 演算法 cs3k.com

這種演算法的本質是用hash function把字串之間的比較由O(m)長的時間變為O(1)

hash function

雜湊表就是個大陣列, hash function是個把字串, float, double, int都轉換到陣列一個位置的mapping.

ABCDE

= (a * 31^4 + b * 31^3 + c * 31^2 + d * 31 + e) % 10^6

其中31是個經驗值, hash size 10^6, 越大越不容易重, 越小越容易衝突, 所以選一個不越界的大的值

如果用int的話, 保證 31 * 10^6不越界.

如果用10^8的話, 就需要long int 了

key到value唯一, 反之不成立.  abc 只等於123, cde也只等與123, 但是123對應兩個string

Screenshot from 2017-03-13 22-31-26.pngScreenshot from 2017-03-13 22-32-09

開始要處理null和length=0

22行的power要邊乘邊模,防止越界.

42行負數的情況最好不要直接模, 因為不同的語言負數的模結果不同,所以手動if一下

48行, hash code一樣串不一定一樣,hash code 不一樣的串一定不一樣, false positive, 所以再比較一次