C++ 什么';该算法获取所有单词阶梯的时间复杂度是多少?

C++ 什么';该算法获取所有单词阶梯的时间复杂度是多少?,c++,algorithm,big-o,depth-first-search,breadth-first-search,C++,Algorithm,Big O,Depth First Search,Breadth First Search,字梯 给定两个单词(开始和结束)和一本字典,全部查找 从开始到结束的最短转换序列, 这样:一次只能更改一个字母,每个中间词必须存在于词典中 例如,给定:start=“命中”end=“重心”dict=[“热点”、“点”、“狗”、“批次”、“日志”]返回 [ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ] 注意:所有单词的长度都相同。所有单词只包含小写字母 我个人认为,该算法的时间复杂度取决于 输入

字梯
给定两个单词(开始和结束)和一本字典,
全部查找 从开始到结束的最短转换序列,
这样:
一次只能更改一个字母,每个中间词必须存在于词典中

例如,
给定:start=“命中”
end=“重心”
dict=[“热点”、“点”、“狗”、“批次”、“日志”]
返回

[ 
  ["hit","hot","dot","dog","cog"], 
  ["hit","hot","lot","log","cog"]
]
注意:
所有单词的长度都相同。
所有单词只包含小写字母


我个人认为,该算法的时间复杂度取决于 输入(开始、结束、记录)不能像时间复杂度那样写出= O(?)。
谢谢你。紧时间复杂性= O(len*N*(26^(N/2)),len是给定起始字符串的长度(或 结束字符串),n是DICT的元素数(假设C++) 无序_集由has集实现)。请查看下面的详细信息

此解决方案的想法:BFS(Map)+DFS。[C++]

#include <vector>
#include <unordered_map>
#include <deque>
#include <string>
using namespace std;

struct Node {
    string val;
    int level;
    vector<Node *> prevs;
    Node (string val, int level): val(val), level(level) {};
};

class Solution {
public:
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
    vector<vector<string>> list;

    // Input validation.
    if (start.compare(end) == 0) {
        vector<string> subList = {start, end};
        list.push_back(subList);
        return list;
    }

    deque<string> queue;
    unordered_map<string, Node *> map;

    queue.push_back(start);
    Node *start_node = new Node(start, 0);
    map.emplace(start, start_node);

    while (!queue.empty()) {
        // Dequeue.
        string curr_string = queue.front();
        queue.pop_front();

        Node *curr_node = map.find(curr_string)->second;
        int curr_level = curr_node->level;

        int len = curr_string.length();

        if (curr_string.compare(end) == 0) {
            // Find the end.
            vector<string> subList;
            subList.push_back(curr_node->val);

            getAllPathes(curr_node, list, subList);

            return list;
        }

        // Iterate all children.
        for (int i = 0; i < len; i ++) {
            char curr_original_char = curr_string[i];

            // Have a try.
            for (char c = 'a'; c <= 'z'; c ++) {
                if (c == curr_original_char) continue;
                curr_string[i] = c;

                if (dict.find(curr_string) != dict.end()) {
                    if (map.find(curr_string) == map.end()) {
                        // The new string has not been visited.
                        Node *child = new Node(curr_string, curr_level + 1);

                        // Add the parents of the current into prevs.
                        child->prevs.push_back(curr_node);

                        // Enqueue.
                        queue.push_back(curr_string);
                        map.emplace(curr_string, child);
                    } else {
                        // The new string has been visited.
                        Node *child = map.find(curr_string)->second;

                        if (child->level == curr_level + 1) {
                            child->prevs.push_back(curr_node);
                        }
                    }
                }
            }

            // Roll back.
            curr_string[i] = curr_original_char;
        }
    }

    return list;
}

