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 fractions[i][0]/fractions[i][1] = values[i]               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 a/b=2.0               …(equation i) , b/c=3.0               …(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 a/b=3.0
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