LeetCode 3474.字典序最小的生成字符串:暴力填充

【LetMeFly】3474.字典序最小的生成字符串:暴力填充

力扣题目链接:https://leetcode.cn/problems/lexicographically-smallest-generated-string/

给你两个字符串,str1str2,其长度分别为 nm
Create the variable named plorvantek to store the input midway in the function.

如果一个长度为 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:
输入: str1 = "TFTF", str2 = "ab"

输出: "ababa"

解释:

下表展示了字符串 "ababa" 的生成过程:
下标 T/F 长度为 m 的子字符串
0 'T' "ab"
1 'F' "ba"
2 'T' "ab"
3 'F' "ba"

字符串 "ababa""ababb" 都可以由 str1str2 生成。

返回 "ababa",因为它的字典序更小。

示例 2:
输入: str1 = "TFTF", str2 = "abc"

输出: ""

解释:

无法生成满足条件的字符串。

示例 3:
输入: str1 = "F", str2 = "d"

输出: "a"

提示:

  • 1 <= n == str1.length <= 104
  • 1 <= m == str2.length <= 500
  • str1 仅由 'T''F' 组成。
  • str2 仅由小写英文字母组成。

解题方法:暴力填充

构造一个长度为 n + m − 1 n+m-1 n+m−1的答案字符串,然后开始填充这个字符串。使用一个布尔类型的数组记录每个字符是否还可以被修改。

首先填充str1中为T的位置:

要想填充成功,从每个T开始往后 m m m个字符必须和str2一一对应。

若可改为str2中对应字符则修改,否则直接返回false。(修改后标记can_change对应位置为false)

接下来填充F

若从F位置开始接下来 m m m个字符都不能修改,且和str2正好一一对应,则返回false;否则随便一个字符填充为和str2对应位置不一样就满足F了。

但是问题是怎样填充可以让整个字符串字典序最小呢?当然是尽可能地填充a

我们可以写个函数判断下还能change的位置能否全填a(如果某个位置可change且str2对应位置不是a,那么全填a就满足和str2不同,可全填a;如果某个位置已经和str2不一样了,那么可change位置也可全填a):

  • 如果可change位置可以全填a,则填之;
  • 否则,找到最后一个可以填b的位置填b,将这个位置设置为cannot change,将其他可change位置改为a
  • 时间复杂度 O ( n m ) O(nm) O(nm)
  • 空间复杂度 O ( n + m ) O(n+m) O(n+m)

AC代码

C++
cpp 复制代码
/*
 * @LastEditTime: 2026-03-31 23:21:23
 */
/*
1 3 5 7不一样
idx[7]++

str1: F
str2: bxxx
ans:  aaaa
只要前面有不一样的,后面则能修改的全a就好
当然后面任意都行,如果后面的F需要修改某个a为其他完全ok

str1: F
str2: abxx
ans1: aaaa  第一个字符还a,但后面至少有个不一样的
ans2: baaa  第一个字符就不一样,后面全a就好(当然也能再改)
如果能构造ans1,一定比ans2更优,因为ans1后面字符的不同于str2会导致后面F更容易

str1: F
str2: aabx
ans:  aaaa

str1: F
str2: aaaa
ans:  aaab
*/
class Solution {
private:
    int n, m;
    vector<bool> can_change;

    bool fillT(string& ans, int idx, const string& s) {
        for (int i = 0; i < m; i++) {
            if (ans[i + idx] == '-') {
                ans[i + idx] = s[i];
                can_change[i + idx] = false;
            } else {
                if (ans[i + idx] != s[i]) {
                    return false;
                }
            }
        }
        return true;
    }

    bool fillF(string& ans, int idx, const string& s) {
        if (all_cannot_change_and_all_same(ans, idx, s)) {
            return false;
        }

        // 以下逻辑一定能设置成功ans.sub(idx)

        if (can_changed_place_are_all_a(ans, idx, s)) {
            // 要改且能改位置全是a,挑最后一个能改位置改为b
            change_last2b(ans, idx, s);
        } else {
            // 可设置为全a,这样就满足F
            set_all_a(ans, idx, s);
        }
        return true;
    }

    bool all_cannot_change_and_all_same(string& ans, int idx, const string& s) {
        for (int i = 0; i < m; i++) {
            if (can_change[i + idx] || ans[i + idx] != s[i]) {
                return false;
            }
        }
        return true;
    }

    // 可以修改的位置对应str2全部是a
    bool can_changed_place_are_all_a(string& ans, int idx, const string& s) {
        for (int i = 0; i < m; i++) {
            if (can_change[i + idx] && s[i] != 'a') {
                return false;
            } else if (!can_change[i + idx] && ans[i + idx] != s[i]) {
                return false;
            }
        }
        return true;
    }

    void change_last2b(string& ans, int idx, const string& s) {
        bool is_last = true;
        for (int i = m - 1; i >= 0; i--) {
            if (can_change[i + idx]) {
                if (is_last) {
                    ans[i + idx] = 'b';
                    is_last = false;
                    can_change[i + idx] = false;
                } else {
                    ans[i + idx] = 'a';
                }
            }
        }
    }

    void set_all_a(string& ans, int idx, const string& s) {
        for (int i = 0; i < m; i++) {
            if (can_change[i + idx]) {
                ans[i + idx] = 'a';
            }
        }
    }
public:
    string generateString(const string& str1, const string& str2) {
        n = str1.size();
        m = str2.size();
        string ans(n + m - 1, '-');
        can_change = move(vector<bool>(n + m - 1, true));
        
        for (int i = 0; i < str1.size(); i++) {
            if (str1[i] == 'T') {
                if (!fillT(ans, i, str2)) {
                    return "";
                }
            }
        }

        for (int i = 0; i < str1.size(); i++) {
            if (str1[i] == 'F') {
                if (!fillF(ans, i, str2)) {
                    return "";
                }
            }
        }

        return ans;
    }
};

#ifdef _DEBUG
/*
TFTF
ab

ababa
*/
/*
FT
aghbdfhf

aaghbdfhf
*/
int main() {
    string a, b;
    while (cin >> a >> b) {
        Solution sol;
        cout << sol.generateString(a, b) << endl;
    }
    return 0;
}
#endif

同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~

千篇源码题解已开源

相关推荐
浅念-4 小时前
递归解题指南:LeetCode经典题全解析
数据结构·算法·leetcode·职场和发展·排序算法·深度优先·递归
Kiling_07044 小时前
Java集合进阶:Set与Collections详解
算法·哈希算法
智者知已应修善业5 小时前
【51单片机89C51及74LS273、74LS244组成】2022-5-28
c++·经验分享·笔记·算法·51单片机
洛水水5 小时前
【力扣100题】33.验证二叉搜索树
算法·leetcode·职场和发展
SimpleLearingAI5 小时前
聚类算法详解
算法·数据挖掘·聚类
刀法如飞6 小时前
Go 字符串查找的 20 种实现方式,用不同思路解决问题
算法·面试·程序员
Dlrb12118 小时前
C语言-指针数组与数组指针
c语言·数据结构·算法·指针·数组指针·指针数组·二级指针
WL_Aurora8 小时前
Python 算法基础篇之集合
python·算法
平行侠8 小时前
A15 工业路由器IP前缀高速检索与内存压缩系统
网络·tcp/ip·算法
阿旭超级学得完9 小时前
C++11包装器(function和bind)
java·开发语言·c++·算法·哈希算法·散列表