Open In App

Evaluate the Fractions

Last Updated : 18 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given a 2D array fractions[] and an array value [ ], which denotes that the value of the [Tex]fractions[i][0]/fractions[i][1] = values[i] [/Tex] for each index ‘i’, you have Q queries of the form [var1, var2]. Print the value of var1/var2 if it can be determined or else print -1. You may assume that there won’t be any contradicting equations and that no division by zero will occur.

Examples:

Input: fractions[]=[[“a”, “b”], [“b”, “c”]], values[]=[2.0, 3.0], queries=[[“a”,”c”],[“b”,”a”],[“a”,”e”],[“a”,”a”],[“x”,”x”]]
Output: [6.0, 0.5, -1.0, 1.0, -1.0]
Explanation: given [Tex]a/b=2.0 [/Tex] …(equation i) , [Tex]b/c=3.0 [/Tex] …(equation ii)
query[0] = a/c = 6.0 (by multiplying equation i and equation ii)
query[1] = b/a = 0.5 (by reciprocal of equation i)
query[2] = a/e = -1.0 (variable e is unknown)
query[3] = a/a = 1.0 (numerator and denominator cancels each other)
query[4] = x/x =-1.0 (variable x is unknown)

Input: fractions[]=[[“a”, “b”]], values=[3.0], queries=[[“b”, “a”], [“a”, “c”]]
Output: [0.333333, -1.0]
Explanation: given [Tex]a/b=3.0 [/Tex]
query[0] = b/a = 1/3.0 = 0.3333333
query[1] = a/c = -1 (variable c is unknown)

Approach: Using Hash-Map and applying DFS on Directed Graph.

We can construct a directed graph for the equation a/b=x by creating two vertices a and b such that the edge from a to b has value=x while the edge from b to a has value=1/x. This can be done for each equation.

For each query of form we can run a DFS from node c to d and multiply each edge value in the DFS path to get our answer for c/d.

Illustration:

Suppose, fractions[]=[[‘a’, ‘b’],[‘b’, ‘c’],[‘c’, ‘d’]] , values[]=[2 , 3 , 1/3] , queries=[[‘a’,’d’]]

Step 1: Create a graph such that variables of fraction array are vertices and use values array to add edges between the variables as shown in fig-1.

Graph-To-Evaluate-The-Fraction

fig-1

Step 2: To calculate the value of “a/d” , simply run dfs on vertex ‘a‘ untill you find vertex ‘d‘ as shown in fig-2

Running-DFS-To-Evaluate-The-Fraction

fig-2

Step by step Algorithm:

  • Use the equations[] and values[] arrays to create a directed graph ‘graph‘ such that:
    • Edge from equations[i][0] to equations[i][1] has weight=values[i].
    • Edge from equations[i][1] to equations[i][0] has weight=1/values[i].
  • We can use a hashmap ‘fractions‘ to efficiently store and retrieve the above information.
  • For each query run a DFS where the start point is queries[i][0] and the end point is queries[i][0].
    • If the DFS reaches the endpoint, return the answer as the product of every edge weight in the DFS path
    • Else return -1, as the answer does not exist.
  • In case a variable of the query does not exist in our initial graph, we return -1.

Below is the implementation of the above algorithm.

C++

// C++ code for the above approach: #include <bits/stdc++.h> using namespace std; // Graph where vertices are strings. map<string, vector<string> > graph; // Map to store fractions and their values. map<string, double> fractions; // ans variable to store our final result // for each query double ans; // DFS function void dfs(string st, string en, map<string, int>& visited, bool& flag, double val) { // base case when end is reached if (st == en) { ans = val; flag = true; return; } // base case when vertex is already visited if (visited[st]) return; visited[st] = 1; // calling dfs on all the adjacent vertices for (auto child : graph[st]) { dfs(child, en, visited, flag, val * fractions[st + "/" + child]); if (flag) return; } } // Function to solve the problem void calculateFraction(vector<vector<string> >& equations, vector<double>& values, vector<vector<string> >& queries) { // Initializing the graph and storing the values // of the fractions for (int i = 0; i < equations.size(); i++) { string u = equations[i][0]; string v = equations[i][1]; double val = values[i]; // Graph initialization graph[u].push_back(v); graph[v].push_back(u); // Fraction initialization fractions[u + "/" + v] = val; fractions[v + "/" + u] = 1 / val; } vector<double> answer; // Loop to process each query for (auto q : queries) { string dfs_begin = q[0]; string dfs_end = q[1]; // If a variable does not exist in our // graph we store -1 as result if (graph.find(dfs_begin) == graph.end() || graph.find(dfs_end) == graph.end()) { answer.push_back(-1.0); } else { // Calling dfs for the case when // variable exists in the graph map<string, int> visited; // Flag to check whether the end point // is reached or not bool flag = false; ans = 1.0; dfs(dfs_begin, dfs_end, visited, flag, ans); if (flag) { answer.push_back(ans); } else answer.push_back(-1.0); } } // Printing answer for each query for (int i = 0; i < queries.size(); i++) { string u = queries[i][0]; string v = queries[i][1]; double ans = answer[i]; cout << u << " / " << v << " = " << ans << endl; } } // Driver Code int main() { // Test case input vector<vector<string> > equations = { { "a", "b" }, { "b", "c" } }; vector<double> values = { 2.0, 3.0 }; vector<vector<string> > queries = { { "a", "c" }, { "b", "a" }, { "a", "e" }, { "a", "a" }, { "x", "x" } }; // Function call to solve the problem calculateFraction(equations, values, queries); return 0; }

