139. 单词拆分以及字符串递归经验-传入右子串-voiddfs与全局变量-booldfs-记忆递归booldfs写法

问题

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。

分析

拆分字符串,判断拆分得到的子串是否在dict中。显然,dfs,需要回溯。超时,需要记忆。递推还没想怎么写,不如递归好写。
经验:字符串与递归结合,将右子串作为参数即可,不需要左右边界

代码

// 返回值递归,比全局变量递归剪枝,35/47,加了记忆后如下,可以通过
class Solution {
public:
    int s_n = 0;
    vector<string> d;
    unordered_set<string> us;
    unordered_map<string, bool> mem;
    // 经验:字符串与递归结合,将右子串作为参数即可,不需要左右边界
    bool dfs(string left_s) {
        if (mem.find(left_s) != mem.end()) {return mem[left_s];}
        if (us.find(left_s) != us.end()) {mem.insert(make_pair(left_s, true)); return true;}
        int left_s_n = left_s.size();
        for (int i = 1; i <= left_s_n; i++) {
            if (us.find(left_s.substr(0, i)) != us.end()) {
                if (dfs(left_s.substr(i))) {
                    mem.insert(make_pair(left_s, true));
                    return true;
                };
                mem.insert(make_pair(left_s, false));
            }
        }
        return false;
    }
    bool wordBreak(string s, vector<string>& wordDict) {
        this->d = wordDict;
        s_n = s.size();
        for (int i = 0; i < wordDict.size(); i++) {
            us.insert(wordDict[i]);
        }
        bool res = dfs(s);
        return res;
    }
};

补一个全局变量递归。

// 法一、全局变量递归,最慢,35 / 47 个通过的测试用例
class Solution {
public:
    bool res = false;
    int s_n = 0;
    vector<string> d;
    unordered_set<string> us;
    void dfs(string left_s) {
        if (us.find(left_s) != us.end()) {res = true; return;}
        int left_s_n = left_s.size();
        for (int i = 1; i <= left_s_n; i++) {
            if (us.find(left_s.substr(0, i)) != us.end()) {
                dfs(left_s.substr(i));
            }
        }
    }
    bool wordBreak(string s, vector<string>& wordDict) {
        this->d = wordDict;
        s_n = s.size();
        for (int i = 0; i < wordDict.size(); i++) {
            us.insert(wordDict[i]);
        }
        dfs(s);
        return res;
    }
};

new

如果不传入右字串,传入要处理的起始位置,string设为全局变量,也是可以的。

从下面的例子来看void dfs()配合全局变量,到bool dfs(),再到记忆递归的bool dfs()的写法。

// void dfs()配合全局变量
class Solution {
private:
    int x = 0;
    unordered_map<string, int> um;
    int n = 0;
    string s;
    bool res = false;
    void dfs(int x) {
        if (x >= n) {res = true; return ;}
        for (int i = x; i < n; i++) {
            string t = s.substr(x, i-x+1);
            if (um.count(t)) {
                dfs(i+1);
            }
        }
    }
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        n = s.size();
        this->s = s;
        for (const string& a : wordDict) {
            um[a]++;
        }
        dfs(0);
        return res;
    }
};

修改返回值,同时dfs()改为if(dfs()) {return true;}

class Solution {
private:
    int x = 0;
    unordered_map<string, int> um;
    unordered_map<int, int> mem;
    int n = 0;
    string s;
    bool res = false;
    bool dfs(int x) {
        if (x >= n) {return true;} // 1 能走完全部s,说明可以分割,返回true
        for (int i = x; i < n; i++) {
            string t = s.substr(x, i-x+1);
            if (um.count(t)) {
                if (dfs(i+1)) {return true;} // 2 如果上层返回true了,这里应该直接返回true
            }
        }
        return false; // 3 不行了,上层也没有返回true,那就返回false
    }
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        n = s.size();
        this->s = s;
        for (const string& a : wordDict) {
            um[a]++;
        }
        res = dfs(0);
        return res;
    }
};

记忆递归的bool dfs()`的写法:

记录某个起点 x 是否“已经确定失败”,避免重复搜索。
mem[x] = 0:从 x 出发 无法拆分成功
mem[x] = 1:从 x 出发 可以拆分成功

class Solution {
private:
    int x = 0;
    unordered_map<string, int> um;
    unordered_map<int, bool> mem;
    int n = 0;
    string s;
    bool res = false;
    bool dfs(int x) {
        if (x >= n) {return true;}
        if (mem.count(x)) {return mem[x];}
        for (int i = x; i < n; i++) {
            string t = s.substr(x, i-x+1);
            if (um.count(t)) {
                if (dfs(i+1)) {
                    mem[x] = true;
                    return true;
                } else {
                    mem[x] = false;
                }
            }
        }
        return false;
    }
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        n = s.size();
        this->s = s;
        for (const string& a : wordDict) {
            um[a]++;
        }
        res = dfs(0);
        return res;
    }
};
posted @ 2025-06-20 22:22  saulstavo  阅读(28)  评论(0)    收藏  举报