栈模拟dfs
- 前言
- 一、花括号展开II
- 二、栈模拟dfs
- 总结
- 参考资料
前言
递归调用,代码非常的简洁。但是可以通过显式栈来模拟栈中的内容,锻炼自己的代码能力,清楚知道栈帧中需要的内容。
一、花括号展开II
二、栈模拟dfs
每碰到一个左括号,就压一次栈,但栈里面存什么?
存set,由于存在组合,组合之前还不能提前求并集,所以存set切片!!
每碰到一个右括号,就把当前set切片整理成一个set,抛向上一层的set切片末尾,根据前面的操作符,再判定是否需要组合。
func braceExpansionII(expression string) []string {
// 模拟函数调用栈,数据栈和操作符栈。
stack := make([][]map[string]interface{},1)
top := 1
lastOp := make([]byte,0) // 0代表需要组合,1代表不用组合。
t := 0
lastCh := ',' // 初始化,表示不用组合,set取交集即可。
for _,e := range expression {
// 碰到括号就压栈
if e == '{' {
stack = append(stack[:top],make([]map[string]interface{},0))
top++
// 当前面字符是'}' 或者 字符时,需要组合,将组合操作符压栈。
if lastCh != '{' && lastCh != ','{
lastOp = append(lastOp[:t],0)
t++
}
// 如果前面是'{',说明是该层第一个set块,当该set块提交上来时不用做任何操作。
if lastCh == '{' {
lastOp = append(lastOp[:t],1)
t++
}
lastCh = e
continue
}
// 碰到右括号,先把元素合并向上抛,再根据操作符来判定是否需要组合。
if e == '}' {
// 先把元素取交集向上层抛
newMap := map[string]interface{}{}
curSlice := stack[top - 1]
top--
for _,sc := range curSlice {
for k := range sc {
newMap[k] = struct{}{}
}
}
stack[top - 1] = append(stack[top - 1],newMap)
// 再根据操作符进行普通放置,还是组合
if t != 0 && lastOp[t - 1] == 0 {
cur := stack[top - 1]
m1,m2 := cur[len(cur) - 1],cur[len(cur) - 2]
nm := map[string]interface{}{}
for k2 := range m2 {
for k1 := range m1 {
nm[k2+k1] = struct{}{}
}
}
stack[top - 1] = append(stack[top-1][:len(cur)-2],nm)
}
// 操作符出栈
if t != 0 {
t--
}
}else if e == ',' {
lastOp = append(lastOp[:t],1)
t++
}else {
// 右贴字符型,需要立即组合
cur := stack[top - 1]
if lastCh != ',' && lastCh != '{'{
m := cur[len(cur) - 1]
nm := map[string]interface{}{}
for k := range m {
nm[k + string(e)] = struct{}{}
}
stack[top-1]=append(stack[top-1][:len(cur)-1],nm)
}else {
m := map[string]interface{}{}
m[string(e)] = struct{}{}
stack[top - 1] = append(stack[top - 1],m)
// 逗号操作符出栈
if lastCh == ',' && t != 0 {
t--
}
}
}
lastCh = e
}
// 取数据并排序
return getData(stack[0])
// 总:append的使用append+slice[:top],以及append在修改该当前slice的情况
}
func getData(ms []map[string]interface{}) []string{
ans := []string{}
for _,m := range ms {
for k := range m {
ans = append(ans,k)
}
}
sort.Slice(ans,func(i,j int)bool{
return ans[i] < ans[j]
})
return ans
}
// ‘,’表示和后面并集(合并去重);‘空’表示相互组合。
// 根据花括号配对,以及进入下一个括号前碰到的指示操作符,来进行组合或并集
// set来做容器,
// 每次向上提交一层,就要看操作符,逗号合井号不管,只管空格符进行组合。 这就是整体的抽象规则。
// 思路:每碰到左括号就压一层栈,栈帧中存一个个set形成的切片,同时需要用另一个栈存操作符,可能需要组合。
// 当碰到组合的情况,当前set需要和切片中前一个set进行组合。
总结
1)采用栈模拟递归调用,锻炼代码能力,清楚知道栈帧中需要什么内容。
参考资料
[1] LeetCode 花括号展开II