Java

// Java code for the above approach: import java.util.*; public class Main { // Graph where vertices are strings. static Map<String, List<String>> graph = new HashMap<>(); // Map to store fractions and their values. static Map<String, Double> fractions = new HashMap<>(); // ans variable to store our final result for each query static double ans; // DFS function static void dfs(String st, String en, Map<String, Integer> visited, boolean[] flag, double val) { // base case when end is reached if (st.equals(en)) { ans = val; flag[0] = true; return; } // base case when vertex is already visited if (visited.containsKey(st)) return; visited.put(st, 1); // calling dfs on all the adjacent vertices for (String child : graph.get(st)) { dfs(child, en, visited, flag, val * fractions.get(st + "/" + child)); if (flag[0]) return; } } // Function to solve the problem static void calculateFraction(List<List<String>> equations, List<Double> values, List<List<String>> queries) { // Initializing the graph and storing the values of the fractions for (int i = 0; i < equations.size(); i++) { String u = equations.get(i).get(0); String v = equations.get(i).get(1); double val = values.get(i); // Graph initialization graph.computeIfAbsent(u, k -> new ArrayList<>()).add(v); graph.computeIfAbsent(v, k -> new ArrayList<>()).add(u); // Fraction initialization fractions.put(u + "/" + v, val); fractions.put(v + "/" + u, 1 / val); } List<Double> answer = new ArrayList<>(); // Loop to process each query for (List<String> q : queries) { String dfs_begin = q.get(0); String dfs_end = q.get(1); // If a variable does not exist in our graph we store -1 as result if (!graph.containsKey(dfs_begin) || !graph.containsKey(dfs_end)) { answer.add(-1.0); } else { // Calling dfs for the case when variable exists in the graph Map<String, Integer> visited = new HashMap<>(); // Flag to check whether the end point is reached or not boolean[] flag = {false}; ans = 1.0; dfs(dfs_begin, dfs_end, visited, flag, ans); if (flag[0]) { answer.add(ans); } else answer.add(-1.0); } } // Printing answer for each query for (int i = 0; i < queries.size(); i++) { String u = queries.get(i).get(0); String v = queries.get(i).get(1); double ans = answer.get(i); System.out.println(u + " / " + v + " = " + ans); } } // Driver Code public static void main(String[] args) { // Test case input List<List<String>> equations = Arrays.asList( Arrays.asList("a", "b"), Arrays.asList("b", "c") ); List<Double> values = Arrays.asList(2.0, 3.0); List<List<String>> queries = Arrays.asList( Arrays.asList("a", "c"), Arrays.asList("b", "a"), Arrays.asList("a", "e"), Arrays.asList("a", "a"), Arrays.asList("x", "x") ); // Function call to solve the problem calculateFraction(equations, values, queries); } }

C#

