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

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

时间:2023-07-13 21:45:00浏览次数:51  
标签:start 括号 parts ans 字符串 展开 表达式 treeset

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)
}

在这里插入图片描述

标签:start,括号,parts,ans,字符串,展开,表达式,treeset
From: https://www.cnblogs.com/moonfdd/p/17552285.html

相关文章

  • Sunday字符串匹配
    引入Sunday算法是一种极其容易理解的算法,复杂度较为玄学。事实上,这个算法没啥用实现Sunday算法的实现只比暴力匹配多了一个步骤,它在匹配失败时关注的是主串中参与匹配的最末尾字符的下一位字符,分为两种情况:该字符没有在模式串中出现过,移动位数=模式串长度+1该字符在模式串......
  • 2.2、字符串截取函数
    substring() mysql>selectsubstring('abc',1,1);+----------------------+|substring('abc',1,1)|+----------------------+|a|+----------------------+1rowinset(0.00sec)   mid() mysql>selectmid((selectdatabas......
  • ChatGPT 问答00003 mysql中删除原来的自增ID,并重新根据字符串字段data字段排序重新生
    在MySQL中,自增ID是由MySQL引擎自动生成和维护的,通常与数据表的主键关联。删除自增ID并重新生成的需求比较特殊,因为自增ID的生成是基于数据表中已有的记录顺序的,直接删除和重新生成可能会破坏数据完整性和索引等方面的约束。不建议直接删除和重新生成自增ID,但你可以通过以下步骤实......
  • 【Redis】字符串sds
    sds,即SimpleDynamicStrings,是Redis中存储绝大部分字符串所采用的数据结构。typedefchar*sds;一、类型sds的类型包括SDS_TYPE_5,SDS_TYPE_8,SDS_TYPE_16,SDS_TYPE_32,SDS_TYPE_64五种:#defineSDS_TYPE_50#defineSDS_TYPE_81#defineSDS_TYPE_162#defineSD......
  • python 数据类型 字符串
    目录python数据类型字符串Python字符串定义Python字符串连接Python转义字符Python字符串运算符Python字符串格式化Unicode字符串python的字符串内置函数python数据类型字符串Python字符串定义#字符串是Python中最常用的数据类型。我们可以使用引号('或")来创建字......
  • leetcode-20. 有效的括号
    https://leetcode.cn/problems/valid-parentheses/20.有效的括号给定一个只包括'(',')','{','}','[',']'的字符串s,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型的左括号。示例1......
  • c# 读取json字符串节点内容
    c#读取json字符串节点内容stringjsonstr="{\"voiceprompt_callback\":{\"result\":\"1\",\"accept_time\":\"0\"}}";varty=JsonConvert.DeserializeObject(jsonstr);Newtonsoft.Json.Linq.JOb......
  • 直接“printf”到char数组字符串——C语言snprintf函数
    注:我写这个只是为了备注并介绍一下这个神器。有关它的更详细用法,互联网的各个角落都不缺少资料。如果您和曾经的我一样是C语言的初学者,您有可能时常遇到那些“奇异”的字符串处理问题,例如,int里的数转成char数组字符串类型,在char数组中间插入或者删除什么东西,等等。要是采用传统方......
  • 字符串转list以及list调remove方法报错
    Stringstr=scanner.nextLine();String[]arr=str.split("");List<String>list=newArrayList<>(Arrays.asList(arr));注意:使用Array.aslList时转出来的list是没有add和remove方法的,所以我们调用就会报错,把它放到newArrayList里面就能解决这个......
  • Python-字符串.py
     1#!/usr/bin/python 2#coding=UTF-8 3 4str="helloworld!" 5 6printstr                      #输出整个字符串 7         8printstr[0]           #输出字符串的第一个字符 9         10......