Arts 第十三週(6/10 ~ 6/16)

ARTS是什麼?
Algorithm:每週至少作一個leetcode的算法題;
Review:閱讀並點評至少一篇英文技術文章;
Tip:學習至少一個技術技巧;
Share:分享一篇有觀點和思考的技術文章。html


Algorithm

LeetCode 126. Word Ladder IIjava

思路分析
這道題是一道經典的搜索問題,難點仍是在於優化。題目要求找出全部可能的解,咱們能夠把這道題轉化爲一個無向圖,每一個單詞表示的是圖上的節點,保證每一個單詞的鄰居單詞跟這個單詞只有一個字母的不一樣,若是用暴力的深度優先搜索,咱們在圖上選中起始節點和終止節點,考慮全部的從起點到終點的可能的路徑,這麼作會大大增長搜索所消耗的時間,那麼怎麼優化呢?和咱們以前經常提到的增長記憶化不一樣的是,這裏咱們考慮使用標記法,由於在搜索的時候,咱們要保證咱們當前的搜索方向是朝着終點去的,什麼意思,就是說,下一個咱們要去的節點到終點的距離要比到當前咱們所在節點到終點的距離更近,根據這麼一個思路咱們能夠進行兩次搜索,第一次僅僅是標記,第二次纔是搜索可能的答案。這裏標記使用的是廣度優先搜索,爲何不使用深度優先搜索?由於這個圖中可能存在環,深度優先搜索無法保證標記的正確性。搜索答案的時候咱們可使用深度優先搜索,也能夠廣度,這裏我使用了深搜。python


參考代碼算法

public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
    if (beginWord.equals(endWord) || !wordList.contains(endWord)) {
        return new ArrayList<>();
    }
    
    List<List<String>> results = new ArrayList<>();
    
    // bfs mark
    Map<String, Integer> memo = new HashMap<>();
    for (String word : wordList) {
        memo.put(word, -1);
    }
    
    memo.put(beginWord, -1);
    memo.put(endWord, 0);
    
    bfsMark(endWord, memo);
    System.out.println(memo);
    
    // dfs find path
    List<String> path = new ArrayList<String>();
    path.add(beginWord);
    
    dfs(memo, beginWord, endWord, wordList, path, results, memo.get(beginWord));
    
    return results;
}

private void dfs(Map<String, Integer> memo, String curWord, String endWord, List<String> wordList, List<String> path, List<List<String>> results, int step) {
    if (curWord.equals(endWord)) {
        results.add(new ArrayList<String>(path));
    }
    
    if (step <= 0) {
        return;
    }
    
    for (String word : wordList) {            
        if (memo.get(word) == step - 1 && checkDiff(word, curWord)) {
            path.add(word);
            
            dfs(memo, word, endWord, wordList, path, results, step - 1);
                
            path.remove(path.size() - 1);
        }
    }
}

private boolean checkDiff(String a, String b) {
    int count = 0;
    for (int i = 0; i < a.length(); ++i) {
        if (a.charAt(i) != b.charAt(i)) {
            count++;
        }
        
        if (count > 1) {
            return false;
        }
    }
    
    return count == 1;
}

private void bfsMark(String endWord, Map<String, Integer> memo) {
    Queue<String> queue = new LinkedList<>();
    queue.offer(endWord);
    
    int stepCount = 0;
    while (!queue.isEmpty()) {
        int size = queue.size();
        stepCount++;
        
        for (int i = 0; i < size; ++i) {
            String curWord = queue.poll();
            
            char[] curWordArr = curWord.toCharArray();
            for (char r = 'a'; r <= 'z'; ++r) {
                for (int j = 0; j < curWordArr.length; ++j) {
                    char tmp = curWordArr[j];
                    curWordArr[j] = r;
                    
                    String newWord = String.valueOf(curWordArr);
                    
                    if (memo.containsKey(newWord) && memo.get(newWord) == -1) {
                        queue.offer(newWord);
                        memo.put(newWord, stepCount);
                    }
                    
                    curWordArr[j] = tmp;
                }
            }
        }
    }
}
複製代碼

Review

一篇關於如何問別人技術問題的文章:
bash

How To Ask Questions The Smart Way網絡