using System; using System.Collections.Generic; class Program { // Graph where vertices are strings. static Dictionary<string, List<string>> graph = new Dictionary<string, List<string>>(); // Map to store fractions and their values. static Dictionary<string, double> fractions = new Dictionary<string, double>(); // ans variable to store our final result // for each query static double ans = 0.0; // Driver Code static void Main(string[] args) { List<List<string>> equations = new List<List<string>>() { new List<string>() { "a", "b" }, new List<string>() { "b", "c" } }; List<double> values = new List<double>() { 2.0, 3.0 }; List<List<string>> queries = new List<List<string>>() { new List<string>() { "a", "c" }, new List<string>() { "b", "a" }, new List<string>() { "a", "e" }, new List<string>() { "a", "a" }, new List<string>() { "x", "x" } }; CalculateFraction(equations, values, queries); } // Function to solve the problem static void CalculateFraction(List<List<string>> equations, List<double> values, List<List<string>> queries) { // Initializing the graph and storing the values // of the fractions for (int i = 0; i < equations.Count; i++) { string u = equations[i][0]; string v = equations[i][1]; double val = values[i]; // Graph initialization if (!graph.ContainsKey(u)) { graph[u] = new List<string>(); } if (!graph.ContainsKey(v)) { graph[v] = new List<string>(); } graph[u].Add(v); graph[v].Add(u); // Fraction initialization fractions[u + "/" + v] = val; fractions[v + "/" + u] = 1 / val; } List<double> answer = new List<double>(); // Loop to process each query foreach (List<string> q in queries) { string dfs_begin = q[0]; string dfs_end = q[1]; // If a variable does not exist in our // graph we store -1 as result if (!graph.ContainsKey(dfs_begin) || !graph.ContainsKey(dfs_end)) { answer.Add(-1.0); } else { // Calling dfs for the case when // variable exists in the graph Dictionary<string, int> visited = new Dictionary<string, int>(); bool[] flag = new bool[1]; ans = 1.0; DFS(dfs_begin, dfs_end, visited, flag, ans); if (flag[0]) { answer.Add(ans); } else { answer.Add(-1.0); } } } // Printing answer for each query for (int i = 0; i < queries.Count; i++) { string u = queries[i][0]; string v = queries[i][1]; double ans = answer[i]; Console.WriteLine($"{u} / {v} = {ans}"); } } // DFS function static void DFS(string st, string en, Dictionary<string, int> visited, bool[] flag, double val) { // base case when end is reached if (st == en) { ans = val; flag[0] = true; return; } // base case when vertex is already visited if (visited.ContainsKey(st)) { return; } visited[st] = 1; // calling dfs on all the adjacent vertices foreach (string child in graph[st]) { DFS(child, en, visited, flag, val * fractions[st + "/" + child]); if (flag[0]) { return; } } } }

Javascript

// JavaScript code for the above approach // Graph where vertices are strings. const graph = new Map(); // Map to store fractions and their values. const fractions = new Map(); // Variable to store our final result for each query let ans; // Depth-First Search (DFS) function function dfs(st, en, visited, flag, val) { // Base case when the end is reached if (st === en) { ans = val; flag.flag = true; return; } // Base case when the vertex is already visited if (visited[st]) return; visited[st] = 1; // Calling DFS on all the adjacent vertices for (const child of graph.get(st)) { dfs(child, en, visited, flag, val * fractions.get(st + "/" + child)); if (flag.flag) return; } } // Function to solve the problem function calculateFraction(equations, values, queries) { // Initializing the graph and storing the values of the fractions for (let i = 0; i < equations.length; i++) { const u = equations[i][0]; const v = equations[i][1]; const val = values[i]; // Graph initialization if (!graph.has(u)) graph.set(u, []); if (!graph.has(v)) graph.set(v, []); graph.get(u).push(v); graph.get(v).push(u); // Fraction initialization fractions.set(u + "/" + v, val); fractions.set(v + "/" + u, 1 / val); } const answer = []; // Loop to process each query for (const q of queries) { const dfs_begin = q[0]; const dfs_end = q[1]; // If a variable does not exist in our graph, we store -1 as the result if (!graph.has(dfs_begin) || !graph.has(dfs_end)) { answer.push(-1.0); } else { // Calling DFS for the case when the variable exists in the graph const visited = {}; // Flag to check whether the endpoint is reached or not const flag = { flag: false }; ans = 1.0; dfs(dfs_begin, dfs_end, visited, flag, ans); if (flag.flag) { answer.push(ans); } else { answer.push(-1.0); } } } // Printing the answer for each query for (let i = 0; i < queries.length; i++) { const u = queries[i][0]; const v = queries[i][1]; const result = answer[i]; console.log(u + " / " + v + " = " + result); } } // Driver Code // Test case input const equations = [ ["a", "b"], ["b", "c"], ]; const values = [2.0, 3.0]; const queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"], ]; // Function call to solve the problem calculateFraction(equations, values, queries);

Python3

# Graph where vertices are strings. graph = {} # Map to store fractions and their values. fractions = {} # ans variable to store our final result # for each query ans = 0.0 # DFS function def dfs(st, en, visited, flag, val): global ans # base case when end is reached if st == en: ans = val flag[0] = True return # base case when vertex is already visited if visited.get(st, 0): return visited[st] = 1 # calling dfs on all the adjacent vertices for child in graph[st]: dfs(child, en, visited, flag, val * fractions[st + "/" + child]) if flag[0]: return # Function to solve the problem def calculateFraction(equations, values, queries): global ans # Initializing the graph and storing the values # of the fractions for i in range(len(equations)): u = equations[i][0] v = equations[i][1] val = values[i] # Graph initialization if u not in graph: graph[u] = [] if v not in graph: graph[v] = [] graph[u].append(v) graph[v].append(u) # Fraction initialization fractions[u + "/" + v] = val fractions[v + "/" + u] = 1 / val answer = [] # Loop to process each query for q in queries: dfs_begin = q[0] dfs_end = q[1] # If a variable does not exist in our # graph we store -1 as result if dfs_begin not in graph or dfs_end not in graph: answer.append(-1.0) else: # Calling dfs for the case when # variable exists in the graph visited = {} flag = [False] ans = 1.0 dfs(dfs_begin, dfs_end, visited, flag, ans) if flag[0]: answer.append(ans) else: answer.append(-1.0) # Printing answer for each query for i in range(len(queries)): u = queries[i][0] v = queries[i][1] ans = answer[i] print(f"{u} / {v} = {ans}") # Driver Code if __name__ == "__main__": # Test case input equations = [["a", "b"], ["b", "c"]] values = [2.0, 3.0] queries = [["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"]] # Function call to solve the problem calculateFraction(equations, values, queries)


Output

a / c = 6 b / a = 0.5 a / e = -1 a / a = 1 x / x = -1

Time Complexity: O(Q*N*log(N)), where Q is the number of queries and N is the number of unique variables in the fractions array
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads