【1096. 花括号展开 II】

news2025/7/21 11:12:07

来源:力扣(LeetCode)

描述:

如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符串。

花括号展开的表达式可以看作一个由 花括号逗号小写英文字母 组成的字符串,定义下面几条语法规则:

  • 如果只给出单一的元素 x,那么表达式表示的字符串就只有 "x"R(x) = {x}
    • 例如,表达式 "a" 表示字符串 "a"
    • 而表达式 "w" 就表示字符串 "w"
  • 当两个或多个表达式并列,以逗号分隔,我们取这些表达式中元素的并集。R({e_1,e_2,...}) = R(e_1) ∪ R(e_2) ∪ ...
    • 例如,表达式 "{a,b,c}" 表示字符串 "a","b","c"
    • 而表达式 "{{a,b},{b,c}}" 也可以表示字符串 "a","b","c"
  • 要是两个或多个表达式相接,中间没有隔开时,我们从这些表达式中各取一个元素依次连接形成字符串。R(e_1 + e_2) = {a + b for (a, b) in R(e_1) × R(e_2)}
    • 例如,表达式 "{a,b}{c,d}" 表示字符串 "ac","ad","bc","bd"
  • 表达式之间允许嵌套,单一元素与表达式的连接也是允许的。
    • 例如,表达式 "a{b,c,d}" 表示字符串 "ab","ac","ad"​​​​​​。
    • 例如,表达式 "a{b,c}{d,e}f{g,h}" 可以表示字符串 "abdfg", "abdfh", "abefg", "abefh", "acdfg", "acdfh", "acefg", "acefh"

给出表示基于给定语法规则的表达式 expression,返回它所表示的所有字符串组成的有序列表。

示例 1:

输入:expression = "{a,b}{c,{d,e}}"
输出:["ac","ad","ae","bc","bd","be"]

示例 2:

输入:expression = "{{a,z},a{b,c},{ab,z}}"
输出:["a","ab","ac","z"]
解释:输出中 不应 出现重复的组合结果。

提示:

  • 1 <= expression.length <= 60
  • expression[i] 由 ‘{’,‘}’,‘,’ 或小写英文字母组成
  • 给出的表达式 expression 用以表示一组基于题目描述中语法构造的字符串

方法:递归解析

思路与算法

表达式可以拆分为多个子表达式,以逗号分隔或者直接相接。我们应当先按照逗号分割成多个子表达式进行求解,然后再对所有结果求并集。这样做的原因是求积的优先级高于求并集的优先级。

我们用 expr 表示一个任意一种表达式,用 term 表示一个最外层没有逗号分割的表达式,那么 expr 可以按照如下规则分解:

expr → term ∣ term, expr

其中的 ∣ 表示或者,即 expr 可以分解为前者,也可以分解为后者。

再来看 term, term 可以由小写英文字母或者花括号包括的表达式直接相接组成,我们用 item 来表示每一个相接单元,那么 term 可以按照如下规则分解:

term → item ∣ item term

item 可以进一步分解为小写英文字母 letter 或者花括号包括的表达式,它的分解如下:

item → letter ∣ {expr}

在代码中,我们编写三个函数,分别负责以上三种规则的分解:

  1. expr 函数,不断的调用 term,并与其结果进行合并。如果匹配到表达式末尾或者当前字符不是逗号时,则返回。
  2. term 函数,不断的调用 item,并与其结果求积。如果匹配到表达式末尾或者当前字符不是小写字母,并且也不是左括号时,则返回。
  3. item 函数,根据当前字符是不是左括号来求解。如果是左括号,则调用 expr,返回结果;否则构造一个只包含当前字符的字符串集合,返回结果。

以下示意图以 {a,b}{c,{d,e}} 为例,展示了表达式递归拆解以及回溯的全过程。

1.png
2.png
在代码实现过程中有以下细节:

  1. 维护一个外部指针来遍历整个表达式,或者将表达式和当前遍历下标以引用的方式传递给被调函数。
  2. 因为最终答案需要去重,所以可以先用集合来求解中间结果,最后再转换成已排序的列表作为最终答案。

代码:

class Solution {
    string expression;
    int idx;

    // item -> letter | { expr }
    set<string> item() {
        set<string> ret;
        if (expression[idx] == '{') {
            idx++;
            ret = expr();
        } else {
            ret = {string(1, expression[idx])};
        }
        idx++;
        return move(ret);
    }

    // term -> item | item term
    set<string> term() {
        // 初始化空集合,与之后的求解结果求笛卡尔积
        set<string> ret = {""};
        // item 的开头是 { 或小写字母,只有符合时才继续匹配
        while (idx < expression.size() && (expression[idx] == '{' || isalpha(expression[idx]))) {
            auto sub = item();
            set<string> tmp;
            for (auto &left : ret) {
                for (auto &right : sub) {
                    tmp.insert(left + right);
                }
            }
            ret = move(tmp);
        }
        return move(ret);
    }

