Talentd
FleetCode
Make and follow sheets.Sign in

Longest Common Subpath solution and explanation

HardArrayBinary SearchHash FunctionRolling Hash5 min read30.7% acceptanceUpdated 9 Apr 2026
LeetCode 1923. Longest Common SubpathHappy Coding · 27:15 · 2K viewsWatch on YouTube
4 more videos on this problem
  1. LeetCode 1923. Longest Common SubpathHappy Coding · 27:15 · 2K views
  2. LeetCode Weekly Contest 248 Question 4: Longest Common SubpathCoding Ninjas Webinars and Contest Editorials · 39:12 · 1K views
  3. 1923. Longest Common Subpath (Leetcode Hard)Programming Live with Larry · 1:25:40 · 859 views
  4. 【每日一题】1923. Longest Common Subpath, 7/5/2021Huifeng Guan · 50:29 · 779 views
  5. LeetCode 1923: Longest Common SubpathAlitaCode · 30:41 · 19 views

The problem

There is a country of n cities numbered from 0 to n - 1. In this country, there is a road connecting every pair of cities.

There are m friends numbered from 0 to m - 1 who are traveling through the country. Each one of them will take a path consisting of some cities. Each path is represented by an integer array that contains the visited cities in order. The path may contain a city more than once, but the same city will not be listed consecutively.

Given an integer n and a 2D integer array paths where paths[i] is an integer array representing the path of the ith friend, return the length of the longest common subpath that is shared by every friend's path, or 0 if there is no common subpath at all.

A subpath of a path is a contiguous sequence of cities within that path.

Example 1:

Input: n = 5, paths = [[0,1,2,3,4],
                       [2,3,4],
                       [4,0,1,2,3]]
Output: 2
Explanation: The longest common subpath is [2,3].

Example 2:

Input: n = 3, paths = [[0],[1],[2]]
Output: 0
Explanation: There is no common subpath shared by the three paths.

Example 3:

Input: n = 5, paths = [[0,1,2,3,4],
                       [4,3,2,1,0]]
Output: 1
Explanation: The possible longest common subpaths are [0], [1], [2], [3], and [4]. All have a length of 1.

Constraints:

  • 1 <= n <= 105
  • m == paths.length
  • 2 <= m <= 105
  • sum(paths[i].length) <= 105
  • 0 <= paths[i][j] < n
  • The same city is not listed multiple times consecutively in paths[i].

Approach overview

Problem Overview: You receive several paths representing sequences of cities visited by different travelers. Each path is an array of integers. The task is to find the maximum length of a subpath (contiguous segment) that appears in every path.

Approach 1: Using Hash Map for Efficient Lookup (Binary Search + Rolling Hash) (Time: O(N log N), Space: O(N))

This approach combines binary search with rolling hash. Instead of directly searching for the longest subpath, you binary search the answer length L. For each candidate length, compute rolling hashes for all subpaths of length L in every path. Store hashes from the first path in a hash set, then intersect with hashes from subsequent paths using a hash map or set lookups. If a common hash exists across all paths, length L is valid. Rolling hash allows constant‑time updates when sliding the window, which keeps substring comparisons efficient.

The key insight: checking whether a subpath of length L exists in all paths is easier than directly finding the maximum length. Binary search reduces the search space from all possible lengths to log N checks. Hash-based matching avoids expensive array comparisons. This technique is widely used in substring and sequence matching problems involving large datasets.

Approach 2: Using Sorting and Two-Pointer Technique (Suffix Array) (Time: O(N log N), Space: O(N))

This method builds a suffix array over the combined paths. Each suffix represents a starting point in one of the paths. After constructing and sorting suffixes lexicographically, compute the LCP (Longest Common Prefix) values between adjacent suffixes. A sliding window with two pointers scans the sorted suffix array while ensuring the window contains suffixes from all paths. The minimum LCP value within that window represents the longest shared prefix among those suffixes.

Sorting suffixes groups similar prefixes together, which makes shared subpaths easy to detect. The two-pointer window ensures that every path contributes at least one suffix to the current candidate group. The maximum valid LCP across such windows gives the final answer.

Recommended for interviews: The binary search + rolling hash solution is the most common interview answer. It demonstrates understanding of hash functions, sliding window hashing, and decision-based binary search. The suffix array method is more advanced and rarely required unless the interviewer specifically asks about suffix structures or large-scale string indexing.

Approach 1: Using Hash Map for Efficient Lookup

This approach involves using a hash map (or hash table) to efficiently solve the problem. The key insight is that we can keep track of elements and quickly perform lookups when needed. This allows us to achieve an optimal time complexity for certain operations by leveraging the hash map's average-case O(1) time for inserts and checks.

