Arts 第十週(5/20 ~ 5/26)

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


Algorithm

LeetCode 140. Word Break II算法

LeetCode 472. Concatenated Words編程

題目一:思路分析
瀏覽器

也是一道比較經典的回溯問題,在搜索的方式上,有兩種思路,第一種思路是基於字符串的字符,另一種是根據詞表裏面的單詞,顯然是第二種更優,代碼也會更加簡潔,可是這一題的難點在如何把暴力搜索變成記憶化搜索,也就是咱們一般說的動態規劃,若是你畫出遞歸樹的話,你能夠明顯看到這裏是有重複子問題的,這樣,問題就變成了原問題和子問題的關係,以及子問題的解如何表示?由於考慮到輸入字符串或者說輸入字符串的子串是容許多個拆分可能性的,所以這裏咱們考慮用一個 Map 去存儲當前子串對應的全部可能的拆分狀況,而後當前考慮的單詞直接加到這些子串以前,就是當前的解,利用遞歸回溯更新,最後返回的就是答案,可是這裏有一點須要注意的是,每當傳入的字符串是空的時候,表示以前的單詞是最後一個單詞,這時須要在返回的 list 中添加一個空串佔位,表示遞歸前面的函數傳進來的 word 是可行的。緩存

題目一:參考代碼安全

public List<String> wordBreak(String s, List<String> wordDict) {
    if (s == null || s.length() == 0) {
        return new ArrayList<String>();
    }
    
    Map<String, List<String>> hash = new HashMap<>();
    
    List<String> path = helper(s, wordDict, hash);
    
    return path;
}

private List<String> helper(String remain, List<String> wordDict, Map<String, List<String>> hash) {
    if (remain.equals("")) {
        List<String> l = new ArrayList<String>();
        l.add("");
        return l;
    }
    
    if (hash.containsKey(remain)) {
        return hash.get(remain);
    }
    
    List<String> path = new ArrayList<>();
    for (String word : wordDict) {
        boolean isStartsWith = remain.startsWith(word);
        
        if (isStartsWith) {
            List<String> subPath = helper(remain.substring(word.length()), wordDict, hash);

            for (String sub : subPath) {
                if (sub.equals("")) {
                    path.add(word);
                } else {
                    path.add(word + " " + sub);
                }
            }
        }
    }
    
    hash.put(remain, path);
    
    return path;
}
複製代碼

題目二:思路分析
服務器

這道題和前面那道題很是的相似,區別就是輸入參數上,這裏給的就是一個詞表,字符串和詞表合二爲一了,須要查找的字符串在詞表裏面。徹底能夠按照上面那道題的解法,就是以記憶化搜索的形式去作動態規劃,可是這一題想一想其實沒有必要像以前那樣使用很是多的字符串操做,字符串自己是不可變的,過多的字符串操做會對時間效率產生影響,使用 StringBuilder 這樣的函數又會使代碼複雜,題目要求咱們僅僅是找出符合的單詞,因而這裏考慮使用字典樹,首先根據單詞列表構建字典樹這裏就不用說了,這裏惟一須要注意的一點是,須要考慮詞表中出現空串的狀況。而後後面就是每一個單詞去字典樹中走一遍,找到了符合要求的單詞就讓字典樹從頭開始,count + 1,可是注意傳入參數和遞歸出口的關係,也就是字典樹節點和當前字符的關係,若是像個人代碼同樣,字典樹節點和當前字符滯後一位,那麼函數出口應該考慮,若是 index 出了單詞,就考慮當前節點是否是一個有效的節點,若是有效,而且 count >= 1,那麼這個單詞就是符合要求的。cookie

題目二:參考代碼框架

private class TrieNode {
    TrieNode[] children = new TrieNode[26];
    boolean isWord = false;
}

private void buildTree(String[] words) {
    TrieNode pointer = root;
    
    for (String word : words) {
        if (word.equals("")) {
            continue;
        }
        
        pointer = root;
        
        for (char c : word.toCharArray()) {
            if (pointer.children[c - 'a'] == null) {
                pointer.children[c - 'a'] = new TrieNode();
            }
            
            pointer = pointer.children[c - 'a'];
        }
        
        pointer.isWord = true;
    }
}

private TrieNode root = new TrieNode();

public List<String> findAllConcatenatedWordsInADict(String[] words) {
    if (words == null || words.length == 0) {
        return new ArrayList<String>();
    }
    
    buildTree(words);
    
    List<String> results = new ArrayList<>();
    for (int i = 0; i < words.length; ++i) {
        if (helper(root, words[i].toCharArray(), 0, 0)) {
            results.add(words[i]);
        }
    }
    
    return results;
}

