zoukankan      html  css  js  c++  java
  • 4专题总结-图论和DFS、BFS

    1图论:

    1.1  133. Clone Graph

    https://leetcode.com/problems/clone-graph/#/description

    思路:这题可以对照拷贝随机链表那道题,首先拷贝图中的节点,然后拷贝每个结点的neighbors数组。

    这题使用BFS,所有的BFS都可以看成是queue和unordered_map的组合实现的,该题模拟实现了一个queue,主要是因为后面要判断某个元素是否已经访问,所以使用一个vector来模拟操作,传统的queue会弹出元素,还需要一个vector来辅助,比较麻烦。拷贝节点前要使用一个if(Map.find(cur -> neighbors[i]) == Map.end()),没找到才将元素复制到一个map里面,key是旧节点,value是新节点,记住因为是拷贝,所以新节点必须是new出来的节点,不然指针还是指向原来的元素,出错。后面拷贝neighbor数组的时候也要注意这点,必须将map中的value当成拷贝数组中的元素(这点很重要)。 Map[qNode[j]] -> neighbors.push_back(  Map[  qNode[j] -> neighbors[k] ]  );

    map操作总结:

    插入使用insert函数,查找每个元素是否在map里面,使用map.find(),如果没找到就对应的指针指向map.end();

    使用下标操作找到对应的value,如果需要找的key不在map里面,就会自动将可以保存起来,默认初始化,比如map里面没有1,执行下标操作map[1]之后,map里面就会有 1.

    insert插入和make_pair组合使用。

    /**
     * Definition for undirected graph.
     * struct UndirectedGraphNode {
     *     int label;
     *     vector<UndirectedGraphNode *> neighbors;
     *     UndirectedGraphNode(int x) : label(x) {};
     * };
     */
    class Solution {
    public:
        UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
            if(node == NULL){
                return NULL;
            }
            vector<UndirectedGraphNode *> qNode;
            unordered_map<UndirectedGraphNode *,UndirectedGraphNode *> Map;
            qNode.push_back(node);
            Map.insert(make_pair(node,new UndirectedGraphNode(node -> label)));
            int start = 0;
            //clone nodes
            while(start < qNode.size()){
                UndirectedGraphNode *cur = qNode[start];
                for(int i= 0;i < cur -> neighbors.size();++i){
                    if(Map.find(cur -> neighbors[i]) == Map.end()){
                        qNode.push_back(cur -> neighbors[i]);
                        Map.insert(make_pair(cur -> neighbors[i],
                                             new UndirectedGraphNode(cur -> neighbors[i] -> label))); 
                      
                    }
                   
                }
                ++start;
            }
            
           // clone neighbors
            for(int j = 0;j < qNode.size();++j){
                for(int k = 0;k < qNode[j] -> neighbors.size();++k){
                   // UndirectedGraphNode *tmp = new UndirectedGraphNode(qNode[j] -> neighbors[k] -> label);
                    Map[qNode[j]] -> neighbors.push_back(Map[qNode[j] -> neighbors[k]]);
                }
            }
            return Map[node];
            
        }
    };
    clone graph

     1.2 Topological Sorting

    http://www.lintcode.com/en/problem/topological-sorting/

    思路:三步走:

    1)不断统计每个节点的入度,如果节点已经存在map里面,就执行增1操作,如果不在,就创建一个节点

    2)找到入度为零的点,记得必须要从neighbor数组里面进行统计,这样才能得到链接关系。

    3)不断的删除入度,将删除后入度为零的点加入到结果中,直到队列为空为止

    /**
     * Definition for Directed graph.
     * struct DirectedGraphNode {
     *     int label;
     *     vector<DirectedGraphNode *> neighbors;
     *     DirectedGraphNode(int x) : label(x) {};
     * };
     */
    class Solution {
    public:
        /**
         * @param graph: A list of Directed graph node
         * @return: Any topological order for the given graph.
         */
        vector<DirectedGraphNode*> topSort(vector<DirectedGraphNode*> graph) {
            // write your code here
            //统计每个结点的入度
            vector<DirectedGraphNode*> result;
            unordered_map<DirectedGraphNode*,int> Map;
            for(DirectedGraphNode* node : graph){
                for(DirectedGraphNode* neigh : node -> neighbors)
                if(Map.find(neigh) != Map.end()){
                    Map[neigh] = Map[neigh] + 1;
                }
                else{
                    Map.insert(make_pair(neigh,1));
                }
            }
            //找入度为零的节点
            queue<DirectedGraphNode*> q;
            for(DirectedGraphNode* tmp : graph){
                if(Map[tmp] == 0){
                    q.push(tmp);
                    result.push_back(tmp);
                }
            }
            //不断删除入度
            while(!q.empty()){
                DirectedGraphNode* tmp = q.front();
                q.pop();
                for(DirectedGraphNode* neigh : tmp -> neighbors){
                    Map[neigh] = Map[neigh] - 1;
                    if(Map[neigh] == 0){
                        q.push(neigh);
                        result.push_back(neigh);
                    }
                }
            }
        return result;
        }
    };
    topological sorting

    2.DFS 解决搜索all的问题,只要求所有方案的,肯定是排列组合的搜索问题,搜索问题都是递归求解。

     Permutations排列问题的时间复杂度是n!(选第一个有n种情况,第二个有n-1种情况。。。。。)。需要将所有情况都走一遍的程序算法时间复杂度都是n!。

    subsets复杂度分析:每个元素有选和不选两种选择,所以是2^n。

    2.1  46. Permutations

    https://leetcode.com/problems/permutations/#/description

    思路:使用helper函数,这里使用一个整数n,递归的时候作为递归基,n = 0的时候,说明每个数都已经排列完了,就可以作为一次排列结果压入result中,for循环是关键,每次交换一次数,调用递归之后,需要将刚才调用的数交换回来。理解时候,可以先不管递归,先理一遍for循环,就可以知道第一个数放置的排列情况。

    记住为什么这里是start + 1,而下面的subsets是i + 1?

    答:permutations每次都是后面n - 1 个元素的全排列,比如[1,2,3],第一位是1的时候,求2,3;第一位是2的时候,求1,3;第一位是3的时候,求1,2.

    subsets中每次都是固定前面i个元素,求后面i - 1个元素的子集,前面是1的时候,求2,3的子集,前面是1,2的时候,求3的子集,所以是i  + 1。

    permutation一共运行sz次。

    permutation从0开始到end,subsets从i + 1 ~end。

    class Solution {
    public:
        void helper(vector<vector<int>>& result,vector<int>& nums,int n){
            if(n == 0){
                result.push_back(nums);
            }
            for(int i =0;i <= n;++i){
                swap(nums[i],nums[n]);
                helper(result,nums,n - 1);
                swap(nums[n],nums[i]);
            }
        }
        vector<vector<int>> permute(vector<int>& nums) {
            vector<vector<int>> result;
            if(nums.size() == 0){
                return result;
            }
            helper(result,nums,nums.size() - 1);
            return result;
        }
    };
    permutations

     2.2 78. Subsets

    https://leetcode.com/problems/subsets/#/description

    思路:更正不需要先排序。

    首先要对数组排序,每次将比前面数大的数字加入到tmp数组里面,然后递归,接下来pop_back还原(pop_back可以将vector最后一个元素删掉)

    helper中记住一定是i+1,而不是start + 1;因为在同一个循环当中,start值是不变的,这样就会使得递归次数变多,所以必须是i+1;注意!!start + 1使得循环次数要多很多,所以必须要使用 i + 1;

    每个元素可以选也可以不选,时间复杂度是O(2^n);

    class Solution {
    public: 
    
        void helper(vector<vector<int>>& result,vector<int>& nums,vector<int>& subset,int start){        
            result.push_back(subset);        
            for(int i = start;i < nums.size();++i){
                subset.push_back(nums[i]);
                helper(result,nums,subset,i + 1);
                subset.pop_back();
            }
        }
       
        vector<vector<int>> subsets(vector<int>& nums) {
            vector<vector<int>> result;
            if(nums.size() == 0){
                return result;
            }
            vector<int> subset;
            sort(nums.begin(),nums.end());       
            helper(result,nums,subset,0);
            return result;
        }
    };
    subsets

     2.3 90. Subsets II

    https://leetcode.com/problems/subsets-ii/#/description

    s思路:1)该题需要一步一步的理清楚,helper(result,nums,tmp,i + 1);//这里记住是i+1,不要写成start+ 1;(因为在同一个循环当中,start值是不变的,这样就会使得递归次数变多,所以必须是i+1;)

    2)

    if(i != start && nums[i] == nums[i -1]){
      continue;
    }

    对于有重复元素的处理一定需要排序。

    去重的方法,有重复元素就跳过,进行下一次循环。举例{1,2,2}的集合一个元素的情况。

    class Solution {
    public:
        void helper(vector<vector<int>>& result,vector<int>& nums,vector<int>& tmp,int start){
            result.push_back(tmp);
            for(int i = start;i < nums.size();++i){
                if(i != start && nums[i] == nums[i -1]){
                    continue;
                }
                tmp.push_back(nums[i]);
                helper(result,nums,tmp,i + 1);//这里记住是i+1,不要写成start+ 1;
                cout << i + 1 << " ";
                tmp.pop_back();
            }
        }
        vector<vector<int>> subsetsWithDup(vector<int>& nums) {
            vector<vector<int>> result;
            if(nums.size() == 0){
                return result;
            }
            
            vector<int> tmp;
            int start = 0;
            sort(nums.begin(),nums.end());
            helper(result,nums,tmp,start);
            return result;
        }
    };
    subsets ii

     2.4 permutations II

    https://leetcode.com/problems/permutations-ii/#/description

    思路:综合permutation I和subsets II的去重方法,定义一个visit矩阵,

    需要处理的情况是:我们先把Num排序,然后只能连续地选,这样就可以避免生成重复的solution.
    例子:1 2 3 4 4 4 5 6 7 8
    444这个的选法只能:4, 44, 444连续这三种选法

    我们用一个visit的数组来记录哪些是选过的。

     if(i != 0 && nums[i] == nums[i - 1] && visit[i - 1] == 0 || visit[i] == 1){
                    continue;
      }
    i != 0才能保证后面判断 i - 1有效,nums[i] == nums[i - 1]前后两个元素相等才需要进行判断,visit[i - 1] == 0,第i - 1个元素没被访问,必须退出。前面属于一种情况,第二种情况就是
    visit[i] == 1,这个时候该元素已经被访问了,就不需要计算,进入下一次循环。
    class Solution {
    public:
        void helper(vector<vector<int>>& result,vector<int>& nums,vector<int>& tmp,vector<int>& visit){
            
            if(tmp.size() == nums.size()){
                result.push_back(tmp);            
            }
            for(int i = 0;i <= nums.size() - 1;++i){
                if(i != 0 && nums[i] == nums[i - 1] && visit[i - 1] == 0 || visit[i] == 1){
                    continue;
                }
                visit[i] = true;
                tmp.push_back(nums[i]);
                helper(result,nums,tmp,visit);
                tmp.pop_back();
                visit[i] = false;
            }
        }
        vector<vector<int>> permuteUnique(vector<int>& nums) {
            vector<int> visit(nums.size(),0);
            vector<vector<int>> result;
            vector<int> tmp;
            if(nums.size() == 0){
                return result;
            }
            sort(nums.begin(),nums.end());
            helper(result,nums,tmp,visit);
            return result;
        }
    };
    permutations II

    这里深入理解下permutation I 和permutation II,只记第二个有重复元素的版本就可以了

    排列合模板总结
    使用范
    几乎所有的搜索问题
    根据具体目要求行改
    什么
    哪些情况需要跳

     2.5 N Queens N皇后问题

    https://leetcode.com/problems/n-queens/#/description

    思路:就是看成permutation那道题,求排列,把n个皇后看成n个数,每种排列就是一个皇后放置的方案,比如n = 4,那么vector<int> row{1,2,3,4}这种排列就代表皇后的放置方案中的一种可能结果,row[0] = 1,表示在第0行第1列放置一个皇后,row的大小代表行数。

    1)何时将当前排列压入结果中??

    使用一个判断函数isValid函数:这里需要注意为什么rows =  cols.size(),不需要减1操作,因为我们进行检查合法性操作的时候,肯定是要新建一行,就是判断下一行是否在column列rows行是否可以插入操作。所以不要rows减1;

    bool isValid(vector<int>& cols,int column){//检查当前位置元素是否和已经放置的皇后冲突
            int rows = cols.size();
            for(int rowIndex = 0;rowIndex < rows;++rowIndex){
                if(cols[rowIndex] == column){//列冲突
                    return false;
                }
                if(rowIndex + cols[rowIndex] == rows + column){//当前行已经放置皇后,检查下一行,所以rows不需要减1操作
                    return false;//left上角 -> right下角对角线冲突
                }
                if(rowIndex - cols[rowIndex] == rows - column){//left下角 -> right上角对角线冲突
                    return false;
                }
                
            }
            return true;
        }

    然后再写一个转化结果的字符串函数,使用字符串的append操作。

    cols[column]等于放置皇后的那一列,看哪一列等于皇后所在列就置为Q,其他的都是空格。
    vector<string> toStr(vector<int>& cols){
            vector<string> resultRow;
            for(int column = 0;column < cols.size();++column){
                string s;
                for(int j = 0;j < cols.size();++j){                
                    j == cols[column] ? s.append("Q") : s.append(".");
                }
                resultRow.push_back(s);
            }
            return resultRow;
        }
    class Solution {
    public:
        vector<string> toStr(vector<int>& cols){
            vector<string> resultRow;
            for(int column = 0;column < cols.size();++column){
                string s;
                for(int j = 0;j < cols.size();++j){                
                    j == cols[column] ? s.append("Q") : s.append(".");
                }
                resultRow.push_back(s);
            }
            return resultRow;
        }
        bool isValid(vector<int>& cols,int column){//检查当前位置元素是否和已经放置的皇后冲突
            int rows = cols.size();
            for(int rowIndex = 0;rowIndex < rows;++rowIndex){
                if(cols[rowIndex] == column){//列冲突
                    return false;
                }
                if(rowIndex + cols[rowIndex] == rows + column){//当前行已经放置皇后,检查下一行,所以rows不需要减1操作
                    return false;//left上角 -> right下角对角线冲突
                }
                if(rowIndex - cols[rowIndex] == rows - column){//left下角 -> right上角对角线冲突
                    return false;
                }
                
            }
            return true;
        }
        void helper(vector<vector<string>>& result,vector<int>& cols,int n){
            if(n == cols.size()){
                result.push_back(toStr(cols));
            }
            for(int column = 0;column < n;++column){
                if(!isValid(cols,column)){
                    continue;
                }
                //接下来的push_back是对下一行进行操作放置皇后,新增加一行,新增加一个皇后才需要进行合法性判断
                cols.push_back(column);
                helper(result,cols,n);
                cols.pop_back();
            }
        }
        vector<vector<string>> solveNQueens(int n) {
            vector<vector<string>> result;
            if(n == 0){
                return result;
            }
            vector<int> cols;   
            helper(result,cols,n);
            return result;        
        }
    };
    N Queens
    if(judge(tmp,tmp.size(),vec[i]) == false){
    //这里传tmp.size()而不是i,因为要保证是全排列,如果从i开始就得不到全排列,因为每次i都是从i = 0开始,
    所以,这次i = 3不符合条件,下次会找到3的防止位置
    continue; }

    2.6 Palindrome Partitioning

    https://leetcode.com/problems/palindrome-partitioning/#/description

    将一个字符串拆分为回文子串,求出所有的可能结果。

    思路:类比permutation思路,主要两个地方1)string subStr = s.substr(start,i + 1 - start);//start开始的i + 1 - start个元素

    2)

    if(start == s.size()){//如果是s.size() - 1那么最后一个元素就会丢掉
    result.push_back(tmp);
    return;
    }

    这又是一道需要用DFS来解的题目,既然题目要求找到所有可能拆分成回文数的情况,那么肯定是所有的情况都要遍历到,对于每一个子字符串都要分别判断一次是不是回文数,那么肯定有一个判断回文数的子函数,还需要一个DFS函数用来递归,再加上原本的这个函数,总共需要三个函数来求解。代码如下:

    class Solution {
    public:
        bool isPalindrome(string s){
            int i = 0,j = s.size() - 1;
            for(i,j;i < j;++i,--j){
                if(s[i] != s[j]){
                    return false;
                }
            }
            return true;
        }
        void helper(vector<vector<string>>& result,string s,vector<string>& tmp,int start){
            if(start == s.size()){//如果是s.size() - 1那么最后一个元素就会丢掉
                result.push_back(tmp);
                return;
            }
            for(int i = start;i <= s.size() - 1;++i){
                string subStr = s.substr(start,i + 1 - start);//start开始的i + 1 - start个元素
                if(!isPalindrome(subStr)){
                    continue;
                }
                tmp.push_back(subStr);
                helper(result,s,tmp,i + 1);
                tmp.pop_back();
            }
        }
        vector<vector<string>> partition(string s) {
            vector<vector<string>> result;
            if(s.size() == 0){
                return result;
            }        
            vector<string> tmp;
            helper(result,s,tmp,0);
            return result;
        }
    };
    131. Palindrome Partitioning

    2.7 39. Combination Sum

    https://leetcode.com/problems/combination-sum/#/description

    数组中没有重复的元素,数组中元素可以使用多次,找到所有相加等于目标元素的集合。

    思路:这题没说给定的数组是否有序,所以需要先对数组排序。如果数组中有重复元素,每个答案中不能有重复元素,那么就需要数组去重的方法,就是使用两个i,j,类比双指针套路;

       第一点是记住每次递归的时候需要target - candidates[i],压入结果的条件是target减到0,,

       第二个很重要的点就是

    if(target < candidates[i]){//这句很关键,不写的话没法target会小于0没法==0,超时。
                    break;
                }这个是退出条件
    第三个点就是helper(result,candidates,tmp,target - candidates[i],i);里面的i作为下一次的start,这里一定要想通,每次找候选数字,找到之后前面的数字肯定是没用的了,而该题每个答案是允许1,1,11,
    这样的重复元素出现的,就是说每个数字可以使用多次,所以不需要i + 1,而是start = i;
    for(int i = start;i < candidates.size();++i){
                if(target < candidates[i]){//这句很关键,不写的话没法target会小于0没法==0,超时。
                    break;
                }
                tmp.push_back(candidates[i]);
                helper(result,candidates,tmp,target - candidates[i],i);
                tmp.pop_back();
            }
    class Solution {
    public:
        void helper(vector<vector<int> >& result,vector<int>& candidates,vector<int>& tmp,int target,int start){
            if(target == 0){
                result.push_back(tmp);
                return;
            }
            for(int i = start;i < candidates.size();++i){
                if(target < candidates[i]){//这句很关键,不写的话没法target会小于0没法==0,超时。
                    break;
                }
                tmp.push_back(candidates[i]);
                helper(result,candidates,tmp,target - candidates[i],i);
                tmp.pop_back();
            }
        }
        vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
            vector<vector<int> > result;
            if(candidates.size() == 0){
                return result;
            }
            vector<int> tmp;  
            sort(candidates.begin(),candidates.end());//没说明数组是否有序,所以需要排序,如果说重复元素,还需要将数组去重
            helper(result,candidates,tmp,target,0);
            return result;
        }
    };
    conbination sum

    2.8 40. Combination Sum II

    https://leetcode.com/problems/combination-sum-ii/#/description

    每个元素只能使用一次,找到所有组合等于target的元素集合。

    思路:这题在上面的题目的基础上,结合了permutation II的重复元素处理方法,这题是给定的数组里面就有重复元素,但是数组中每个元素只能使用一次,使用一次的题目递归的start就必须每次i + 1,  helper(result,candidates,tmp,target - candidates[i],i + 1,visited);

    这题做个总结:给定的数组有重复元素,每次是对剩下的元素进行运算,那么就应该考虑当前元素和之前一个元素是否相当,相等就跳过。

    permutation II是每次都要从头开始考虑整个数组的全排列,所以需要一个visited数组,判断当前元素是否已经排列过,subsets II是剩下的数组元素进行考虑每次 start = i + 1,所以不需要维护一个visited数组,这题也是对剩下元素进行操作,所以和subsets II很像,当然permutation II是都可以的方法。permutation II的if判断方法包含所有的情况,是万能方法。

     if( candidates[i - 1] == candidates[i] && i != start){
                    continue;//permutation II有重复元素的排列
                }
    class Solution {
    public:
        
        void helper(vector<vector<int>>& result,
                    vector<int>& candidates,
                    vector<int>& tmp,
                    int target,int start,
                    vector<int>& visited){
            if(target == 0){
                result.push_back(tmp);
            }
            for(int i = start;i < candidates.size();++i){
                if(target < candidates[i]){
                    break;
                }
                if(visited[i] == 1 || visited[i] == 0 && candidates[i - 1] == candidates[i] && i != start){
                    continue;//permutation II有重复元素的排列
                }
                visited[i] = 1;
                tmp.push_back(candidates[i]);
                helper(result,candidates,tmp,target - candidates[i],i + 1,visited);
                tmp.pop_back();
                visited[i] = 0;
            }
        }
        vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
            vector<vector<int>> result;
            if(candidates.size() == 0){
                return result;
            }
            vector<int> tmp,reDupCan;
            vector<int> visited(candidates.size(),0);
            int start = 0;
            sort(candidates.begin(),candidates.end());       
            helper(result,candidates,tmp,target,start,visited);
            return result;
        }
    };
    combination sum II使用permutation II的判断方法
    class Solution {
    public:
        
        void helper(vector<vector<int>>& result,
                    vector<int>& candidates,
                    vector<int>& tmp,
                    int target,int start
                    ){
            if(target == 0){
                result.push_back(tmp);
            }
            for(int i = start;i < candidates.size();++i){
                if(target < candidates[i]){
                    break;
                }
                if( candidates[i - 1] == candidates[i] && i != start){//每次是对剩下的那部分进行运算
                    continue;//subsets II有重复元素的排列
                }            
                tmp.push_back(candidates[i]);
                helper(result,candidates,tmp,target - candidates[i],i + 1);
                tmp.pop_back();
                
            }
        }
        vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
            vector<vector<int>> result;
            if(candidates.size() == 0){
                return result;
            }
            vector<int> tmp,reDupCan;        
            int start = 0;
            sort(candidates.begin(),candidates.end());       
            helper(result,candidates,tmp,target,start);
            return result;
        }
    };
    使用subsets II 的if判断方法

     3、BFS宽度优先搜索

    从起始状态A变化到目标状态B,最小需要多少步,使用BFS求解。

    求最短是多少使用BFS;

    求所有的最短是多少使用DFS。

    广度优先搜索时间复杂度和答案个数有密切关系,O(X * N + m),其中X是答案个数,N是总的节点数,m是BFS中访问的节点数目。

    3.1 127. Word Ladder

    https://leetcode.com/problems/word-ladder/#/description3

    有一个起始单词变为目标单词,要求中间变化使用指定集合的元素。求出路径的长度。

    思路:类比二叉树的层次遍历,主程序是差不多的,要注意的第一点是length初始化为1,不存在转化路径的时候返回0,题目中已经给出了,第二点是对于每个初始字符,要找到词典中和他相差一个编辑距离的单词,然后看这些单词是否已经访问或者是endword,如果不是就压入queue和unordered_set。

    class Solution {
    public:
        vector<string> getString(string word,unordered_set<string>& wordListSet){//找到词典中对应Word一个距离的所有单词
            vector<string> result;
            for(char c = 'a';c <= 'z';++c){
                for(int i = 0;i < word.size();++i){
                    string s = word;                
                    if(c == s[i]){
                        continue;
                    }
                    s[i] = c;
                    if(wordListSet.find(s) != wordListSet.end()){
                        result.push_back(s);
                    }
                }
            }
            return result;
        }
        int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
            if(wordList.size() == 0){
                return 0;
            }
            if(beginWord == endWord){
                return 1;//读题,没转化数的时候才返回0
            }
            // wordList.push_back(beginWord);
            // wordList.push_back(endWord);//必须利用list中的单词进行转化,start和end不一定在list中,如果end不在list中,肯定不能进行转化得到
            unordered_set<string> hash,wordListSet;
            queue<string> q;
            hash.insert(beginWord);
            q.push(beginWord);
            for(string s : wordList){
                wordListSet.insert(s);
            }
            int length = 1;//从1开始,
            while(!q.empty()){
                ++length;
                int size = q.size();
                for(int i = 0;i < size;++i){
                    string tmp = q.front();
                    q.pop();
                    for(string s : getString(tmp,wordListSet)){
                        if(hash.count(s) != 0){
                            continue;
                        }
                        if(s == endWord){//从1开始,则上一层就是路径长度,这时候q不包含endWord(s)
                            return length;
                        }
                        hash.insert(s);
                        q.push(s);
                    }
                }
            }
            return 0 ;
            
        }
    };
    Word Ladder

     3.2 126. Word Ladder II

    https://leetcode.com/problems/word-ladder-ii/#/description

    思路:这道题目太难,主要看思路。给出所有的路径。

    使用BFS从end到start进行,如果按照正常的方法从start找end,然后根据这个来构造路径,代价会比较高,因为保存前驱结点容易,而保存后驱结点则比较困难。所以我们在广度优先搜索时反过来先从end找start,最后再根据生成的前驱结点映射从start往end构造路径,这样算法效率会有明显提高。

  • 相关阅读:
    Linux特殊权限分析(第二版)
    Linux用户配置文件(第二版)
    Vim/Vi实用技巧(第二版)
    Vim/Vi常用操作(第二版)
    GRUB与Linux系统修复(第二版)
    inittab文件剖析[CentOS 5.X](第二版)
    CentOS 6.X启动流程
    /etc/fstab文件出错,无法进入Linux系统
    Linux引导流程(第二版)
    Linux备份策略(第二版)
  • 原文地址:https://www.cnblogs.com/dingxiaoqiang/p/7132073.html
Copyright © 2011-2022 走看看