    // expr -> term | term, expr
    set<string> expr() {
        set<string> ret;
        while (true) {
            // 与 term() 求解结果求并集
            ret.merge(term());
            // 如果匹配到逗号则继续,否则结束匹配
            if (idx < expression.size() && expression[idx] == ',') {
                idx++;
                continue;
            } else {
                break;
            }
        }
        return move(ret);
    }

public:
    vector<string> braceExpansionII(string expression) {
        this->expression = expression;
        this->idx = 0;
        auto ret = expr();
        return {ret.begin(), ret.end()};
    }
};

执行用时:8 ms, 在所有 C++ 提交中击败了89.66%的用户
内存消耗:10 MB, 在所有 C++ 提交中击败了87.36%的用户
复杂度分析
时间复杂度:O(nlogn),其中 n 是 expression 的长度。整个
expression 只会遍历一次,时间复杂度为 O(n),集合合并以及求积运算的时间复杂度为 O(nlogn),因此总的时间复杂度为 O(nlogn)。
空间复杂度:O(n)。递归过程所需的栈空间为 O(n),以及存放中间答案的空间复杂度为 O(n),因此总的空间复杂度为 O(n)。
author:LeetCode-Solution

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/395073.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

E900V21C(S905L-armbian)安装armbian-Ubuntu(WiFi)

基本上是s905L芯片的刷机都是如此&#xff0c;包括Q7等 在网上寻找好多的教程关于e900v21c的刷机包和教程都少的可怜&#xff0c;唯一的就是这个&#xff1a;山东联通版创维E900V21C盒子刷入Armbiam并安装宝塔和Docker&#xff0c;但他是不能用WiFi和蓝牙的然后就是寻找s90l的…

C++基础了解-01-基础语法

基础语法 一、基础语法 C 程序可以定义为对象的集合&#xff0c;这些对象通过调用彼此的方法进行交互。现在让我们简要地看一下什么是类、对象&#xff0c;方法、即时变量。 对象 - 对象具有状态和行为。例如&#xff1a;一只狗的状态 - 颜色、名称、品种&#xff0c;行为 -…

【LeetCode每日一题】——334.递增的三元子序列

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【题目进阶】九【时间频度】十【代码实现】十一【提交结果】一【题目类别】 贪心算法 二【题目难度】 中等 三【题目编号】 334.递增的三元子序列 四【题…

Vue3视频播放组件(Video)

Vue2视频播放组件 可自定义设置以下属性&#xff1a; 视频文件url&#xff08;videoUrl&#xff09;&#xff0c;必传&#xff0c;支持网络地址https和相对地址 视频封面url&#xff08;videoCover&#xff09;&#xff0c;默认为null&#xff0c;支持网络地址https和相对地…

【nacos2.2.1本地启动】

nacos2.2.1本地启动填坑之行 下载nacos代码 nacos文档地址&#xff1a;https://nacos.io/zh-cn/docs/quick-start-spring.html github地址下载代码&#xff1a;https://github.com/alibaba/nacos.git appllo文章&#xff1a;https://blog.51cto.com/muxiaonong/3933418 下…

UEFI学习(三)-创建一个dxe driver-UDK2017

创建一个dxe driver 创建UEFI DXE driver DXE驱动的运行阶段 DXE驱动创建 创建UEFI DXE driver 在edk2中&#xff0c;我们可以了解到它有非常多种类的模块&#xff0c;每种模块运行于不同阶段&#xff0c;上一阶段&#xff0c;我们尝试了一下标准应用程序的工程模块&#xff0c…

Centos7超详细安装教程

Centos 7适合初入门的带图形化的界面系统安装 本文是基于VMware虚拟机&#xff0c;centos7 64位安装教学 文章目录Centos 7适合初入门的带图形化的界面系统安装一、软件准备二、VMware新建适配虚拟机三、Centos 安装四、基础检查一、软件准备 VMware 虚拟机安装 官网下载链接&…

Redis 做延迟消息队列

背景 看到消息队列&#xff0c;我们肯定会想到各种MQ&#xff0c;比如&#xff1a;RabbitMQ&#xff0c;acivityMQ、RocketMQ、Kafka等。 但是&#xff0c;当我们需要使用消息中间件的时候&#xff0c;并非每次都需要非常专业的消息中间件&#xff0c;假如我们只有一个消息队…

问一下ChatGPT:DIKW金字塔模型

经常看到这张DIKW金字塔模型图&#xff0c;还看到感觉有点过份解读的图&#xff0c;后面又加上了insight&#xff0c;impact等内容。 Data&#xff1a;是数据&#xff0c;零散的、无规则的呈现到人们眼前&#xff0c;如果你只看到这些数字&#xff0c;如果没有强大的知识背景&a…

