2023-07-13:如果你熟悉 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。

返回它所表示的所有字符串组成的有序列表。

输入:expression = "{a,b}{c,{d,e}}"。

输出:["ac","ad","ae","bc","bd","be"]。

答案2023-07-13:

大体步骤如下:

1.定义了一个结构体 Info,其中包含一个 treeset.Set 类型的指针 ans 和一个整数 end

2.定义了一个 NewInfo 函数,用于初始化 Info 对象。

3.定义了 braceExpansionII 函数,接收一个表示表达式的字符串,并返回展开后的字符串列表。

4.process 函数是实际处理展开过程的核心函数,它接收一个表示表达式的字符数组 exp 和一个起始索引 start,返回一个 Info 对象。

5.在 process 函数中,创建了一个空的 treeset.Set 对象 ans 和一个空的 []*treeset.Set 切片 parts

6.使用 strings.Builder 创建了一个字符串构建器 builder

7.在循环中,依次遍历 exp 中的字符,直到遇到 } 或到达字符串末尾为止。

8.如果当前字符为 {,则调用 addStringToParts 函数将构建器中的字符串添加到 parts 中,并递归调用 process 函数处理 {} 内部的表达式,将返回的 ans 添加到 parts 中,并更新起始索引 start

9.如果当前字符为 ,,则调用 addStringToParts 函数将构建器中的字符串添加到 parts 中,并将 parts 中的所有集合添加到 ans 中,然后清空 parts,并更新起始索引 start

10.如果当前字符为小写英文字母,则将其添加到构建器中。

11.循环结束后,调用 addStringToParts 函数将构建器中的最后一个字符串添加到 parts 中。

12.调用 addPartsToSet 函数将 parts 中的所有集合添加到 ans 中。

13.返回包含 ans 和起始索引 startInfo 对象。

14.addStringToParts 函数将构建器中的字符串添加到 parts 中,如果构建器不为空,则创建一个新的 treeset.Set 对象,并将字符串添加到集合中,再将集合添加到 parts 中。

15.addPartsToSet 函数将 parts 中的所有集合进行组合并添加到 ans 中。

16.processParts 函数是递归处理 parts 切片的核心函数。如果索引 i 等于 parts 的长度,则表示已经处理完所有集合,将连接后的字符串添加到 ans 中。否则,取出当前集合,遍历集合中的每个元素,与 path 进行连接,并递归调用 processParts 处理下一个集合。

17.toSlice 函数将 ans 中的元素转换为有序字符串切片,并返回该切片。

18.在 main 函数中,定义了一个表达式字符串 expression,并调用 braceExpansionII 函数对表达式进行展开,并将结果打印输出。

该代码的时间复杂度为$O(N^M)$,其中N为表达式中的字符数,M为展开括号的深度。具体来说,代码中的核心函数process通过遍历表达式字符并进行递归处理,每次递归都会将问题规模缩小,直到达到展开括号的最深层级。因此,时间复杂度取决于表达式中字符的数量以及展开括号的深度。

空间复杂度是$O(NM)$,其中N为表达式中的字符数,M为展开括号的深度。在代码执行过程中,会创建一些辅助数据结构,如字符串构建器和集合。对于集合这种动态数据结构,其占用的内存空间与展开括号的深度呈指数关系。而字符串构建器的空间复杂度与表达式中字符的数量成线性关系。因此,最终的空间复杂度取决于展开括号的深度和表达式中字符的数量,即$O(NM)$。

go完整代码如下:

package main

import (
"fmt"
"strings" "github.com/emirpasic/gods/sets/treeset"
) type Info struct {
ans *treeset.Set
end int
} func NewInfo(a *treeset.Set, e int) *Info {
ans := &Info{}
ans.ans = a
ans.end = e
return ans
} func braceExpansionII(expression string) []string {
ans := process([]rune(expression), 0).ans
return toSlice(ans)
} func process(exp []rune, start int) *Info {
ans := treeset.NewWith(func(a, b interface{}) int {
aa := a.(string)
bb := b.(string)
if aa < bb {
return -1
} else if aa == bb {
return 0
} else {
return 1
}
})
parts := make([]*treeset.Set, 0)
builder := strings.Builder{} for start < len(exp) && exp[start] != '}' {
if exp[start] == '{' {
addStringToParts(&builder, &parts)
next := process(exp, start+1)
parts = append(parts, next.ans)
start = next.end + 1
} else if exp[start] == ',' {
addStringToParts(&builder, &parts)
addPartsToSet(ans, &parts)
start++
parts = make([]*treeset.Set, 0)
} else {
builder.WriteRune(exp[start])
start++
}
} addStringToParts(&builder, &parts)
addPartsToSet(ans, &parts)
return &Info{ans, start}
} func addStringToParts(builder *strings.Builder, parts *[]*treeset.Set) {
if builder.Len() != 0 {
s := treeset.NewWithStringComparator()
s.Add(builder.String())
*parts = append(*parts, s)
builder.Reset()
}
} func addPartsToSet(ans *treeset.Set, parts *[]*treeset.Set) {
processParts(parts, 0, "", ans)
} func processParts(parts *[]*treeset.Set, i int, path string, ans *treeset.Set) {
if i == len(*parts) {
if path != "" {
ans.Add(path)
}
} else {
part := (*parts)[i]
it := part.Iterator()
for it.Next() {
cur := it.Value().(string)
processParts(parts, i+1, path+cur, ans)
}
}
} func toSlice(set *treeset.Set) []string {
slice := make([]string, 0)
it := set.Iterator()
for it.Next() {
slice = append(slice, it.Value().(string))
}
return slice
} func main() {
expression := "{a,b}{c,{d,e}}"
result := braceExpansionII(expression)
fmt.Println(result)
}

2023-07-13:如果你熟悉 Shell 编程,那么一定了解过花括号展开,它可以用来生成任意字符串。 花括号展开的表达式可以看作一个由 花括号、逗号 和 小写英文字母 组成的字符串 定义下面几条语的更多相关文章

  1. 随机生成长度为len的密码,且包括大写、小写英文字母和数字

    一道华三面试题,随机生成长度为len的密码,且包括大写.小写英文字母和数字,主要Random类的使用,random.nextInt(len)表示生成[0,len)整数.具体实现见下面代码,已经很详细了 ...

  2. 末学者笔记--shell编程上 1 玄

    Shell 编程 [内容简列]: 1.shell简介 2. shell分类 3. 查看shell 4. 第一个shell脚本 5. shell编程常用命令 5.1 grep 5.2 cut 5.3 s ...

  3. [转]Shell编程

    原文链接 Shell编程其实真的很简单(一) 如今,不会Linux的程序员都不意思说自己是程序员,而不会shell编程就不能说自己会Linux.说起来似乎shell编程很屌啊,然而不用担心,其实she ...

  4. shell编程快速入门及实战

    shell编程:对于hadoop程序员,通常需要熟悉shell编程,因为shell可以非常方便的运行程序代码. 1.shell文件格式:xxx.sh #!/bin/sh ---shell文件第一行必须 ...

  5. shell编程其实真的很简单(三)

    通过前两篇文章,我们掌握了shell的一些基本写法和变量的使用,以及基本数据类型的运算.那么,本次就将要学习shell的结构化命令了,也就是我们其它编程语言中的条件选择语句及循环语句. 不过,在学习s ...

  6. shell编程/字库裁剪(2)——编程过程

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7704085.html 作者:窗户 Q ...

  7. 【shell】shell编程(三)-if,select,case语句

    通过前两篇文章,我们掌握了shell的一些基本写法和变量的使用,以及基本数据类型的运算.那么,本次就将要学习shell的结构化命令了,也就是我们其它编程语言中的条件选择语句及循环语句. 不过,在学习s ...

  8. 查找常用字符(给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 3 次。)

    给定仅有小写字母组成的字符串数组 A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表. 例如,如果一个字符在每个字符串中出现 3 次,但不是 4 次,则需要在最终答案中包含该字符 ...

  9. 【Python】【demo实验18】【练习实例】【统计输入字符串中,数字的个数、英文字母的个数及其他符号的个数】

    原题: 输入一行字符,分别统计出其中英文字母.空格.数字和其它字符的个数. (本题暂时不支持中文字符及汉字) 我的代码: #!/usr/bin/python # encoding=utf-8 # -* ...

  10. Day_09【常用API】扩展案例5_获取长度为5的随机字符串,字符串由随机的4个大写英文字母和1个0-9之间(包含0和9)的整数组成

    分析以下需求,并用代码实现 1.定义String getStr(char[] chs)方法 功能描述:获取长度为5的随机字符串,字符串由随机的4个大写英文字母和1个0-9之间(包含0和9)的整数组成 ...

随机推荐

  1. 我的第一个NPM包:panghu-planebattle-esm(胖虎飞机大战)使用说明

    好家伙,我的包终于开发完啦 欢迎使用胖虎的飞机大战包!! 为你的主页添加色彩 这是一个有趣的网页小游戏包,使用canvas和js开发 使用ES6模块化开发 效果图如下:  (觉得图片太sb的可以自己改 ...

  2. 【Python毕业设计】基于Python+Flask+MySQL的学生信息管理系统(附完整源码)

    1.项目说明基于python+Flask+mysql的学生信息管理系统项目实战 项目需要安装pycharm专业版,mysql数据库以及项目所需的所有模块创建数据库名称db_online_notes,然 ...

  3. GPT护理机器人 - 让护士的工作变简单

    引子 书接上文<GPT接入企微应用 - 让工作快乐起来>,我把GPT接入了企微应用,不少同事都开始尝试起来了.有的浅尝辄止,有的刨根问底,五花八门,无所不有.这里摘抄几份: "帮 ...

  4. P1008 [NOIP1998 普及组] 三连击,置顶题解的问题

    题目链接: https://www.luogu.com.cn/problem/P1008 置顶题解 暴力,加简化的判断,数学原理,2个集合内所有数相加相乘结果一样,2个集合的内容一样(没错我自己编得, ...

  5. MySQL中的Join 的算法(NLJ、BNL、BKA)

    本文已收录至Github,推荐阅读 Java随想录 微信公众号:Java随想录 目录 摘要 什么是Join Index Nested-Loop Join Block Nested-Loop Join ...

  6. 2020-12-13:用最少数量的线程,每个线程执行for的空循环,把cpu打满了。如果在for的空循环里添加打印输出函数,会把cpu打满吗?为什么?

    福哥答案2020-12-13:不会.输出会进行io操作,相对于CPU的速度,这是一个非常缓慢的过程,所以CPU会有机会空闲下来.***[评论](https://user.qzone.qq.com/31 ...

  7. 2022-05-04:比如,str = “ayxbx“, 有以下4种切法 : a | yxbx、ay | xbx、ayx | bx、ayxb | x, 其中第1、3、4种切法符合:x和y的个数,至少在

    2022-05-04:比如,str = "ayxbx", 有以下4种切法 : a | yxbx.ay | xbx.ayx | bx.ayxb | x, 其中第1.3.4种切法符合: ...

  8. gitlab-runner 中的 Docker-in-Docker

    笔者个人理解:gitlab-runner 安装后就是一个监听状态的 runner,而通过 gitlab-runner register 注册的"实例"其实只是预定义的配置节,当消息 ...

  9. < Python全景系列-5 > 解锁Python并发编程:多线程和多进程的神秘面纱揭晓

    欢迎来到我们的系列博客<Python全景系列>!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法.无论你是编程新手,还是有一 ...

  10. AcWing 1230. K倍区间

    给定一个长度为 N 的数列,A1,A2,-AN,如果其中一段连续的子序列 Ai,Ai+1,-Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K倍区间. 你能求出数列中总共有多少个 K倍区间 ...