問問題也是一門學問,特別是在網上問問題,文章讀起來不是太好懂,但仍是理解了、學到了很多,總結一下重點內容:app

  • 在問別人問題前,必定要對你的問題有所瞭解、而且嘗試着去解決,你能夠 Google,或本身手動模擬測試可能的狀況,再或者問你身邊的在行的朋友,若是嘗試了不少方法,可是依舊沒有辦法解決,在來問問題。本身發現問題並解決問題是對本身的成長幫助最大的,這樣也能夠保證你問的問題相對來講比較有質量,深思熟慮事後的問題更可以吸引高手的注意,相信沒有哪一個程序高手願意回答相似 「Java 如何打印輸出」 這樣的問題。
  • 在網絡上 POST 問題的時候注意問題標題的清晰、直接、易懂。做者給出了一個 「對象-錯誤表現」 的模版,對象說的是什麼東西,具體到哪一個地方出問題,這裏越具體越好,最好加上版本號,具體開源模組等等;錯誤表現是指這個東西發生了什麼狀況,這裏要作的是言簡意賅,直接了當說明症狀。標題不能過長但又要說明大體的狀況,保證別人閱讀起來不會耗時耗力,但又能立刻反應過來這個問題是什麼
  • 上面講了 POST 問題的標題,再說說描述問題的正文部分,這裏要注意的是不要加上一些本身的猜想,別人須要花時間閱讀這些猜想不說,還要去理解你爲何這麼想,容易混淆視聽,致使別人不肯意再看下去,更好的作法是描述問題發生的環境,而後你是怎麼作的致使了這個問題,還有一點就是你要寫出一些東西代表你嘗試着去解決這個問題,可是由於種種緣由,失敗了,這麼作有兩點緣由:
    • 讓別人明白這個問題對你來講是真的問題,你很但願本身獲得幫助,別人會以爲他的幫助在這裏會頗有價值
    • 打消那些可能的解,有些時候咱們問問題會獲得一些回答,可是那些回答你看完了發現本身以前已經嘗試過,可是問題沒有解決,而後咱們又要去追問,別人繼續追答,這樣很沒效率不說,下次其餘的人遇到相同的問題來看這個帖子的時候會閱讀不少無關信息,很沒效率
  • 咱們問的問題,要讓別人可以很快給出解,這個解最好就是一個指示,告訴咱們如何去作。不能說叫別人寫出一長串代碼,這樣的幫助耗時耗力,相信願意幫助的人很少。也不要讓別人看你的 code 去幫你 debug,要問的話,最好是能大大縮短代碼篇幅,方便別人,也方便本身
  • 防止目的不明確或者寬泛的問題,每一個問題都有一個最終目的,不論是想讓找出 bug,或者是解決發現的 bug,再或是設計上面想要有多點的建議,須要讓別人明白你想要什麼。另外就是不要把問題加上 「緊急」,「快速」 這樣的詞彙,這樣的話有一種在催別人的感受,致使別人不肯意看你的問題

Tip

這周接觸了 openresty,記錄一下它在 Mac 上的安裝和啓動post

安裝(使用 homebrew):學習

>$ brew tap openresty/brew
>$ brew install openresty
複製代碼

啓動:測試

>$ openresty -p `...` -c ...
複製代碼

中止:

>$ openresty -s quit -p `...` -c ...
複製代碼

再來記錄幾個以前比較模糊,可是如今懂了的 Python 基礎知識點:

  • Python 當中的對象的淺拷貝並非說只是拷貝引用,而是建立了一個新的對象,可是這個新對象裏面的子對象仍是以前對象裏面的子對象,下面的代碼很好的解釋了這一點:
import copy

a = [[1,2],2,3,4]
b = copy.copy(a)

b.append(1)
b[0].append(3)

print(a)
print(b)

-----------------------------
[[1, 2, 3], 2, 3, 4]
[[1, 2, 3], 2, 3, 4, 1]
複製代碼
  • == 運算符的定義,Python 和 Java 很不同,這裏 Python 比較的不是地址,而是值。Python 中比較地址用的是 is 運算符,順便說一下 Python 中用 id 來區分表示對象,其實能夠表明對象的地址了,is 運算符的運算速度會比 == 運算符快不少,由於 is 不會被重載,它僅僅比較兩個對象的 id

Share

這周最後仍是來聊聊算法,拓撲排序

拓撲排序原理和習題分析

相關文章
相關標籤/搜索