LeetCode 399 除法求值

把它想象成一个走路的问题,问题的两个分别是路的两端,要找到各个子路径把这条路连起来,要求各个子路径头尾相连。顺着这个思路想,队列?回溯?动态规划?发现题目确实存在子状态,即每一条路径都可以划分为子路径的乘积。

这一次为了方便使用,定义二维数组dp,dp[i][j]表示从节点i到节点j的路径长度。

1、构建letter map[string]int,dp [][]float64,res []float64

2、遍历equations,将不同的节点存储到map中并从0开始分配编号。同时初始化填充dp,将equations 中已有的子路径填充到dp中(主义针对equations中的每一个二元组,可以填充两个子路径),在遍历的过程中,如果发现当前节点已经存储于letter中,那么dp中存在可扩充的路径,对其进行补充(例如,已经遍历过[a, b]后,再次遍历到[b, c],发现b已经在letter中,那么就找到以b为起始的子路径,将其扩充为 [c,b]+[b,a]=[c,a],以及直接反转后的[a,c])。

3、遍历queries,针对其中每一个问题的开始节点,首先判断节点是否在letter中:

  • 如果不在,直接将-1.00存储到res中并继续遍历下一个问题。
  • 如果存在,判断该路径是否已经在dp中,如果是,将对应的值存储到res中,继续遍历下一个问题,如果不是,存储-1.00到res中。

按照上述思路完成代码编写后发现存在问题(给的三个测试用例过了,但是提交出了问题)问题如下,例如已知[a,b][c,e][b,c],按照上述代码的思路,dp中的路径更新顺序为(1)dp[a][b],dp[b][a](2)dp[c][e],dp[e][c](3)dp[b][c],dp[c][b],dp[a][c],dp[c][a],这样的更新顺序缺失了 dp[a][e],dp[e][a]的可能。

针对这一个问题,想到了两种解决的思路 1)BFS:每当产生新的产生式,例如上述(3)中出现了新的 dp[a][c],dp[c][a],就将新的[a,c]组合加入到 equations 中,同步更新 values(这样一想发现我这种遍历完所有可能的组合的情况反而是绕远了,不如直接从queries 出发,BFS遍历所有可能的组合,找到可能的值)。2)递归:这次从 queries 出发,遍历以当前字母为开头的多有可能,将长串逐步划分为短的子串相乘。

决定实现 2)了,练练递归,而且1)感觉思路跟递归差不多但会没有那么顺畅

func calcEquation(equations [][]string, values []float64, queries [][]string) []float64 {
    var res []float64
    var letter map[string]int = make(map[string]int)
    var queue [][]int
    var ma [][]float64=make([][]float64, 2*len(equations))
    for i:=0; i<len(ma); i++{ ma[i]=make([]float64, 2*len(equations)) }
    
    num:=0
    for k, e := range equations{
        if _, ok := letter[e[0]]; !ok { 
            letter[e[0]] = num
            num++ 
        }
        if _, ok := letter[e[1]]; !ok { 
            letter[e[1]] = num
            num++ 
        }
        queue=append(queue, []int{letter[e[0]], letter[e[1]]})
        ma[letter[e[0]]][letter[e[1]]]=values[k]
        ma[letter[e[1]]][letter[e[0]]]=1/values[k]
    }
    // fmt.Println(ma)
    var helper func(s, e int, visited map[int]bool) float64
    helper = func(s, e int, visited map[int]bool) float64 {
        // fmt.Println(s, e)
        if ma[s][e]!=0.0 { return ma[s][e] }
        for i:=0; i<num; i++{
            if _, ok:=visited[i]; !ok && ma[s][i]!=0.0{
                visited[i]=true
                t:=helper(i, e, visited)
                if t>0{ return ma[s][i]*t }
            }
        }
        return -1
    }

    for _, q:=range(queries){
        v0, ok0 := letter[q[0]]
        v1, ok1 := letter[q[1]]
        if !ok0 || !ok1{
            res=append(res, -1.0)
        }else{
            res=append(res, helper(v0, v1, make(map[int]bool)))
        }
    }
    return res
}

LeetCode热题100完结撒花🎉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值