void getAllPathes(Node *end, vector<vector<string>> &list, vector<string> &subList) {
    // Base case.
    if (end == NULL) {
        // Has been get to the top level, no topper one.
        vector<string> one_rest(subList);
        list.push_back(one_rest);
        return;
    }

    vector<Node *> prevs = end->prevs;

    if (prevs.size() > 0) {
        for (vector<Node *>::iterator it = prevs.begin();
             it != prevs.end(); it ++) {

            // Have a try.
            subList.insert(subList.begin(), (*it)->val);         

            // Do recursion.
            getAllPathes((*it), list, subList);

            // Roll back.
            subList.erase(subList.begin());
        }

    } else {
        // Do recursion.
        getAllPathes(NULL, list, subList);
    }
}
};
#包括
#包括
#包括
#包括
使用名称空间std;
结构节点{
字符串val;
智力水平;
向量预测;
节点(字符串val,int-level):val(val),level(level){};
};
类解决方案{
公众:
矢量查找加法器(字符串开始、字符串结束、无序集合和dict){
向量表;
//输入验证。
如果(开始比较(结束)==0){
向量子列表={start,end};
列表。推回(子列表);
退货清单;
}
排队;
无序地图;
队列。推回(启动);
Node*start\u Node=新节点(start,0);
映射放置(开始,开始节点);
而(!queue.empty()){
//下队。
字符串curr_string=queue.front();
queue.pop_front();
Node*curr\u Node=map.find(curr\u字符串)->秒;
int curr\u level=当前节点->级别;
int len=curr_string.length();
如果(当前字符串比较(结束)==0){
//找到终点。
向量子列表;
子列表。推回(当前节点->值);
GetAllPaths(当前节点、列表、子列表);
退货清单;
}
//迭代所有子项。
对于(int i=0;isecond;
如果(子->级别==当前级别+1){
子节点->上推后(当前节点);
}
}
}
}
//滚回去。
当前字符串[i]=当前原始字符;
}
}
退货清单;
}
void getAllPaths(节点*结束、向量和列表、向量和子列表){
//基本情况。
if(end==NULL){
//已经达到了最高水平,没有一流的。
向量1_rest(子列表);
列表。推回(剩余一个);
返回;
}
向量prevs=结束->上一个;
如果(上一个大小()>0){
for(vector::iterator it=prevs.begin();
it!=prevs.end();it++){
//试试看。
插入(subList.begin(),(*it)->val);
//执行递归。
getAllPaths((*it)、列表、子列表);
//滚回去。
subList.erase(subList.begin());
}
}否则{
//执行递归。
GetAllPaths(空、列表、子列表);
}
}
};
拆分 让我们将复杂性分为三部分:

  • 在转换序列中查找下一个单词
  • 最短变换序列的长度
  • 变换序列的个数
  • 假设 设
    n
    为给定单词的长度,设
    n
    为字典中的单词数。还假定字典已排序

    1.部分 然后你可以在
    O(n)中找到下一个单词⋅ 26⋅ log(N))=O(N log N)
    步骤

    • n
      单词中可以更改的字符
    • 26
      每个字符可能的更改
    • log(N)
      查找字典中是否存在该单词
    2.部分 最短的转换序列可以有多长

    示例:让起始词为“aa”,结束词为“zz”,字典
    [“ab”、“bb”、“bc”、“cc”、…]。
    这个例子需要26个转换,我认为你可以构建最坏情况下的输入,需要26n-1个转换

    但这取决于词典中的单词。因此最坏的情况是
    N
    ,即使用词典中的所有单词

    3.部分 存在多少不同的序列

    每次你在序列中寻找下一个单词时,都有可能找到26个不同的下一步。但只适用于最短序列长度的前半部分,因为如果你切换开始和结束单词,这也适用。因此最多可能有
    O(26N/2)
    不同的序列,只要最短序列的最坏情况长度是
    O(N)

    总结
    • O(n log n)
      查找序列中的下一个转换
    • O(N)
      每个序列的变换
    • O(26N/2)
      不同的序列
    您总共得到
    O(26N/2n log N)

    通知
    • 只有当您的字典可以包含任何字符序列作为“单词”时,这一点才成立。如果您只允许存在于真实语言中的单词,您可以使用统计数据来证明一个更好的方法