472 Concatenated Words

472 Concatenated Words




题目链接:472 Concatenated Words



题意

给定一个字符串数组(vector),要求找出当中所有能被数组中其他多于一个字符串组成的字符串


解法

  • 构建字典树,每个字符串对应字典树中的一条路径,这条路径不必以叶子节点结尾,因为不同字符串可能共享一条路径的一部分,比如“cat”和“cats”,所以在字典树节点类中增加一个bool字段isEnd。
  • 要查询一个字符串是否可以由字典树中的多个字符串拼接而成,用一个下标current指向字符串当前的字符,用计数器count记录目前子串可以拆分成多少个字符串,查询每次都从树的根节点开始

    • 如果当前节点没有current指向的字符对应的子节点,返回false
    • 如果有对应的子节点,判断该节点是否是一条路径的终点,即判断该节点的isEnd字段
      • 如果isEnd为假,只需将当前节点迭代为该子节点,并且下标current自增
      • 如果isEnd为真,首先判断current是否已经到达字符串末尾
        • 如果是,返回计数器是否大于0的结果
        • 否则,面临两个选择,一是沿着这条路径访问下个节点,二是重新从根节点开始访问,这两种情况都有可能,比如字典中已经有cat,dog,catdog,如果要查询catdogcat,则对应第一种情况,如果要查询catdog,则对应第二种情况,所以这里使用深度优先搜索试着迭代一次,如果成功直接返回true,否则沿着当前路径继续搜索。
  • 总体步骤如下:

    1. 将所有字符串添加到字典树中
    2. 再次遍历数组中所有字符串,对于每个字符串,查询是否可以由字典树中多个字符串拼接而成




代码

#include<iostream>
#include<vector>
#include<string>
#include<map>
using namespace std;

class DictNode {
public:
    bool isEnd;
    map<char, DictNode*> next;
    DictNode() {
        isEnd = false;
    }
};

class Solution {
public:
    DictNode *root;
    vector<string> findAllConcatenatedWordsInADict(vector<string>& words) {
        vector<string> result;
        root = new DictNode();
        for (string word : words)
            add(word);

        for (string word : words) {
            if (canResolve(word, 0, 0)) {
                result.push_back(word);
            }
        }
        return result;
    }

    void add(string word) {//为word在字典树中构建一条路径
        DictNode *node = root;
        for (int current = 0; current < word.length(); ++current) {
            if (node->next.find(word[current] ) == node->next.end())
                node->next[word[current]] = new DictNode();
            node = node->next[word[current]];
        }
        node->isEnd = true;//标出字符串路径终点
    }

    bool canResolve(string word, int current, int count) {
        if (word == "catsdogcats")
            int r = 0;

        DictNode *node = root;

        for (int i = current; i < word.length(); ++i) {
            if (node->next.find(word[i])==node->next.end())
                return false;
            if (node->next[word[i]]->isEnd) {
                if (i == word.length() - 1) {
                    return count >= 1;
                }
                if (canResolve(word, i + 1, count + 1)) {//深度优先搜索迭代判断
                    return true;
                }
            }
            node = node->next[word[i]];
        }
        return false;
    }
};




算法复杂度

算法复杂度为O(nm)。n为数组长度,m为数组中字符串平均长度。




注意

字典树节点表示子节点的数据结构如果简单地选择节点指针数组,那么在面对比如a,aa,aaa,aaaa…这种字典树退化成链表的情况可能会出现超出内存限制的问题,所以最好方便点办法是使用map存储子节点指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值