Evaluate the Fractions
Last Updated :
18 Mar, 2024
Given a 2D array fractions[] and an array value [ ], which denotes that the value of the 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 …(equation i) , …(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
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.
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
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)
Outputa / 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)
Share your thoughts in the comments
Please Login to comment...