STM32之DMA

DMA介绍DMA(Direct MemoryAccess&#xff0c;直接存储器访问)提供在外设与内存、存储器和存储器、外设与外设之间的高速数据传输使用。它允许不同速度的硬件装置来沟通&#xff0c;而不需要依赖于CPU&#xff0c;在这个时间中&#xff0c;CPU对于内存的工作来说就无法使用。DMA…

音乐、音效素材库,好听的BGM都在这~

推荐6个超好用的音频素材网站&#xff0c;免费可商用&#xff0c;热门BGM配乐都能找到&#xff0c;自媒体视频剪辑必备&#xff01;建议收藏&#xff01; 1、菜鸟图库 https://www.sucai999.com/audio.html?vNTYxMjky 菜鸟图库素材非常多&#xff0c;包含了设计、办公、自媒体…

详解FPGA:人工智能时代的驱动引擎观后感

详解FPGA&#xff1a;人工智能时代的驱动引擎观后感 本书大目录 第一章 延续摩尔定律 第二章 拥抱大数据的洪流 第三章 FPGA在人工智能时代的独特优势 第四章 更简单也更复杂——FPGA开发的新方法 第五章 站在巨人肩上——FPGA发展新趋势 文章目录详解FPGA&#xff1a;人工智能…

Redis技术详解

Redis技术详解 Redis是一种支持key-value等多种数据结构的存储系统。可用于缓存&#xff0c;事件发布或订阅&#xff0c;高速队列等场景。支持网络&#xff0c;提供字符串&#xff0c;哈希&#xff0c;列表&#xff0c;队列&#xff0c;集合结构直接存取&#xff0c;基于内存&…

75. CSV文件的写入(保姆级教程)

75. CSV文件的写入&#xff08;保姆级教程&#xff09; 文章目录75. CSV文件的写入&#xff08;保姆级教程&#xff09;1. 目标任务2. 什么是CSV文件2.1 CSV文件知识2.2 准备工作2.3 实操练习12.4 实操练习22.5 实操练习33. os模块文件操作3.1 准备工作3.2 os模块知识回顾3.3 模…

12N60-ASEMI高压MOS管12N60

编辑-Z 12N60在TO-220封装里的静态漏极源导通电阻&#xff08;RDS(ON)&#xff09;为0.7Ω&#xff0c;是一款N沟道高压MOS管。12N60的最大脉冲正向电流ISM为48A&#xff0c;零栅极电压漏极电流(IDSS)为1uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。12N60功耗&#xff…

SpringCloud微服务实战——搭建企业级开发框架(五十):集成移动端推送功能的系统通知公告数据库设计

系统的通知公告功能似乎是很容易被忽略的功能模块&#xff0c;在传统的软件系统中&#xff0c;一般OA类软件系统不可或缺&#xff0c;而在应用软件系统中此功能或有或无&#xff0c;在现在大多数的互联网软件系统中&#xff0c;此功能又必不可缺。所以&#xff0c;在框架设计时…

C++基础了解-04-C++ 变量作用域

变量作用域 一、C 变量作用域 作用域是程序的一个区域&#xff0c;一般来说有三个地方可以定义变量&#xff1a; 1、在函数或一个代码块内部声明的变量&#xff0c;称为局部变量。 2、在函数参数的定义中声明的变量&#xff0c;称为形式参数。 3、在所有函数外部声明的变量…

神经网络结构常见可视化工具汇总及效果演示

文章目录各种训练框架自带的可视化工具pytorch自带pytorchvizkeras自带visualkerasTensorFlow自带TensorBoard其它画图工具NN-SVG&#xff1a;FCNN style、LeNet style、AlexNet stylePlotNeuralNet&#xff1a;使用Latex编写Netron&#xff1a;多种格式的网络模型文件可视化ZE…

计算机网络的166个概念你知道几个 第九部分

计算机网络网络层 路由选择算法&#xff1a;网络层中决定分组发送路径的一种算法。 转发&#xff1a;它指的是将分组从一个输入链路转移到合适的输出链路的动作。 路由选择&#xff1a;指确定分组从一端发送到另一端所选择路径的处理过程。 三种路由交换技术&#xff1a;内…

对word文档中指定的相同内容/文字加颜色或背景颜色

1.请看一段文章。 2.我们要给文中的“code”换成白色字体&#xff0c;黑色背景如何批量呢&#xff1f; 2.1.先摁下“ctrl”"H" 2.2.选择“查找” 2.3.查找内容框填入“code” 2.4.点击以下项中查找&#xff0c;选择主文档。&#xff08;如果你要对某一段文章的相…