算法练习(5) —— 图

算法练习(5) —— 图

习题

本次题目取自leetcode中的 Graph 栏目中的第399题:
Evaluate Division


题目如下:

Description

Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). Given some queries, return the answers. If the answer does not exist, return -1.0.

Example

Given a / b = 2.0, b / c = 3.0.
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? .
return [6.0, 0.5, -1.0, 1.0, -1.0 ].

The input is: vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries , where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector<double>.

According to the example above:

equations = [ [“a”, “b”], [“b”, “c”] ],
values = [2.0, 3.0],
queries = [ [“a”, “c”], [“b”, “a”], [“a”, “e”], [“a”, “a”], [“x”, “x”] ].

The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.

思路与代码

  • 理解题意并不难,就是给你一堆已有的算式,再给你一些新的算式,求出其答案,能推出来就输出答案,推不出来就输出-1…
  • 首先要注意几点
    • 输入绝对有效
    • 知道a / b, 也就知道了b / a
    • 在上面那个条件下, 可能有0 / b = 0的情况,这时候b / 0是不允许的
  • 做这个题目最直观的想法是将每个除数和被除数当作结点,连接起来,构成一个图。每次先寻找初始节点,如果找不到直接返回-1。接下来开始找目标节点,能联通的不断做除法或者乘法就行,不能联通的直接赋值为-1。
  • 第二个想法是比较幼稚但是效率很高的方法…把除数或者被除数赋个初始值,然后算出对应的另一个…也就是把所给的所有的已有算式,转化在同一个坐标系下,对应的比率都是一样的。例如:
    equations : [["a", "b"], ["b", "c"]]
    values    : [2.0, 5.0]
    一开始从equations的第一个被除数 a 赋值, 令 a = 1.0, 则 b = a / 2.0 = 0.5, c = b / 5.0 = 0.1
    这样在求a / c或者 c / a的时候, 就不需要从两个算式之间去转换, 直接用对应的数字去算就OK了
  • 上面那个方法看似简单,但是有个很大的弊病就是有可能出现除不尽的情况,有的乘回来能恢复,有的就说不定了…不过我觉得可行性很高,不知道提交能不能通过测试样例呢…
  • 最后我采用了另外一种方法。因为hash map可以用string作key存储信息,寻找方面很方便,操作也很方便。存储 a / b = value 的信息时,可以存储 key = a, v = value 时的顺便存储key = b, v = 1 / value。hash map 在 c++ 中对应的是unordered_map

代码如下:


#include <vector>
#include <unordered_map>
#include <set>
using namespace std;

class Solution {
public:
    vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
        unordered_map<string, unordered_map<string, double>> hashMap;
        vector<double> result;

        for (int i = 0; i < equations.size(); i++) {
            // 存储 a / b
            hashMap[equations[i].first].insert(make_pair(equations[i].second, values[i]));
            // 存储 b / a
            if (values[i] != 0)
                hashMap[equations[i].second].insert(make_pair(equations[i].first, 1 / values[i]));
        }

        for (int j = 0; j < queries.size(); j++) {
            set<string> s;
            // dfs
            double ans = findPath(queries[j].first, queries[j].second, hashMap, s);
            if (ans)
                result.push_back(ans);
            else
                result.push_back(-1);
        }

        return result;
    }

    double findPath(string first, string second, unordered_map<string, unordered_map<string, double>>& hashMap, set<string>& s) {
        if (hashMap[first].find(second) != hashMap[first].end())
            return hashMap[first][second];

        for (auto sec : hashMap[first]) {
            if (s.find(sec.first) == s.end()) {
                s.insert(sec.first);
                double ans = findPath(sec.first, second, hashMap, s);
                if (ans)
                    return sec.second * ans;
            }
        }
        return 0;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值