private boolean helper(TrieNode cur, char[] word, int count, int index) {
    if (cur == null) {
        return false;
    }
    
    if (index == word.length) {
        if (count >= 1 && cur.isWord) {
            return true;
        } else {
            return false;
        }
    }
    
    if (cur.isWord
           && helper(root.children[word[index] - 'a'], word, count + 1, index + 1)) {
        return true;
    }
    
    return helper(cur.children[word[index] - 'a'], word, count, index + 1);
}
複製代碼

Review

一篇關於學習編程的建議性文章:
dom

The main pillars of learning programming — and why beginners should master them

  • TDD(Test-Driven-Developement)測試驅動開發
    新手每每並不知道測試的重要性,他們可能會以爲測試有時很煩人,不寫測試可以大大地節省開發效率,可是測試,特別是單元測試是對代碼安全的保障,防止代碼在往後帶來嚴重的問題。若是在一開始保持寫代碼就必須有測試的意識,是對後面的學習新知識頗有幫助的,養成良好的習慣真的很重要。

  • 基礎優先
    函數、變量、條件判斷以及循環是全部程序的基礎,必須把這些基礎性的,特別是不少認知性的東西弄清楚,而且賦予足夠的、全面的練習後,再去考慮一些應用層面的學習;在這裏必須求穩,而不是求快。

  • 學習使用庫和框架
    對於新手來講,一開始確定是須要使用別人寫的代碼,可以基本理解這個庫的功能和用途,使用正確的框架作正確的事情,這樣可以提升新手的學習以及開發效率,否則新手就會對編程失去興趣,以爲太難,獨自造輪子的事情是對於經驗豐富的人來講的

  • 找一個好老師
    有時候別人的一句話等於本身想好幾天,有一個好的老師帶領,確實對學習頗有幫助,也會讓你開始的路好走不少

  • 挑戰和動機
    繼續學習,持續學習的動力是源於本身心裏的動機,以及外界的挑戰,這兩個因素都會督促你去千方百計去提升本身的能力和認知,咱們要時刻保持上進的精神,同時咱們也要明白本身當前是否是在溫馨區內,敢於走出溫馨區,主動去尋找本身的下一個挑戰


Tip

初識 Chrome 瀏覽器的 Network 面板

分紅五大部分:

  • 控制器 -> 用於控制
    • 控制抓包(開始、中止、清除請求)
    • Preserve log(跨頁面加載保存請求)
    • Capture Screenshots (屏幕截圖)
    • 停用瀏覽器緩存
    • Clear browser cache(手動清除瀏覽器緩存)
    • Clear Browser Cookies(手動清除瀏覽器 Cookies)
    • Offline(離線模式)
    • Network Throttling(可自定義網速)
  • 過濾器 -> 有一個搜索欄,外加一些按鈕,幫助過濾搜索請求文件信息
    • domain:... 只顯示來自指定定義域的請求
    • has-response-header:... 顯示包含指定 HTTP 響應標頭的資源
    • is:... is:running -> 查找 WebSocket 資源,is:from-cache -> 查找緩存讀出資源
    • larger-than:... 顯示大於指定大小的資源
    • method:... 顯示經過指定 HTTP 方法類型檢索的資源
    • mime-type:... 顯示指定 MIME 類型的資源
    • schema:... schema:http
    • status-code:... 僅顯示指定狀態編碼的資源
    • set-cookie-value
    • set-cookie-name
    • set-cookie-domain
  • 概覽 -> 顯示 HTTP 請求,響應的時間軸
  • 請求列表 -> 請求的文件資源,默認時間排序
    • Name: 資源的名稱
    • Status: HTTP 狀態碼
    • Type: 請求的資源的 MIME 類型
    • initiator: 發起請求的對象或者進程
      • Parser(解析器): Chrome 的 HTML 解析器發起的請求
      • Redirect(重定向): HTTP 重定向啓動了請求
      • Script(腳本): 腳本啓動了請求
      • Other(其餘): 用戶點擊、輸入,等等
    • size: 服務器返回的響應大小
    • time: 總持續時間,從請求開始到接收響應的最後一個字節
    • waterfall: 各請求相關活動的直觀分析圖
  • 概要 -> 請求總數、總數據量、總花費時間

這裏有個小技巧就是,咱們能夠按住 shift 鍵,而後鼠標懸停在某個資源上,能夠顯示這個資源的上下游請求(下游請求是由上游請求發起的)

另外補充一下瀏覽器的加載流程

  • 解析 HTML 結構
  • 加載外部腳本和樣式表文件
  • 解析並執行腳本代碼(部分腳本會阻塞頁面的加載)
  • DOM 樹構建完成(DOMContentLoaded 事件)
  • 加載圖片等外部文件
  • 頁面加載完畢(load 事件)

Share

這已是第十次 ARTS 了,此次作一個階段性地總結吧,談談收穫,談談計劃,再談談理想。

ARTS 階段性總結

相關文章
相關標籤/搜索