Open In App

Longest Path with Maximum Letter Frequency

Last Updated : 23 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a graph with n vertex and m-directed edges. One lowercase letter is assigned to each vertex. The value of the path is the number of the most frequently occurring letters in the path. The task is to find a path whose value is the largest.

Example:

Input: n = 5, m = 4, node_value = “abaca”, edges[] = {1 2}, {1 3}, {3 4}, {4, 5}
Output: 3

Input: n = 6, m = 6, node_value = “xzyabc”, edges[] = {1, 2}, {3, 1}, {2, 3}, {5, 4}, {4, 3}, {6, 4}
Output: -1

Approach:

The idea is to use dynamic programming to avoid redundant traversal of nodes. Use a 2-D array ‘dp’, where dp[i][j] represents the maximum count of character ‘j’ when reaching node i. ‘i’ ranges from 1 to N, and ‘j’ from 0 to 25 (representing ‘a’ to ‘z’). Use topological sorting to calculate dp values, ensuring that nodes with edges to node ‘i’ are visited first. If a cycle is detected in the graph, the function returns -1 to indicate an infinitely large result due to repetitive traversal of the cycle.

Step-by-step approach:

  • Define ‘inDegree’ array for node indegrees, initially set to 0.
  • Iterate edges, updating ‘inDegree’ for each node.
  • Use a queue for topological order, enqueue nodes with ‘inDegree’ 0.
  • Pop the front element, increment character frequency in ‘dp’ array.
  • Update ‘dp’ array for adjacent nodes and adjust ‘inDegree’.
  • Enqueue nodes with ‘inDegree’ 0 after updating.
  • If queue has elements after ‘N’ pops, return -1 (cycle detected).
  • Return the maximum element in the ‘dp’ array.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
int maxPathValue(int n, int m, vector<vector<int> >& edges,
                 string& values)
{
    // Adjacency list.
    vector<int> adj[n + 1];
 
    // To store the indegree of each node.
    vector<int> inDegree(n + 1, 0);
 
    // Iterate through the edges.
    for (vector<int> i : edges) {
        adj[i[0]].push_back(i[1]);
        inDegree[i[1]]++;
    }
 
    // Queue for traversing the nodes in the topological
    // order.
    queue<int> q;
 
    // To store the frequency of each character for each
    // node.
    vector<vector<int> > dp(n + 1, vector<int>(26, 0));
 
    // Push all nodes with 0 indegree into the queue.
    for (int i = 1; i <= n; i++) {
        if (inDegree[i] == 0) {
            q.push(i);
        }
    }
 
    // To count the number of nodes popped from the queue.
    int popCounts = 0;
    int ans = 0;
 
    while (q.empty() == false) {
        // Pop the front node.
        int curr = q.front();
        q.pop();
        popCounts++;
 
        // Increment the value of the character assigned to
        // the current node.
        dp[curr][values[curr - 1] - 'a']++;
        ans = max(ans, dp[curr][values[curr - 1] - 'a']);
 
        // Iterate through all adjacent nodes.
        for (int i : adj[curr]) {
            // Update the dp array for the adjacent node.
            for (int j = 0; j < 26; j++) {
                dp[i][j] = max(dp[i][j], dp[curr][j]);
            }
            inDegree[i]--;
 
            // Push the node into the queue if all incoming
            // edges to that node have been traversed.
            if (inDegree[i] == 0) {
                q.push(i);
            }
        }
        if (popCounts == n) {
            break;
        }
    }
    // Check whether there is a cycle or not.
    if (q.empty() == false || popCounts < n) {
        return -1;
    }
    return ans;
}
 
int main()
{
    // Example inputs
    int n = 5;
    int m = 4;
    vector<vector<int> > edges
        = { { 1, 2 }, { 1, 3 }, { 3, 4 }, { 4, 5 } };
    string values = "abaca";
 
    // Function call
    int result = maxPathValue(n, m, edges, values);
 
    // Display the result
    if (result != -1) {
        cout << "Maximum path value: " << result << endl;
    }
    else {
        cout << "-1" << endl;
    }
 
    return 0;
}


Java




import java.util.*;
 
public class MaxPathValue {
 
