Longest Path with Maximum Letter Frequency
Last Updated :
23 Dec, 2023
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
OutputMaximum path value: 3
Time Complexity: O(N), Where 'N' is the number of nodes in the given graph.
Auxiliary Space: O(N)
Similar Reads
Maximum length substring with highest frequency in a string Given a string. The task is to find the maximum occurred substring with a maximum length. These occurrences can overlap. Examples: Input: str = "abab" Output: ab "a", "b", "ab" are occur 2 times. But, "ab" has maximum length Input: str = "abcd" Output: a Approach: The idea is to store the frequency
5 min read
Substring with highest frequency length product Given a string which contains lower alphabetic characters, we need to find out such a substring of this string whose product of length and frequency in string is maximum among all possible choices of substrings. Examples: Input : String str = âabddabâOutput : 6All unique substring with product of th
15+ min read
Length of the longest substring with no consecutive same letters Given a string str, the task is to find the length of the longest sub-string which does not have any pair of consecutive same characters. Examples: Input: str = "abcdde" Output: 4 "abcd" is the longestInput: str = "ccccdeededff" Output: 5 "ededf" is the longest Approach: The following steps can be f
7 min read
Split string to get maximum common characters Given a string S of length, N. Split them into two strings such that the number of common characters between the two strings is maximized and return the maximum number of common characters. Examples: Input: N = 6, S = abccbaOutput: 3Explanation: Splitting two strings as "abc" and "cba" has at most 3
6 min read
Substring of length K having maximum frequency in the given string Given a string str, the task is to find the substring of length K which occurs the maximum number of times. If more than one string occurs maximum number of times, then print the lexicographically smallest substring. Examples: Input: str = "bbbbbaaaaabbabababa", K = 5Output: ababaExplanation:The sub
14 min read