題目
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.
題目大意
題目大概是說給若干個形如a/b=k的等式,其中a,b是字符串,k是double類型的常數,然後再給你幾個同樣形如a/b的式子,讓你根據之前的等式求出這些式子的值,例如a/b=2.0,b/c=3.0,現在求a/c,值爲6.0。
還有a/x,因爲x這個字符串之前沒給出,所以是不合法的值,定義爲-1.0。這裏還要注意一點,所有等式的值均爲正值。
分析
這道題因爲牽扯到很多變量之間的關係,那麼考慮下我們學過什麼模型或者算法裏面牽扯到很多變量之間的關係?嗯,如果這裏把每一個變量都看成是一個結點,k值看做是邊的權值,那麼是不是很像數據結構中的圖論,當然這裏是有向圖,而且是帶環的,畢竟自己除自己也是有意義的,值爲1.0。上面的example對應的圖畫出來差不多就像下面這個樣子:
每條邊的權值都是它的弧尾/弧頭的值,例如a/b=2,b/a=1.0/2.0。
那麼接下來就簡單了,整個問題也就轉換爲了求從頂點i到
頂點j的路徑的權值之積就好了,例如求c/a,那麼只要c->b->a這條路徑上的權值相乘就好了,也就是0.3333*2.0。那麼現在只要找到c->a的路徑就可以得到答案了。也就是對這個圖做個dfs的事。
不過這裏要注意一點,如果dfs用遞歸實現,會提示running error,我放到vs下調試發現是stack over flow也就是遞歸導致內存溢出了,所以只好考慮用dfs的非遞歸的版本去實現。
好了,下面先給出代碼,然後再分析代碼吧
class Solution {
public:
vector<double> calcEquation(vector<pair<string, string>> equations, vector<double>& values, vector<pair<string, string>> queries) {
unordered_map<string, int> symbol;
int index = 0;
vector<double> res;
for (int i = 0; i<equations.size(); i++) {
if (symbol.find(equations[i].first) == symbol.end()) {
symbol[equations[i].first] = index++;
}
if (symbol.find(equations[i].second) == symbol.end()) {
symbol[equations[i].second] = index++;
}
}
vector<vector<double>> graph;/*define the graph*/
/*init the graph*/
for (int i = 0; i<index; i++) {
graph.emplace_back(vector<double>());
for (int j = 0; j<index; j++) {
if (i == j)
graph[i].emplace_back(1.0);
else
graph[i].emplace_back(-1.0);
}
}
/*create all edges*/
for (int i = 0; i<equations.size(); i++) {
int a = symbol[equations[i].first];
int b = symbol[equations[i].second];
graph[a][b] = values[i];
graph[b][a] = 1.0 / values[i];
}
/*get the result*/
for (int i = 0; i<queries.size(); i++) {
if (symbol.find(queries[i].first) == symbol.end() || symbol.find(queries[i].second) == symbol.end())
res.emplace_back(-1.0);
else
res.emplace_back(getRes(symbol[queries[i].first], symbol[queries[i].second], graph));
}
return res;
}
private:
double getRes(int start, int end, vector<vector<double>> graph) {/*get the weight from start to end*/
return dfs(start,end,graph);
}
double dfs(int start ,int end, vector<vector<double>> graph) {
if (start == end)
return 1.0;
double temp = 1.0;
double priortemp=1.0;
vector<bool> visited;
for (int i = 0; i < graph.size(); i++)
visited.emplace_back(false);
stack<int> m_stack;
m_stack.push(start);
visited[start] = true;
while (!m_stack.empty()) {
int tmp = m_stack.top();
int i = 0;
for (i = 0; i < graph.size(); i++) {
if (visited[i]|| graph[tmp][i] == -1.0)
continue;
m_stack.push(i);
visited[i] = true;
priortemp=temp;
temp *= graph[tmp][i];
if (i == end) {
return temp;
}
break;
}
if (i == graph.size()){/*back to the prior state*/
m_stack.pop();
temp=priortemp;
}
}
return -1.0;
}
};
calcEquation()先從這個函數開始吧。首先我懶的用鄰接表去存儲圖,所以就想用鄰接矩陣去存,但是這題目給了一大堆字符串,肯定不方便用下標去表示,於是我想到先用unordered_map先把這些字符串和下標綁定,接着直接用這些下標用vector建立一個鄰接矩陣。之後就是對題目給定的表達式逐個求值了。再來講講dfs函數,這是一個簡單的dfs非遞歸實現,但是要注意,我使用了一個priortemp變量來記錄回溯時要用的值。嗯,差不多就這樣吧