hash_map = {}

def insert(key):
    hash_map[key] = True


def exists(key):
    return key in hash_map


insert(10)
insert(20)
print(exists(10))  # prints True
print(exists(15))  # prints False
import java.util.HashMap;

public class HashMapExample {
    private static HashMap<Integer, Boolean> hashMap = new HashMap<>();

    public static void insert(int key) {
        hashMap.put(key, true);
    }

    public static boolean exists(int key) {
        return hashMap.containsKey(key);
    }

    public static void main(String[] args) {
        insert(10);
        insert(20);
        System.out.println(exists(10)); // prints true
        System.out.println(exists(15)); // prints false
    }
}
#include <iostream>
#include <unordered_map>

std::unordered_map<int, bool> hashMap;

void insert(int key) {
    hashMap[key] = true;
}

bool exists(int key) {
    return hashMap.find(key) != hashMap.end();
}

int main() {
    insert(10);
    insert(20);
    std::cout << exists(10) << std::endl; // prints 1
    std::cout << exists(15) << std::endl; // prints 0
    return 0;
}
let hashMap = {};

function insert(key) {
    hashMap[key] = true;
}

function exists(key) {
    return hashMap.hasOwnProperty(key);
}

insert(10);
insert(20);
console.log(exists(10)); // prints true
console.log(exists(15)); // prints false
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 1000

int hash_map[MAX];

void init() {
    memset(hash_map, -1, sizeof(hash_map));
}

void insert(int key) {
    int index = key % MAX;
    if (hash_map[index] == -1) {
        hash_map[index] = key;
    }
}

int exists(int key) {
    int index = key % MAX;
    return hash_map[index] == key;
}

int main() {
    init();
    insert(10);
    insert(20);
    printf("%d\n", exists(10)); // prints 1
    printf("%d\n", exists(15)); // prints 0
    return 0;
}
using System;
using System.Collections.Generic;

class Program {
    private static Dictionary<int, bool> hashMap = new Dictionary<int, bool>();

    public static void Insert(int key) {
        hashMap[key] = true;
    }

    public static bool Exists(int key) {
        return hashMap.ContainsKey(key);
    }

    static void Main() {
        Insert(10);
        Insert(20);
        Console.WriteLine(Exists(10)); // prints True
        Console.WriteLine(Exists(15)); // prints False
    }
}

In Python, the built-in dictionary type serves as a hash map. The insert function adds a key by setting its value to True, while exists checks if the key is in the dictionary using the 'in' keyword.

Complexity

Time Complexity: O(1) average for insert and lookup.
Space Complexity: O(n) for n elements in the dictionary.

Try this approach in the editor

Approach 2: Using Sorting and Two-Pointer Technique

This method first sorts the input array and then utilizes a two-pointer technique to efficiently solve the problem. The two-pointer technique is often used in problems involving sorted arrays where we need to find pairs or combinations that satisfy certain conditions.

def has_pair_with_sum(arr, sum):
    arr.sort()
    left, right = 0, len(arr) - 1

    while left < right:
        current_sum = arr[left] + arr[right]
        if current_sum == sum:
            return True
        elif current_sum < sum:
            left += 1
        else:
            right -= 1
    return False

nums = [10, 0, -1, 20, 25, 30]
print(has_pair_with_sum(nums, 25))  # prints True
import java.util.Arrays;

public class TwoPointerTechnique {

