LeetCode 3474. 字典序最小的生成字符串

LeetCode 3474. 字典序最小的生成字符串

题目描述

给你两个字符串,str1str2,其长度分别为 nm

如果一个长度为 n + m - 1 的字符串 word 的每个下标 0 <= i <= n - 1 都满足以下条件,则称其由 str1str2 生成:

如果 str1[i] == 'T',则长度为 m 的 子字符串(从下标 i 开始)与 str2 相等,即 word[i..(i + m - 1)] == str2

如果 str1[i] == 'F',则长度为 m 的 子字符串(从下标 i 开始)与 str2 不相等,即 word[i..(i + m - 1)] != str2

返回可以由 str1str2 生成 的 字典序最小 的字符串。如果不存在满足条件的字符串,返回空字符串 ""

如果字符串 a 在第一个不同字符的位置上比字符串 b 的对应字符在字母表中更靠前,则称字符串 a 的 字典序 小于 字符串 b

如果前 min(a.length, b.length) 个字符都相同,则较短的字符串字典序更小。

子字符串 是字符串中的一个连续、非空的字符序列。

思路分析

这道题属于字符串构造问题,关键在于同时满足多组"必须相等"和"必须不等"的约束。我们可以分两步解决:

  1. 强制满足所有 'T' 条件

    对于每个 s[i] == 'T',将 ans[i..i+m-1] 直接赋值为 t。如果不同位置要求冲突(比如同一个位置既要填 t[j] 又要填不同的字符),则直接无解。

  2. 处理所有 'F' 条件

    'T' 已经确定的基础上,先将未确定的位置(仍为 '?')填充为默认字符 'a',得到一个候选字符串。

    然后检查每个 'F' 位置:如果当前子串恰好等于 t,就说明违反了条件,需要破坏它。

    破坏的方法:从子串的末尾向前找到第一个原本是 '?' 的位置(即未被 'T' 强制固定的位置),将其改为 'b',这样该子串就不再等于 t

    如果找不到这样的位置(子串所有位置都被 'T' 锁死),则无解。

为什么从后向前找?因为后面的子串起始索引更大,修改靠后的位置对后续子串的影响最小,可以避免不必要的冲突。

代码实现

cpp 复制代码
class Solution {
public:
    string generateString(string s, string t) {
        int n = s.size(), m = t.size();
        string ans(n + m - 1, '?');   // 初始化全为 '?'

        // 步骤1:处理所有 'T' 条件
        for (int i = 0; i < n; ++i) {
            if (s[i] != 'T') continue;
            for (int j = 0; j < m; ++j) {
                char v = ans[i + j];
                if (v != '?' && v != t[j]) return ""; // 冲突
                ans[i + j] = t[j];
            }
        }

        string old_ans = ans;          // 记录哪些位置是原本由 'T' 确定的
        // 步骤2:默认填充 'a'
        for (char& c : ans) {
            if (c == '?') c = 'a';
        }

        // 步骤3:处理所有 'F' 条件
        for (int i = 0; i < n; ++i) {
            if (s[i] != 'F') continue;
            // 检查当前子串是否等于 t
            if (string(ans.begin() + i, ans.begin() + i + m) != t)
                continue;             // 已经满足,跳过

            bool same = false;
            // 从后向前找第一个原本为 '?' 的位置
            for (int j = i + m - 1; j >= i; --j) {
                if (old_ans[j] == '?') {
                    ans[j] = 'b';     // 改为 'b' 破坏匹配
                    same = true;
                    break;
                }
            }
            if (!same) return "";     // 无法破坏,无解
        }

        return ans;
    }
};

复杂度分析

  • 时间复杂度 :O(n·m)

    最坏情况下,每个 'T''F' 位置都需要遍历长度为 m 的子串。实际常数较小。

  • 空间复杂度 :O(n + m)

    存储 ansold_ans 字符串。

总结

本题通过先满足所有强制相等条件,再破坏所有强制不等条件的策略,利用贪心方法逐个解决冲突。关键在于:

  • 'T' 要求的子串直接填充,同时检测冲突。
  • 'F' 条件,仅当当前子串意外相等时才进行破坏,且破坏时优先选择原本可修改的位置。
  • 从后向前修改可以减少对其他条件的干扰。

这种方法简单直观,且能有效判断无解情况。

相关推荐
平行侠5 分钟前
A15 工业路由器IP前缀高速检索与内存压缩系统
网络·tcp/ip·算法
阿旭超级学得完1 小时前
C++11包装器(function和bind)
java·开发语言·c++·算法·哈希算法·散列表
li星野1 小时前
位运算 & 数学 & 高频进阶九题通关(Python + C++)
c++·python·学习·算法
jerryinwuhan1 小时前
hello算法,简单讲(1)
算法·排序算法
y = xⁿ2 小时前
20天速通LeetCodeday15:BFS广度优先搜索
算法·宽度优先
400分2 小时前
吃透RAG核心-----语义检索与关键字检索底层原理
算法·架构
目黑live +wacyltd2 小时前
算法备案:常见驳回原因与应对策略
人工智能·算法
磊 子2 小时前
多态类原理+四种类型转换+异常处理
开发语言·c++·算法
染指11103 小时前
3.AI大模型-token是什么-大模型底层运行机制
人工智能·算法·机器学习
谙弆悕博士4 小时前
快速学C语言——第19章:C语言常用开发库
c语言·开发语言·算法·业界资讯·常用函数