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

这周最后仍是来聊聊算法,拓扑排序

拓扑排序原理和习题分析

相关文章
相关标签/搜索