【刷题打卡】1048. 最长字符串链

150 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

一、题目描述:

1048. 最长字符串链 - 力扣(LeetCode) (leetcode-cn.com)

给出一个单词数组 words ,其中每个单词都由小写英文字母组成。

如果我们可以 不改变其他字符的顺序 ,在 wordA 的任何地方添加 恰好一个 字母使其变成 wordB ,那么我们认为 wordA 是 wordB 的 前身 。

  • 例如,"abc" 是 "abac" 的 前身 ,而 "cba" 不是 "bcad" 的 前身

词链是单词 [word_1, word_2, ..., word_k] 组成的序列,k >= 1,其中 word1 是 word2 的前身,word2 是 word3 的前身,依此类推。一个单词通常是 k == 1 的 单词链 。

从给定单词列表 words 中选择单词组成词链,返回 词链的 最长可能长度 。  

示例 1:

输入:words = ["a","b","ba","bca","bda","bdca"]
输出:4
解释:最长单词链之一为 ["a","ba","bda","bdca"]

示例 2:

输入:words = ["xbc","pcxbcf","xb","cxbc","pcxbc"]
输出:5
解释:所有的单词都可以放入单词链 ["xb", "xbc", "cxbc", "pcxbc", "pcxbcf"].

示例 3:

输入:words = ["abcd","dbqca"]
输出:1
解释:字链["abcd"]是最长的字链之一。
["abcd""dbqca"]不是一个有效的单词链,因为字母的顺序被改变了。

提示:

  • 1 <= words.length <= 1000
  • 1 <= words[i].length <= 16
  • words[i] 仅由小写英文字母组成。

二、思路分析:

  1. 首先对输入words按长度进行升序排序,保证从前往后找的顺序
  2. 动态规划方程,如果words[j]是words[i]的前身,dp[i] = dp[j] + 1,j < i 且 words[j].size + 1 == words[i].size
  3. 针对每一个i,遍历比i小的字符串j,检查words[j]是否满足words[i]的前身,进行状态转移

三、AC 代码:

class Solution {
public:
    bool check(string& a, string& b) {
        int index = 0;
        int n = b.size();
        bool flag = false;
        for (int i = 0; i < a.size(); i++) {
            if (index < n && a[i] == b[index]) {
                index++;
            } else {
                if (flag) {
                    return false;
                }
                flag = true;
            }
        }
        return true;
    }
    int longestStrChain(vector<string>& words) {
        int n = words.size();
        sort(words.begin(), words.end(), [](string& a, string& b) {
            return a.length() < b.length();
        });
        vector<int> dp(n, 1);
        int index = 0; // 记录j的下一次起始位置,没必要每次从0开始遍历,尽量从长度等于words[i].size() - 1开始遍历,对于长度小于words[i].size() - 1的部分不需要再考虑,减少check的次数
        int ans = 1;
        for (int i = 1; i < n; i++) {
            for (int j = index; j < i; j++) {
                if (words[i].size() == words[j].size() + 1) {
                    if (check(words[i], words[j])) {
                        dp[i] = max(dp[i], dp[j] + 1);
                    }
                } else if (words[i].size() > words[j].size() + 1) {
                    index++;
                } else {
                    break;
                }
            }
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};