1. 程式人生 > >九章演算法筆記 5.深度優先搜尋 Depth First Search

九章演算法筆記 5.深度優先搜尋 Depth First Search

DFS cs3k.com

什麼時候用dfs?

短, 小, 最問題

而90%DFS的題, 要麼是排列, 要麼是組合

組合搜尋問題 Combination

問題模型:求出所有滿足條件的“組合”

判斷條件:組合中的元素是順序無關的

時間複雜度:與 2^n 相關

遞迴三要素

一般來說,如果面試官不特別要求的話,DFS都可以使用遞迴(Recursion)的方式來實現。

遞迴三要素是實現遞迴的重要步驟:

• 遞迴的定義

• 遞迴的拆解

• 遞迴的出口

Combination Sum

cs3k.com

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

The same repeated number may be chosen from C unlimited number of times.

為什麼是正整數?

如果有0:

取一次是一種方案, 取兩次是一種方案, 最後有無數種方案.

新題和老題的關係:

看到新題要和老題產生關係, 哪兒像哪兒不像

這道題和subset的關係:

  1. 可以無限制的取

     

  2. 限制了一個和

  3. 去重: {1,2} == {2,1} 選代表

{2,2,3} = {2,3,2] = {3,2,2]

enter image description here

enter image description here

其中49行, [2’,2”,3]可能有三種:

[2’,2”,3]

[2’,2’,3]

ps: 也可以用hash set去重

去重

Given an array of integers, remove the duplicate numbers in it.

You should:

  1. Do it in place in the array.

     

  2. Move the unique numbers to the front of the array.

  3. Return the total number of the unique numbers.

class Solution {
public:
    /**
     * @param A: a list of integers
     * @return : return an integer
     */
    int removeDuplicates(vector<int> &nums) { if (nums.size() == 0) { return 0; } int len = 0; for (int i = 1; i < nums.size(); i++) { if (nums[len] != nums[i]) { nums[++len] = nums[i]; } } return len + 1; } };

兩點需要注意:

  1. for 之後的i從1開始

     

  2. return的不是index,二是數量,所以要加1

時間複雜度

cs3k.com

答案個數不知道, 假設為S;

每個答案用的時間=target;

所以總的時間複雜度= O(S*target), 是個NP問題

Combination Sum II

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

Each number in C may only be used once in the combination.

enter image description here

其中:

 if (i != startIndex && candidates[i] == candidates[i - 1]) { continue; }

去重的方式是相同的從第一個開始選, 不能跳過第一個選第二個.

Palindrome Partitioning

cs3k.com

Given a string s, partition s such that every substring of the partition is a palindrome.

Return all possible palindrome partitioning of s.

這道題的本質是組合問題:

aab怎麼分割的問題, 就是要不要縫隙

三個字元兩個空隙, 每個空隙我可以選擇要或者不要, 所以有4個答案.

enter image description here

一邊切, 一邊驗證是不是迴文串:

enter image description here

因為搜尋是一種嘗試, 是把以這個方案開頭的所有都找到.

找完之後, 還要回到原來的狀態, 要記得remove

Permutation

cs3k.com

Given a list of numbers, return all possible permutations.

排列搜尋問題 Permutation

問題模型:求出所有滿足條件的“排列”。

判斷條件:組合中的元素是順序“相關”的。

時間複雜度:與 n! 相關。

enter image description here

enter image description here

此題的時間複雜度是: O(n! * n)

和subsets的關係是:

  1. permutation是湊齊再加到答案上; 而subsets是中間結果也存.

     

  2. permutation是可以回頭取的, 但是不能重複取, 所以沒有startIndex.

Permutation II

cs3k.com

Given a list of numbers with duplicate number in it. Find all unique permutations.

enter image description here

  1. 邊排列邊看有沒有斜線攻擊.
    • 左上到右下的斜線上的點符合差相等:x1 – y1 = x2 – y2
    • 右上到左下和相等.
  2. 每個function不超過三十行, 不容易出bug

Word Ladder

cs3k.com

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:

Only one letter can be changed at a time

Each intermediate word must exist in the dictionary

搜尋,動態規劃,二叉樹的時間複雜度計算通用公式

搜尋的時間複雜度:O(答案總數 * 構造每個答案的時間)

舉例:Subsets問題,求所有的子集。子集個數一共 2^n,每個集合的平均長度是 O(n) 的,所以時間複雜度為 O(n * 2^n),同理 Permutations 問題的時間複雜度為:O(n * n!)

動態規劃的時間複雜度:O(狀態總數 * 計算每個狀態的時間複雜度)

舉例:triangle,數字三角形的最短路徑,狀態總數約 O(n^2) 個,計算每個狀態的時間複雜度為 O(1)——就是求一下 min。所以總的時間複雜度為 O(n^2)

用分治法解決二叉樹問題的時間複雜度:O(二叉樹節點個數 * 每個節點的計算時間)

舉例:二叉樹最大深度。二叉樹節點個數為 N,每個節點上的計算時間為 O(1)。總的時間複雜度為 O(N)

enter image description here

enter image description here

enter image description here

public class Solution {
    public int ladderLength(String start, String end, Set dict) { if (dict == null) { return 0; } if (start.equals(end)) { return 1; } dict.add(start); dict.add(end); HashSet hash = new HashSet(); Queue queue = new LinkedList(); queue.offer(start); hash.add(start); int length = 1; while(!queue.isEmpty()) { length++; int size = queue.size(); for (int i = 0; i < size; i++) { String word = queue.poll(); for (String nextWord: getNextWords(word, dict)) { if (hash.contains(nextWord)) { continue; } if (nextWord.equals(end)) { return length; } hash.add(nextWord); queue.offer(nextWord); } } } return 0; } // replace character of a string at given index to a given character // return a new string private String replace(String s, int index, char c) { char[] chars = s.toCharArray(); chars[index] = c; return new String(chars); } // get connections with given word. // for example, given word = 'hot', dict = {'hot', 'hit', 'hog'} // it will return ['hit', 'hog'] private ArrayList getNextWords(String word, Set dict) { ArrayList nextWords = new ArrayList(); for (char c = 'a'; c <= 'z'; c++) { for (int i = 0; i < word.length(); i++) { if (c == word.charAt(i)) { continue; } String nextWord = replace(word, i, c); if (dict.contains(nextWord)) { nextWords.add(nextWord); } } } return nextWords; } }

難點一: BFS

難點二:

L單詞長度遠小於N詞典裡的單詞數, 所以

L: 10 N:10K

可以把時間從100k變成2.5k

ps: hash_map的時間是O(key.size())

因為key變成hash code即為index

Word Ladder II

cs3k.com

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:

Only one letter can be changed at a time

Each intermediate word must exist in the dictionary

既有all又有shortest

BFS+DFS

enter image description here

  1. 小人往A走, 走的是回頭路;

往B走, 沒走的更近;

C才是正確的路線.

  1. start -> end BFS

end ->start DFS

再reverse

enter image description here

enter image description here

Subsets

非遞迴和其他組合題不一樣, 用位操作構造一個0~2^(n-1)的大迴圈

enter image description here

 

Permutation Next

cs3k.com

Given a list of integers, which denote a permutation.

Find the next permutation in ascending order.

Notice

The list may contains duplicate integers.

1 5 2 4 3找這些數字組成的稍微大那麼一點的數

從右往左找第一個降序的地方, 把它和右邊比他大的最小的換, 換完reverse回來

1 5 3 4 2

1 5 3 2 4