    // Function to find the maximum path value
    public static int
    maxPathValue(int n, int m, List<List<Integer> > edges,
                 String values)
    {
        // Adjacency list to represent the graph
        List<List<Integer> > adj = new ArrayList<>(n + 1);
        for (int i = 0; i <= n; i++) {
            adj.add(new ArrayList<>());
        }
 
        // To store the in-degree of each node
        List<Integer> inDegree = new ArrayList<>(
            Collections.nCopies(n + 1, 0));
 
        // Build the adjacency list and in-degree array
        for (List<Integer> edge : edges) {
            adj.get(edge.get(0)).add(edge.get(1));
            inDegree.set(edge.get(1),
                         inDegree.get(edge.get(1)) + 1);
        }
 
        // Queue for topological order traversal
        Queue<Integer> q = new LinkedList<>();
 
        // DP array to store the frequency of each character
        // for each node
        List<List<Integer> > dp = new ArrayList<>(n + 1);
        for (int i = 0; i <= n; i++) {
            dp.add(new ArrayList<>(
                Collections.nCopies(26, 0)));
        }
 
        // Push nodes with in-degree 0 into the queue
        for (int i = 1; i <= n; i++) {
            if (inDegree.get(i) == 0) {
                q.offer(i);
            }
        }
 
        int popCounts = 0;
        int ans = 0;
 
        // Perform topological order traversal
        while (!q.isEmpty()) {
            int curr = q.poll();
            popCounts++;
 
            // Increment the value of the character assigned
            // to the current node
            dp.get(curr).set(
                values.charAt(curr - 1) - 'a',
                dp.get(curr).get(values.charAt(curr - 1)
                                 - 'a')
                    + 1);
            ans = Math.max(
                ans, dp.get(curr).get(
                         values.charAt(curr - 1) - 'a'));
 
            // Update the DP array for adjacent nodes
            for (int i : adj.get(curr)) {
                for (int j = 0; j < 26; j++) {
                    dp.get(i).set(
                        j, Math.max(dp.get(i).get(j),
                                    dp.get(curr).get(j)));
                }
                inDegree.set(i, inDegree.get(i) - 1);
 
                // Push the node into the queue if all
                // incoming edges to that node have been
                // traversed
                if (inDegree.get(i) == 0) {
                    q.offer(i);
                }
            }
 
            // Break if all nodes have been processed
            if (popCounts == n) {
                break;
            }
        }
 
        // Check whether there is a cycle or not
        if (!q.isEmpty() || popCounts < n) {
            return -1;
        }
        return ans;
    }
 
    // Main method for testing
    public static void main(String[] args)
    {
        // Example inputs
        int n = 5;
        int m = 4;
        List<List<Integer> > edges = Arrays.asList(
            Arrays.asList(1, 2), Arrays.asList(1, 3),
            Arrays.asList(3, 4), Arrays.asList(4, 5));
        String values = "abaca";
 
        // Function call
        int result = maxPathValue(n, m, edges, values);
 
        // Display the result
        if (result != -1) {
            System.out.println("Maximum path value: "
                               + result);
        }
        else {
            System.out.println("-1");
        }
    }
}


Python3




# Python code for the above approach
 
from collections import deque
 
def maxPathValue(n, m, edges, values):
    # Adjacency list.
    adj = [[] for _ in range(n+1)]
    # vector<int> adj[n + 1];
 
    # To store the indegree of each node.
    inDegree = [0 for _ in range(n+1)]
 
    # Iterate through the edges.
    for i in edges:
        adj[i[0]].append(i[1])
        inDegree[i[1]] += 1
 
    # Queue for traversing the nodes in the
    # topological order.
    q = deque()
 
    # To store the frequency of each character
    # for each node.
    dp = [[0 for j in range(26)] for i in range(n+1)]
 
    # Push all nodes with 0 indegree into the queue.
    for i in range(1, n+1):
        if (inDegree[i] == 0):
            q.append(i)
 
    # To count the number of nodes popped from the queue.
    popCounts, ans = 0, 0
 
    while len(q):
        # Pop the front node.
        curr = q.popleft()
        popCounts += 1
 
        # Increment the value of the character assigned to
        # the current node.
        dp[curr][ord(values[curr - 1]) - ord('a')] += 1
        ans = max(ans, dp[curr][ord(values[curr - 1]) - ord('a')])
 
        # Iterate through all adjacent nodes.
        for i in adj[curr]:
            # Update the dp array for the adjacent node.
            for j in range(26):
                dp[i][j] = max(dp[i][j], dp[curr][j])
 
            inDegree[i] -= 1
 
            # Push the node into the queue if all incoming
            # edges to that node have been traversed.
            if (inDegree[i] == 0):
                q.append(i)
 
        if (popCounts == n):
            break
 
    # Check whether there is a cycle or not.
    if (len(q) > 0 or popCounts < n):
        return -1
    return ans
 
