Leetcode(剑指offer专项训练)——DFS/BFS专项(1)

发布时间 2023-04-08 14:54:26作者: 理想国的糕

计算除法

题目

给定一个变量对数组 equations 和一个实数值数组 values 作为已知条件,其中 equations[i] = [Ai, Bi] 和 values[i] 共同表示等式 Ai / Bi = values[i] 。每个 Ai 或 Bi 是一个表示单个变量的字符串。
另有一些以数组 queries 表示的问题,其中 queries[j] = [Cj, Dj] 表示第 j 个问题,请你根据已知条件找出 Cj / Dj = ? 的结果作为答案。
返回 所有问题的答案 。如果存在某个无法确定的答案,则用 -1.0 替代这个答案。如果问题中出现了给定的已知条件中没有出现的字符串,也需要用 -1.0 替代这个答案。
链接

题解

可以将题目理解为是给定了一张图,找到起点到终点的路径的问题;
比如给的示例中

输入:equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
输出:[6.00000,0.50000,-1.00000,1.00000,-1.00000]
解释:
条件:a / b = 2.0, b / c = 3.0
问题:a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
结果:[6.0, 0.5, -1.0, 1.0, -1.0 ]

其中已知a/b以及b/c,则a/c=(a/b)*(b/c);可以等价于当我们知道有向图a➡b以及b➡c的边权时候,a➡c的边权也就知道了(按照题目中的意思为边权乘积)
接着要做的就是将字符串视作图的节点(用map记录),除法的值视作两个节点有向图的边权(用graph记录),而为了避免同一个有向边反复遍历dfs陷入死循环,需要有vis来记录每一组中某个有向边是否被使用过
所以题目的意思可以抽象为给一个有向图以及一组起始点,找到起点到终点的路径并给出路径边的乘积

答案如下:

class Solution {
public:
    double path;
    void dfs(int node_index,int ed,vector<vector<double>>&graph,vector<vector<int>>&vis,double temp,int flag){
        //printf("%d %lf\n",node_index,temp);
        if(node_index==ed){
            path=temp;
        }else{
            for(int next_node_index=0;next_node_index<graph[node_index].size();next_node_index++){
                if(vis[node_index][next_node_index]<flag&&graph[node_index][next_node_index]>0){
                    vis[node_index][next_node_index]=flag;
                    dfs(next_node_index,ed,graph,vis,temp*graph[node_index][next_node_index],flag);
                }
            }
        }
    }
    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
        unordered_map<string,int>mp;
        int cnt=0;//统计节点个数
        for(auto eq:equations){
            if(mp.find(eq[0])==mp.end()){
                mp[eq[0]]=cnt;
                cnt++;
            }
            if(mp.find(eq[1])==mp.end()){
                mp[eq[1]]=cnt;
                cnt++;
            }
        }
        vector<vector<double>>graph(cnt,vector<double>(cnt,-1));
        vector<vector<int>>vis(cnt,vector<int>(cnt,0));
        for(int i=0;i<values.size();i++){
            int u=mp[equations[i][0]];
            int v=mp[equations[i][1]];
            graph[u][v]=values[i];
            graph[v][u]=1/values[i];
        }

        int n=queries.size();
        vector<double>ans(n);
        int i=0;
        for(auto q:queries){
            //printf("======\n");
            if(mp.find(q[0])!=mp.end()&&mp.find(q[1])!=mp.end()){
                if(graph[mp[q[0]]][mp[q[1]]]!=-1){
                    ans[i]=graph[mp[q[0]]][mp[q[1]]];
                }else{
                    path=-1;
                    dfs(mp[q[0]],mp[q[1]],graph,vis,1,i+1);
                    if(path!=-1){
                        graph[mp[q[0]]][mp[q[1]]]=path;
                        if(path!=0){
                            graph[mp[q[1]]][mp[q[0]]]=1.0/path;
                        }
                    }
                    ans[i]=path;
                }
                
            }else{
                ans[i]=-1;
            }
            i++;

            // a / b=2; b/c =3
            // b / a

        }
        return ans;
    }
};