• [LeetCode#127]Word Ladder


    ---恢复内容开始---

    The problem:

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

    1. Only one letter can be changed at a time
    2. Each intermediate word must exist in the dictionary

    For example,

    Given:
    start = "hit"
    end = "cog"
    dict = ["hot","dot","dog","lot","log"]

    As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
    return its length 5.

    Note:
    Return 0 if there is no such transformation sequence.
    All words have the same length.
    All words contain only lowercase alphabetic characters.

    My analysis:

    This problem's solution is very elegant and tricky! It represents a new kind of problem that could be solved by using abstract graph. 
    The key idea: use the graph to search. But it differs a lot from the previous problem, which has a obvious link or neighbor list of a node. We need to extract this information from a very tricky way. 
    The abstract graph:
    1. represent each String in the dictionary as a node in the graph.
    2. iff two nodes differ in only one character, there is a edge between those two nodes in the graph.
    
    The shortest problem in the grpah:(unweighted graph)
    The breadth first search could layered the nodes in the graph. 
    The path from source node to another node in the breadth first traversal is the shortest path from source node to the node. The distance is the layer the node in. 
    
    It seems that there is no linkage domain, how could we traversal?
    Since we have no link to follow, how about we try all possible pathes according to the requirement!
    The requirement: Only one letter can be changed at a time. It is not hard to simulate. 
    for (int i = 0; i < cur.length(); i++) {
        char[] cur_array = cur.toCharArray();
        for (char c = 'a'; c <= 'z'; c++) {
            cur_array[i] = c;
            String temp = new String(cur_array);
        ...
    }
    However, the while loop could result in all possbile branches(which only differ a character with the current node). We could only search along the edge that existed in the graph, we need to rule out some unreasonable branches.
    if (dict.contains(temp) && !visited.contains(temp)) {
        queue.offer(temp);
        visited.add(temp);
        next_num++;
    }
    
    What a beautful way!!!(fake traversal and rule out!)
    
    Note:
    the above rountine is for continue search, which means we have not reach out the "end(target)" String. However, if we reach the target, we could directly return the distance, cause the target need not to be in the dict. 
    for (int i = 0; i < cur.length(); i++) {
        char[] cur_array = cur.toCharArray();
        for (char c = 'a'; c <= 'z'; c++) {
            cur_array[i] = c;
            String temp = new String(cur_array); 
            if (temp.equals(end))
                return level + 1;
        ...
        }
    }
    
    The time complexity analysis:
    while (!queue.isEmpty()) {
        ...
        for (int i = 0; i < cur.length(); i++) {
        ...
            for (char c = 'a'; c <= 'z'; c++) {
            ...
                if (dict.contains(temp) && !visited.contains(temp)) {
                    queue.offer(temp);
                    visited.add(temp);
                    next_num++;
                }
            }
        }
    }
    The time complexity for the big for loop: Length * 26
    Since we use "dict.contains(temp)" to restrict searching domain. we enter the for loop at most. dict.size() times. 
    thus the total complexity is 
    size(dict) * length * 26
    
    Note:
    Be very careful with the function of "!visited.contains(temp)".
    Unlike Binary, there could be circle in the graph, thus we must use visted set to record all nodes we have visited. Otherwise it would result in infinite loop. Cause we keep on(there might be iterleaves) enqueuing and dequeing it. 

    My solution:

    public class Solution {
        public int ladderLength(String start, String end, Set<String> dict) {
            
            if (start == null || end == null || dict == null || start.length() == 0 || end.length() == 0 || dict.size() == 0)
                return 0;
            
            HashSet<String> visited = new HashSet<String> ();
            Queue<String> queue= new LinkedList<String> ();
            String cur;
            
            queue.offer(start);
            int cur_num = 1;
            int next_num = 0;
            int level = 1;
            
            while (!queue.isEmpty()) {
                cur = queue.poll();
                cur_num-- ; //only intermdiate string need to be in the dict.
                for (int i = 0; i < cur.length(); i++) {
                    char[] cur_array = cur.toCharArray();
                    for (char c = 'a'; c <= 'z'; c++) {
                        cur_array[i] = c;
                        String temp = new String(cur_array); //must do it in this way, only change one char a time. 
                        if (temp.equals(end))
                            return level + 1;
                        if (dict.contains(temp) && !visited.contains(temp)) {//very imprtant checking condition!!!
                            queue.offer(temp);
                            visited.add(temp);
                            next_num++;
                        }
                    }
                }
                
                if (cur_num == 0) {
                    cur_num = next_num;
                    next_num = 0;
                    level++;
                }
            }
            return 0;
        }
    }

    ---恢复内容结束---

  • 相关阅读:
    json针对list map set 应用
    数据转换与枚举
    override和overload的区别
    JAVA NIO 基础学习
    JavaScript ES6箭头函数指南
    Javascript 中的神器
    如何编写Hexo主题
    什么是闭包?闭包的优缺点?
    微信小程序封装http访问网络库实例代码
    微信小程序 生命周期函数详解
  • 原文地址:https://www.cnblogs.com/airwindow/p/4220300.html
Copyright © 2020-2023  润新知