def main():
    # Example inputs
    n, m = 5, 4
 
    edges = [[1, 2], [1, 3], [3, 4], [4, 5]]
    values = "abaca"
 
    # Function call
    result = maxPathValue(n, m, edges, values)
 
    # Display the result
    if (result != -1):
        print("Maximum path value:", result)
    else:
        print("-1")
 
if __name__ == '__main__':
    main()
 
# This code is contributed by ragul21


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
class MainClass {
    static int MaxPathValue(int n, int m, List<List<int>> edges, string values) {
        List<List<int>> adj = new List<List<int>>();
        for (int i = 0; i <= n; i++) {
            adj.Add(new List<int>());
        }
 
        List<int> inDegree = new List<int>(new int[n + 1]);
        List<List<int>> dp = new List<List<int>>();
        for (int i = 0; i <= n; i++) {
            dp.Add(Enumerable.Repeat(0, 26).ToList());
        }
 
        foreach (var edge in edges) {
            adj[edge[0]].Add(edge[1]);
            inDegree[edge[1]]++;
        }
 
        Queue<int> q = new Queue<int>();
 
        for (int i = 1; i <= n; i++) {
            if (inDegree[i] == 0) {
                q.Enqueue(i);
            }
        }
 
        int popCounts = 0;
        int ans = 0;
 
        while (q.Count != 0) {
            int curr = q.Dequeue();
            popCounts++;
 
            dp[curr][values[curr - 1] - 'a']++;
            ans = Math.Max(ans, dp[curr][values[curr - 1] - 'a']);
 
            foreach (int i in adj[curr]) {
                for (int j = 0; j < 26; j++) {
                    dp[i][j] = Math.Max(dp[i][j], dp[curr][j]);
                }
                inDegree[i]--;
 
                if (inDegree[i] == 0) {
                    q.Enqueue(i);
                }
            }
            if (popCounts == n) {
                break;
            }
        }
 
        if (q.Count != 0 || popCounts < n) {
            return -1;
        }
        return ans;
    }
 
    public static void Main (string[] args) {
        int n = 5;
        int m = 4;
        List<List<int>> edges = new List<List<int>> {
            new List<int> { 1, 2 },
            new List<int> { 1, 3 },
            new List<int> { 3, 4 },
            new List<int> { 4, 5 }
        };
        string values = "abaca";
 
        int result = MaxPathValue(n, m, edges, values);
 
        if (result != -1) {
            Console.WriteLine("Maximum path value: " + result);
        } else {
            Console.WriteLine("-1");
        }
    }
}


Javascript




function maxPathValue(n, m, edges, values) {
    const adj = new Array(n + 1).fill(null).map(() => []);
    const inDegree = new Array(n + 1).fill(0);
    const dp = new Array(n + 1).fill(null).map(() => new Array(26).fill(0));
 
    for (const [u, v] of edges) {
        adj[u].push(v);
        inDegree[v]++;
    }
 
    const q = [];
    let popCounts = 0;
    let ans = 0;
 
    for (let i = 1; i <= n; i++) {
        if (inDegree[i] === 0) {
            q.push(i);
        }
    }
 
    while (q.length > 0) {
        const curr = q.shift();
        popCounts++;
 
        dp[curr][values.charCodeAt(curr - 1) - 'a'.charCodeAt(0)]++;
        ans = Math.max(ans, dp[curr][values.charCodeAt(curr - 1) - 'a'.charCodeAt(0)]);
 
        for (const next of adj[curr]) {
            for (let j = 0; j < 26; j++) {
                dp[next][j] = Math.max(dp[next][j], dp[curr][j]);
            }
 
            inDegree[next]--;
 
            if (inDegree[next] === 0) {
                q.push(next);
            }
        }
 
        if (popCounts === n) {
            break;
        }
    }
 
    if (q.length > 0 || popCounts < n) {
        return -1;
    }
 
    return ans;
}
 
