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' 条件,仅当当前子串意外相等时才进行破坏,且破坏时优先选择原本可修改的位置。
  • 从后向前修改可以减少对其他条件的干扰。

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

相关推荐
ZPC82104 分钟前
nmtui
人工智能·算法·机器人
_深海凉_6 分钟前
LeetCode热题100-全排列
算法·leetcode·职场和发展
programhelp_8 分钟前
TikTok 26 Summer SDE Intern 面经分享|两轮技术面 + Timeline 复盘
数据结构·经验分享·算法·面试
成都易yisdong10 分钟前
C# 实现道路横断面自动生成与格式转换(最小二乘拟合 + 方向向量法)
windows·算法·c#·visual studio
阿Y加油吧20 分钟前
算法二刷复盘:LeetCode 39 组合总和 & 22 括号生成(Java 回溯精讲)
java·算法·leetcode
WL_Aurora25 分钟前
每日一题——自然倍树
数据结构·python·算法·深度优先
水木流年追梦31 分钟前
CodeTop Top 300 热门题目3-字符串相加
java·前端·算法
澈20731 分钟前
内存四区模型详解(栈、堆、全局、常量)
c++·面试·职场和发展
一江寒逸35 分钟前
数据结构与算法之美:绪论——构建算法思维的基石
数据结构·算法
AC赳赳老秦35 分钟前
OpenClaw界面错乱、闪退问题,一键修复教程(附工具)
人工智能·python·职场和发展·django·tornado·deepseek·openclaw