Given two sorted arrays of distinct integers, arr1[] and arr2[], which may have some common elements, find the maximum sum of a path from the beginning of any array to the end of any array. You may switch from one array to the other only at common elements.
Note: When switching, count the common element only once.
Examples:
Input: arr1[] = [2, 3, 7, 10, 12], arr2[] = [1, 5, 7, 8]
Output: 35
Explanation: The path will be (1 + 5 + 7 + 10 + 12) = 35, where 1 and 5 come from arr2 and then 7 is common so we switch to arr1 and add 10 and 12.Input: arr1[] = [1, 2, 3], arr2 = [3, 4, 5]
Output: 15
Explanation: The path will be (1 + 2 + 3 + 4 + 5) = 15.Input: arr1[] = [2, 3, 7, 10, 12, 15, 30, 34], arr2[] = [1, 5, 7, 8, 10, 15, 16, 19]
Output: 122
Explanation: 122 is sum of 1, 5, 7, 8, 10, 12, 15, 30, 34. Start from the first element of arr2 which is 1, then move to 5, then 7. From 7 switch to arr1 (as 7 is common), then traverse the remaining arr1.
Table of Content
[Naive Approach] Using Recursion - O(2^k) Time and O(n + m) Space
We can explore all possible valid paths. We traverse the array recursively, and every time we land on a common element, you branch your recursive function into two choices: stay in the current array or switch to the other. Then return the path that yields the highest sum. If there are k common elements we can do this in 2^k time complexity.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
// Helper to find the index of a target (returns -1 if not found)
int indexOf(vector<int> arr, int target)
{
for (int i = 0; i < arr.size(); i++)
{
if (arr[i] == target)
return i;
}
return -1;
}
// f = true means we are currently in arr1. f = false means arr2.
int solve(int i, int j, bool f, vector<int> arr1, vector<int> arr2)
{
// Base cases: reached the end of the active array
if (f && i == arr1.size())
return 0;
if (!f && j == arr2.size())
return 0;
if (f)
{
int matchIdx = indexOf(arr2, arr1[i]);
// Path 1: Stay in array 1
int stay = arr1[i] + solve(i + 1, j, true, arr1, arr2);
// Path 2: Switch to array 2 (only valid if it's a common element)
int swap = (matchIdx != -1) ? arr1[i] + solve(i + 1, matchIdx + 1, false, arr1, arr2) : 0;
return max(stay, swap);
}
else
{
int matchIdx = indexOf(arr1, arr2[j]);
// Path 1: Stay in array 2
int stay = arr2[j] + solve(i, j + 1, false, arr1, arr2);
// Path 2: Switch to array 1
int swap = (matchIdx != -1) ? arr2[j] + solve(matchIdx + 1, j + 1, true, arr1, arr2) : 0;
return max(stay, swap);
}
}
int maxPathSum(vector<int> arr1, vector<int> arr2)
{
// Try starting from both arrays and take the maximum
int startInArr1 = solve(0, 0, true, arr1, arr2);
int startInArr2 = solve(0, 0, false, arr1, arr2);
return max(startInArr1, startInArr2);
}
int main()
{
vector<int> arr1 = {2, 3, 7, 10, 12, 15, 30, 34};
vector<int> arr2 = {1, 5, 7, 8, 10, 15, 16, 19};
cout << maxPathSum(arr1, arr2);
return 0;
}
class Solution {
// Helper to find the index of a target (returns -1 if
// not found)
int indexOf(int[] arr, int target)
{
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target)
return i;
}
return -1;
}
// f = true means we are currently in arr1. f = false
// means arr2.
public int solve(int i, int j, boolean f, int[] arr1,
int[] arr2)
{
// Base cases: reached the end of the active array
if (f && i == arr1.length)
return 0;
if (!f && j == arr2.length)
return 0;
if (f) {
int matchIdx = indexOf(arr2, arr1[i]);
// Path 1: Stay in array 1
int stay = arr1[i]
+ solve(i + 1, j, true, arr1, arr2);
// Path 2: Switch to array 2 (only valid if it's
// a common element)
int swap
= (matchIdx != -1)
? arr1[i]
+ solve(i + 1, matchIdx + 1,
false, arr1, arr2)
: 0;
return Math.max(stay, swap);
}
else {
int matchIdx = indexOf(arr1, arr2[j]);
// Path 1: Stay in array 2
int stay = arr2[j]
+ solve(i, j + 1, false, arr1, arr2);
// Path 2: Switch to array 1
int swap
= (matchIdx != -1)
? arr2[j]
+ solve(matchIdx + 1, j + 1,
true, arr1, arr2)
: 0;
return Math.max(stay, swap);
}
}
public int maxPathSum(int[] arr1, int[] arr2)
{
// Try starting from both arrays and take the
// maximum
int startInArr1 = solve(0, 0, true, arr1, arr2);
int startInArr2 = solve(0, 0, false, arr1, arr2);
return Math.max(startInArr1, startInArr2);
}
public static void main(String[] args)
{
// Create an instance of Solution to call the
// non-static methods
Solution obj = new Solution();
int[] arr1 = { 2, 3, 7, 10, 12 };
int[] arr2 = { 1, 5, 7, 8 };
int res = obj.maxPathSum(arr1, arr2);
System.out.println(res); // Expected Output: 35
}
}
def indexOf(arr, target):
for i in range(len(arr)):
if arr[i] == target:
return i
return -1
# f = true means we are currently in arr1. f = false means arr2.
def solve(i, j, f, arr1, arr2):
# Base cases: reached the end of the active array
if f and i == len(arr1):
return 0
if not f and j == len(arr2):
return 0
if f:
matchIdx = indexOf(arr2, arr1[i])
# Path 1: Stay in array 1
stay = arr1[i] + solve(i + 1, j, True, arr1, arr2)
# Path 2: Switch to array 2 (only valid if it's a common element)
swap = arr1[i] + solve(i + 1, matchIdx + 1, False,
arr1, arr2) if matchIdx != -1 else 0
return max(stay, swap)
else:
matchIdx = indexOf(arr1, arr2[j])
# Path 1: Stay in array 2
stay = arr2[j] + solve(i, j + 1, False, arr1, arr2)
# Path 2: Switch to array 1
swap = arr2[j] + solve(matchIdx + 1, j + 1, True,
arr1, arr2) if matchIdx != -1 else 0
return max(stay, swap)
def maxPathSum(arr1, arr2):
# Try starting from both arrays and take the maximum
startInArr1 = solve(0, 0, True, arr1, arr2)
startInArr2 = solve(0, 0, False, arr1, arr2)
return max(startInArr1, startInArr2)
arr1 = [2, 3, 7, 10, 12, 15, 30, 34]
arr2 = [1, 5, 7, 8, 10, 15, 16, 19]
print(maxPathSum(arr1, arr2))
using System;
public class Solution {
// Helper to find the index of a target (returns -1 if
// not found)
int indexOf(int[] arr, int target)
{
for (int i = 0; i < arr.Length; i++) {
if (arr[i] == target)
return i;
}
return -1;
}
// f = true means we are currently in arr1. f = false
// means arr2.
public int solve(int i, int j, bool f, int[] arr1,
int[] arr2)
{
// Base cases: reached the end of the active array
if (f && i == arr1.Length)
return 0;
if (!f && j == arr2.Length)
return 0;
if (f) {
int matchIdx = indexOf(arr2, arr1[i]);
// Path 1: Stay in array 1
int stay = arr1[i]
+ solve(i + 1, j, true, arr1, arr2);
// Path 2: Switch to array 2 (only valid if it's
// a common element)
int swap
= (matchIdx != -1)
? arr1[i]
+ solve(i + 1, matchIdx + 1,
false, arr1, arr2)
: 0;
return Math.Max(stay, swap);
}
else {
int matchIdx = indexOf(arr1, arr2[j]);
// Path 1: Stay in array 2
int stay = arr2[j]
+ solve(i, j + 1, false, arr1, arr2);
// Path 2: Switch to array 1
int swap
= (matchIdx != -1)
? arr2[j]
+ solve(matchIdx + 1, j + 1,
true, arr1, arr2)
: 0;
return Math.Max(stay, swap);
}
}
public int maxPathSum(int[] arr1, int[] arr2)
{
// Try starting from both arrays and take the
// maximum
int startInArr1 = solve(0, 0, true, arr1, arr2);
int startInArr2 = solve(0, 0, false, arr1, arr2);
return Math.Max(startInArr1, startInArr2);
}
public static void Main(string[] args)
{
// Create an instance of Solution to call the
// non-static methods
Solution obj = new Solution();
int[] arr1 = { 2, 3, 7, 10, 12 };
int[] arr2 = { 1, 5, 7, 8 };
int res = obj.maxPathSum(arr1, arr2);
Console.WriteLine(res); // Expected Output: 35
}
}
function indexOf(arr, target)
{
for (let i = 0; i < arr.length; i++) {
if (arr[i] === target) {
return i;
}
}
return -1;
}
// f = true means we are currently in arr1. f = false means
// arr2.
function solve(i, j, f, arr1, arr2)
{
// Base cases: reached the end of the active array
if (f && i === arr1.length) {
return 0;
}
if (!f && j === arr2.length) {
return 0;
}
if (f) {
let matchIdx = indexOf(arr2, arr1[i]);
// Path 1: Stay in array 1
let stay
= arr1[i] + solve(i + 1, j, true, arr1, arr2);
// Path 2: Switch to array 2 (only valid if it's a
// common element)
let swap = (matchIdx !== -1)
? arr1[i]
+ solve(i + 1, matchIdx + 1,
false, arr1, arr2)
: 0;
return Math.max(stay, swap);
}
else {
let matchIdx = indexOf(arr1, arr2[j]);
// Path 1: Stay in array 2
let stay
= arr2[j] + solve(i, j + 1, false, arr1, arr2);
// Path 2: Switch to array 1
let swap = (matchIdx !== -1)
? arr2[j]
+ solve(matchIdx + 1, j + 1,
true, arr1, arr2)
: 0;
return Math.max(stay, swap);
}
}
function maxPathSum(arr1, arr2)
{
// Try starting from both arrays and take the maximum
let startInArr1 = solve(0, 0, true, arr1, arr2);
let startInArr2 = solve(0, 0, false, arr1, arr2);
return Math.max(startInArr1, startInArr2);
}
let arr1 = [ 2, 3, 7, 10, 12, 15, 30, 34 ];
let arr2 = [ 1, 5, 7, 8, 10, 15, 16, 19 ];
console.log(maxPathSum(arr1, arr2));
Output
122
Using Two Pointers and Prefix Sum Traversal - O(n + m) Time and O(1) Space
The idea is to do something similar to the merge process of merge sort. This involves calculating the sum of elements between all common points of both arrays. Whenever there is a common point, compare the two sums and add the maximum of two to the result.
Follow the steps below to solve the given problem:
- Initialize result = 0, sum1 = 0, and sum2 = 0, where sum1 and sum2 store the sums between consecutive common elements.
- Traverse both sorted arrays simultaneously.
- If arr1[i] < arr2[j], add arr1[i] to sum1; otherwise, if arr2[j] < arr1[i], add arr2[j] to sum2.
- If both elements are equal, add max(sum1, sum2) and the common element to result, then reset sum1 and sum2.
- After traversal, add the larger of the remaining sums to result.
The good thing about this approach is, we cover all elements before reaching a common point. So when we are at a common point, we compare the two sums and decide which one to choose.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int maxPathSum(vector<int> &arr1, vector<int> &arr2)
{
int i = 0, j = 0;
int m = arr1.size(), n = arr2.size();
int result = 0, sum1 = 0, sum2 = 0;
// Using two pointers to iterate over two arrays
while (i < m && j < n)
{
// if arr1 is smaller than arr2,
// incresing arr1 and adding its value to sum1
if (arr1[i] < arr2[j])
{
sum1 += arr1[i++];
}
// if arr2 is smaller than arr1,
// incresing arr2 and adding its value to sum
else if (arr1[i] > arr2[j])
{
sum2 += arr2[j++];
}
// if arr1=arr2, checking the maximum sum obtained from both the arrays
// updating result and sum1 and sum2 is again changed to zero
else
{
result += max(sum1, sum2) + arr1[i];
sum1 = 0;
sum2 = 0;
i++;
j++;
}
}
// if jth pointer reaches end
while (i < m)
sum1 += arr1[i++];
// if ith pointer reaches end
while (j < n)
sum2 += arr2[j++];
// last maximum sum to be added after the end of the loop
result += max(sum1, sum2);
return result;
}
int main()
{
vector<int> arr1 = {2, 3, 7, 10, 12, 15, 30, 34};
vector<int> arr2 = {1, 5, 7, 8, 10, 15, 16, 19};
cout << maxPathSum(arr1, arr2);
return 0;
}
import java.util.Arrays;
class GFG {
public static int maxPathSum(int[] arr1, int[] arr2)
{
int i = 0, j = 0;
int m = arr1.length, n = arr2.length;
int result = 0, sum1 = 0, sum2 = 0;
// Using two pointers to iterate over two arrays
while (i < m && j < n) {
// if arr1 is smaller than arr2, incresing arr1
// and adding its value to sum1
if (arr1[i] < arr2[j]) {
sum1 += arr1[i++];
}
// if arr2 is smaller than arr1, incresing arr2
// and adding its value to sum
else if (arr1[i] > arr2[j]) {
sum2 += arr2[j++];
}
// if arr1=arr2, checking the maximum sum
// obtained from both the arrays updating result
// and sum1 and sum2 is again changed to zero
else {
result += Math.max(sum1, sum2) + arr1[i];
sum1 = 0;
sum2 = 0;
i++;
j++;
}
}
// if jth pointer reaches end
while (i < m)
sum1 += arr1[i++];
// if ith pointer reaches end
while (j < n)
sum2 += arr2[j++];
// last maximum sum to be added after the end of the
// loop
result += Math.max(sum1, sum2);
return result;
}
public static void main(String[] args)
{
int[] arr1 = { 2, 3, 7, 10, 12, 15, 30, 34 };
int[] arr2 = { 1, 5, 7, 8, 10, 15, 16, 19 };
System.out.println(maxPathSum(arr1, arr2));
}
}
def maxPathSum(arr1, arr2):
i = 0
j = 0
m = len(arr1)
n = len(arr2)
result = 0
sum1 = 0
sum2 = 0
# Using two pointers to iterate over two arrays
while i < m and j < n:
# if arr1 is smaller than arr2,
# incresing arr1 and adding its value to sum1
if arr1[i] < arr2[j]:
sum1 += arr1[i]
i += 1
# if arr2 is smaller than arr1,
# incresing arr2 and adding its value to sum
elif arr1[i] > arr2[j]:
sum2 += arr2[j]
j += 1
# if arr1=arr2, checking the maximum sum obtained from both the arrays
# updating result and sum1 and sum2 is again changed to zero
else:
result += max(sum1, sum2) + arr1[i]
sum1 = 0
sum2 = 0
i += 1
j += 1
# if jth pointer reaches end
while i < m:
sum1 += arr1[i]
i += 1
# if ith pointer reaches end
while j < n:
sum2 += arr2[j]
j += 1
# last maximum sum to be added after the end of the loop
result += max(sum1, sum2)
return result
if __name__ == '__main__':
arr1 = [2, 3, 7, 10, 12, 15, 30, 34]
arr2 = [1, 5, 7, 8, 10, 15, 16, 19]
print(maxPathSum(arr1, arr2))
using System;
public class GFG {
public static int maxPathSum(int[] arr1, int[] arr2) {
int i = 0, j = 0;
int m = arr1.Length, n = arr2.Length;
int result = 0, sum1 = 0, sum2 = 0;
// Using two pointers to iterate over two arrays
while (i < m && j < n) {
// if arr1 is smaller than arr2,
// increasing arr1 and adding its value to sum1
if (arr1[i] < arr2[j]) {
sum1 += arr1[i];
i++;
}
// if arr2 is smaller than arr1,
// increasing arr2 and adding its value to sum
else if (arr1[i] > arr2[j]) {
sum2 += arr2[j];
j++;
}
// if arr1=arr2, checking the maximum sum obtained from both the arrays
// updating result and sum1 and sum2 is again changed to zero
else {
result += Math.Max(sum1, sum2) + arr1[i];
sum1 = 0;
sum2 = 0;
i++;
j++;
}
}
// if jth pointer reaches end
while (i < m) {
sum1 += arr1[i];
i++;
}
// if ith pointer reaches end
while (j < n) {
sum2 += arr2[j];
j++;
}
// last maximum sum to be added after the end of the loop
result += Math.Max(sum1, sum2);
return result;
}
public static void Main(string[] args) {
int[] arr1 = {2, 3, 7, 10, 12, 15, 30, 34};
int[] arr2 = {1, 5, 7, 8, 10, 15, 16, 19};
Console.WriteLine(maxPathSum(arr1, arr2));
}
}
function maxPathSum(arr1, arr2)
{
let i = 0, j = 0;
let m = arr1.length, n = arr2.length;
let result = 0, sum1 = 0, sum2 = 0;
// Using two pointers to iterate over two arrays
while (i < m && j < n) {
// if arr1 is smaller than arr2, increasing arr1 and
// adding its value to sum1
if (arr1[i] < arr2[j]) {
sum1 += arr1[i++];
}
// if arr2 is smaller than arr1, increasing arr2 and
// adding its value to sum
else if (arr1[i] > arr2[j]) {
sum2 += arr2[j++];
}
// if arr1=arr2, checking the maximum sum obtained
// from both the arrays updating result and sum1 and
// sum2 is again changed to zero
else {
result += Math.max(sum1, sum2) + arr1[i];
sum1 = 0;
sum2 = 0;
i++;
j++;
}
}
// if jth pointer reaches end
while (i < m)
sum1 += arr1[i++];
// if ith pointer reaches end
while (j < n)
sum2 += arr2[j++];
// last maximum sum to be added after the end of the
// loop
result += Math.max(sum1, sum2);
return result;
}
// Driver code
let arr1 = [ 2, 3, 7, 10, 12, 15, 30, 34 ];
let arr2 = [ 1, 5, 7, 8, 10, 15, 16, 19 ];
console.log(maxPathSum(arr1, arr2));
Output
122