// Example inputs
const n = 5;
const m = 4;
const edges = [[1, 2], [1, 3], [3, 4], [4, 5]];
const values = 'abaca';
 
// Function call
const result = maxPathValue(n, m, edges, values);
 
// Display the result
if (result !== -1) {
    console.log(`Maximum path value: ${result}`);
} else {
    console.log('-1');
}
 
 
// This code is contributed by akshitaguprzj3


Output

Maximum path value: 3









Time Complexity: O(N), Where ‘N’ is the number of nodes in the given graph.
Auxiliary Space: O(N)



Similar Reads

Count of words whose i-th letter is either (i-1)-th, i-th, or (i+1)-th letter of given word
Given a string str. The task is to count the words having the same length as str and each letter at the i-th position is either (i-1)-th, i-th, or (i+1)-th position letter of str.Note: For the first letter consider i-th and (i+1)-th position letter of W. And for last letter consider (i-1)-th and i-th position letter of str. Examples: Input : str[]
7 min read
Minimum deletions required to make frequency of each letter unique
Content removed for this article.
1 min read
Program to perform a letter frequency attack on a monoalphabetic substitution cipher
Given a string S of size N representing a monoalphabetic cipher, the task is to print the top five possible plain texts that can be decrypted from the given monoalphabetic cipher using a letter frequency attack. Examples: Input: S = "ETAOINSHRDLCUMWFGYPBVKJXQZ"Output: A SIMPLE MESSAGE B TJNQMF NFTTBHF A SIMPLE MESSAGE C UKORNG OGUUCIG C UKORNG OGUU
13 min read
Construct String with given frequency and minimum continuous occurrence of a letter
Construct a string that contains a times letter 'A' and b times letter 'B' (a &gt; b) such that the maximum continuous occurrence of a letter is as small as possible. Examples: Input: a = 4, b = 3 Output: ABABABAExplanation: The other possible ways could be "AAAABBB" or "AABBAAB" etc. But "ABABABA" is the most optimum solution with minimum consecut
7 min read
Remove at most K letter to equalize the frequency
Given a string S of length n, consisting of lowercase English letters. The task is to check if it is possible to remove at most K letter from S such that the frequency of every remaining letter is equal. Examples: Input: S = "aabbcc", K = 2Output: TrueExplanation: We can remove one 'a' and one 'b' to get "abbcc", where the frequency of each remaini
3 min read
Maximum length prefix such that frequency of each character is atmost number of characters with minimum frequency
Given a string S, the task is to find the prefix of string S with the maximum possible length such that frequency of each character in the prefix is at most the number of characters in S with minimum frequency. Examples: Input: S = 'aabcdaab' Output: aabcd Explanation: Frequency of characters in the given string - {a: 4, b: 2, c: 1, d: 1} Minimum f
8 min read
Maximum difference between frequency of two elements such that element having greater frequency is also greater
Given an array of n positive integers with many repeating elements. The task is to find the maximum difference between the frequency of any two different elements, such that the element with greater frequency is also greater in value than the second integer. Examples: Input : arr[] = { 3, 1, 3, 2, 3, 2 }. Output : 2 Frequency of 3 = 3. Frequency of
12 min read
Generate a number such that the frequency of each digit is digit times the frequency in given number
Given a number N containing digits from 1 to 9 only. The task is to generate a new number using the number N such that the frequency of each digit in the new number is equal to the frequency of that digit in N multiplied by the digit itself.Note: The digits in the new number must be in increasing order.Examples: Input : N = 312 Output : 122333 Expl
8 min read
Check if frequency of character in one string is a factor or multiple of frequency of same character in other string
Given two strings, the task is to check whether the frequencies of a character(for each character) in one string are multiple or a factor in another string. If it is, then output "YES", otherwise output "NO". Examples: Input: s1 = "aabccd", s2 = "bbbaaaacc" Output: YES Frequency of 'a' in s1 and s2 are 2 and 4 respectively, and 2 is a factor of 4 F
6 min read
Count of Binary Strings of length N such that frequency of 1's exceeds frequency of 0's
Given an integer N, the task is to find the number of Binary Strings of length N such that frequency of 1's is greater than the frequency of 0's. Example: Input: N = 2Output: 1Explanation: Count of binary strings of length 2 is 4 i.e. {"00", "01", "10", "11"}. The only string having frequency of 1's greater than that of 0's is "11". Input: N = 3Out
8 min read