花括号展开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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DFS(深度优先搜索)是一种基于的搜索算法,可以用于寻路等问题。以下是使用实现DFS寻路算法的基本步骤: 1. 创建一个,并将起始点压入中。 2. 循环执行以下步骤,直到找到终点或为空: - 从中弹出一个节点作为当前节点。 - 如果当前节点是终点,则返回寻路路径。 - 如果当前节点未被访问过,则将其标记为已访问,并将其相邻且未被访问过的节点压入中。 3. 如果为空并且仍未找到终点,则返回无法到达终点的结果。 下面是使用实现DFS寻路算法的示例代码: ```csharp public List<Node> DFS(Node start, Node end) { Stack<Node> stack = new Stack<Node>(); Dictionary<Node, bool> visited = new Dictionary<Node, bool>(); Dictionary<Node, Node> parent = new Dictionary<Node, Node>(); List<Node> path = new List<Node>(); stack.Push(start); visited[start] = true; while (stack.Count > 0) { Node curr = stack.Pop(); if (curr == end) { // 构建路径 while (curr != null) { path.Add(curr); curr = parent.ContainsKey(curr) ? parent[curr] : null; } path.Reverse(); return path; } foreach (Node neighbor in curr.neighbors) { if (!visited.ContainsKey(neighbor) || !visited[neighbor]) { visited[neighbor] = true; parent[neighbor] = curr; stack.Push(neighbor); } } } // 未找到终点 return null; } ``` 在这个示例代码中,我们使用了 Dictionary 类型来存储节点的访问状态和父节点,以便在找到终点后构建路径。你可以根据实际情况来修改这个代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值