    public static boolean hasPairWithSum(int[] nums, int sum) {
        Arrays.sort(nums);
        int left = 0, right = nums.length - 1;

        while (left < right) {
            int currentSum = nums[left] + nums[right];
            if (currentSum == sum) {
                return true;
            } else if (currentSum < sum) {
                left++;
            } else {
                right--;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        int[] nums = {10, 0, -1, 20, 25, 30};
        int sum = 25;
        System.out.println(hasPairWithSum(nums, sum)); // prints true
    }
}
#include <iostream>
#include <vector>
#include <algorithm>

bool hasPairWithSum(std::vector<int>& nums, int sum) {
    std::sort(nums.begin(), nums.end());
    int left = 0, right = nums.size() - 1;

    while (left < right) {
        int currentSum = nums[left] + nums[right];
        if (currentSum == sum) {
            return true;
        } else if (currentSum < sum) {
            left++;
        } else {
            right--;
        }
    }
    return false;
}

int main() {
    std::vector<int> nums = {10, 0, -1, 20, 25, 30};
    int sum = 25;
    std::cout << hasPairWithSum(nums, sum) << std::endl; // prints 1
    return 0;
}
function hasPairWithSum(arr, sum) {
    arr.sort((a, b) => a - b);
    let left = 0, right = arr.length - 1;

    while (left < right) {
        let currentSum = arr[left] + arr[right];
        if (currentSum === sum) {
            return true;
        } else if (currentSum < sum) {
            left++;
        } else {
            right--;
        }
    }
    return false;
}

let nums = [10, 0, -1, 20, 25, 30];
console.log(hasPairWithSum(nums, 25)); // prints true
#include <stdio.h>
#include <stdlib.h>

int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

int hasPairWithSum(int arr[], int n, int sum) {
    qsort(arr, n, sizeof(int), compare);
    int left = 0, right = n - 1;
    while (left < right) {
        int currentSum = arr[left] + arr[right];
        if (currentSum == sum) {
            return 1;
        } else if (currentSum < sum) {
            left++;
        } else {
            right--;
        }
    }
    return 0;
}

int main() {
    int arr[] = {10, 0, -1, 20, 25, 30};
    int sum = 25;
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("%d\n", hasPairWithSum(arr, n, sum)); // prints 1
    return 0;
}
using System;

public class TwoPointerTechnique {
    public static bool HasPairWithSum(int[] nums, int sum) {
        Array.Sort(nums);
        int left = 0, right = nums.Length - 1;

        while (left < right) {
            int currentSum = nums[left] + nums[right];
            if (currentSum == sum) {
                return true;
            } else if (currentSum < sum) {
                left++;
            } else {
                right--;
            }
        }
        return false;
    }

    public static void Main() {
        int[] nums = {10, 0, -1, 20, 25, 30};
        Console.WriteLine(HasPairWithSum(nums, 25)); // prints True
    }
}

The Python solution sorts the array and employs two pointers to check for pairs adding up to the target. The pointers adjust based on the current sum relative to the desired sum.

Complexity

Time Complexity: O(n log n) because of sorting.
Space Complexity: O(1) if sorting can be done in-place.

Try this approach in the editor

Complexity comparison

ApproachComplexity
Using Hash Map for Efficient Lookup

Time Complexity: O(1) average for insert and lookup.
Space Complexity: O(n) for n elements in the dictionary.

Using Sorting and Two-Pointer Technique

Time Complexity: O(n log n) because of sorting.
Space Complexity: O(1) if sorting can be done in-place.

Complexity analysis

ApproachTimeSpaceWhen to Use
Binary Search + Rolling Hash (Hash Map Lookup)O(N log N)O(N)Best general solution for interviews and competitive programming
Suffix Array + Sorting + Two PointersO(N log N)O(N)When working with large sequence comparisons or advanced string processing

Frequently asked questions

Is Longest Common Subpath easy or hard?

Longest Common Subpath is classified as Hard on LeetCode. The challenge comes from combining multiple advanced techniques such as binary search on answer, rolling hash collision handling, and efficient cross-array substring matching.

Longest Common Subpath Python/Java solution

Most Python and Java solutions implement binary search on the subpath length combined with rolling hash. A sliding window computes hashes for each path, and set intersection checks whether a hash appears in all paths. This approach balances performance and implementation complexity.

How to solve Longest Common Subpath in O(n)?

Strict O(n) solutions are uncommon for this problem because verifying shared subpaths across multiple arrays requires repeated comparisons. The closest practical solution is O(N log N) using binary search with rolling hash or suffix array construction. These approaches significantly reduce comparisons while keeping memory manageable.

What is the best approach for Longest Common Subpath?

Binary search combined with rolling hash is the most practical approach. You binary search the subpath length and verify each candidate using rolling hashes stored in hash sets. This reduces comparisons and runs in about O(N log N) time with O(N) space.

Is Longest Common Subpath asked at Google/Amazon/Meta?

Longest Common Subpath is considered a high‑difficulty algorithm problem and reflects patterns seen in interviews at companies like Google and Meta. It tests binary search on the answer, rolling hash design, and large-scale string or array matching techniques.

What data structure is used in Longest Common Subpath?

Common implementations use hash sets or hash maps to store rolling hash values for candidate subpaths. More advanced solutions rely on suffix arrays and LCP arrays for efficient prefix comparisons across sorted suffixes.

What is the time complexity of Longest Common Subpath?

The optimal solution using binary search and rolling hash runs in O(N log N) time, where N is the total length of all paths. Each binary search step computes rolling hashes for subpaths and checks intersections across paths. Space complexity is O(N) for storing hash sets.

Comments

Now write it yourselfClose this page and solve Longest Common Subpath in the editor, without looking.
Practise Longest Common Subpath