Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1764. Form Array by Concatenating Subarrays of Another Array - Leetcode Solution

Problem Description

You are given two arrays: groups (a list of lists of integers) and nums (a list of integers). The task is to determine whether it is possible to select subarrays from nums (without reusing any element) so that, when concatenated in order, they form the sequence of arrays in groups.

  • Each subarray from nums must exactly match the corresponding group in groups (order and values).
  • The subarrays must appear in nums in the same order as in groups, but may be separated by other numbers in nums (i.e., gaps are allowed between groups).
  • No element of nums can be reused across different groups.
  • There is at most one valid way to select subarrays for all groups.

The function should return True if it is possible to form the concatenation of groups within nums as described, and False otherwise.

Thought Process

At first glance, this problem may seem similar to finding whether all elements of one array exist in another. However, the key constraints are that the groups must be found as contiguous subarrays (in order), and elements cannot be reused between groups.

A brute-force approach would involve trying every possible position in nums for each group, checking all combinations and backtracking when a group cannot be matched. This would be highly inefficient.

Instead, we can recognize that since each group must be matched in order and without overlap, we can scan through nums sequentially, looking for each group in turn. Once a group is matched, we move the scanning pointer forward past the matched subarray, ensuring no overlap.

This linear scan is much more efficient and leverages the constraints of the problem: groups must be matched in order, and elements cannot be reused.

Solution Approach

We can solve the problem efficiently with the following steps:

  1. Initialize a pointer i to the start of nums.
  2. For each group in groups:
    • Scan nums starting from i to find a subarray that matches the current group exactly (both values and order).
    • If a match is found at position j, move i to j + len(group) (just past the matched subarray).
    • If no match is found for the current group, return False immediately.
  3. If all groups are matched in order, return True.

This approach works efficiently because:

  • We never backtrack or check the same element twice.
  • Each group is matched using a sliding window over nums.
  • The problem guarantees at most one valid way to match, so we do not need to consider multiple paths.

Example Walkthrough

Let's consider the following example:

  • groups = [[1,2,3], [3,4]]
  • nums = [7,1,2,3,5,3,4,6]
  1. Start with the first group [1,2,3]. Scan nums from the beginning:
    • At index 0: [7,1,2] (no match)
    • At index 1: [1,2,3] (match!)
    Move pointer to index 4 (just past [1,2,3]).
  2. Next group is [3,4]. Start scanning from index 4:
    • At index 4: [5,3] (no match)
    • At index 5: [3,4] (match!)
    Move pointer to index 7.
  3. All groups have been matched in order. Return True.

Time and Space Complexity

Brute-force approach:

  • Would involve backtracking and trying all possible combinations, leading to exponential time complexity: O(N^G), where N is the length of nums and G is the number of groups.

Optimized approach:

  • For each group, we scan at most all remaining elements in nums. In the worst case, we scan the entire nums array for each group, but since we advance the pointer after each match, the total number of comparisons is at most O(N).
  • Space complexity is O(1), since we only use pointers and do not store extra data structures proportional to input size.

Summary

The problem asks us to check if we can find each group as a contiguous subarray inside nums, in order and without overlap. By scanning nums sequentially for each group and advancing past each match, we ensure correctness and efficiency. The solution leverages the constraints to avoid unnecessary backtracking or complex data structures, resulting in a clean and optimal O(N) algorithm.

Code Implementation

class Solution:
    def canChoose(self, groups, nums):
        i = 0  # pointer in nums
        for group in groups:
            found = False
            while i + len(group) <= len(nums):
                if nums[i:i+len(group)] == group:
                    i += len(group)
                    found = True
                    break
                i += 1
            if not found:
                return False
        return True
      
class Solution {
public:
    bool canChoose(vector<vector<int>>& groups, vector<int>& nums) {
        int i = 0;
        for (auto& group : groups) {
            bool found = false;
            while (i + group.size() <= nums.size()) {
                bool match = true;
                for (int j = 0; j < group.size(); ++j) {
                    if (nums[i + j] != group[j]) {
                        match = false;
                        break;
                    }
                }
                if (match) {
                    i += group.size();
                    found = true;
                    break;
                }
                i++;
            }
            if (!found) return false;
        }
        return true;
    }
};
      
class Solution {
    public boolean canChoose(int[][] groups, int[] nums) {
        int i = 0;
        for (int[] group : groups) {
            boolean found = false;
            while (i + group.length <= nums.length) {
                boolean match = true;
                for (int j = 0; j < group.length; j++) {
                    if (nums[i + j] != group[j]) {
                        match = false;
                        break;
                    }
                }
                if (match) {
                    i += group.length;
                    found = true;
                    break;
                }
                i++;
            }
            if (!found) return false;
        }
        return true;
    }
}
      
var canChoose = function(groups, nums) {
    let i = 0;
    for (let group of groups) {
        let found = false;
        while (i + group.length <= nums.length) {
            let match = true;
            for (let j = 0; j < group.length; j++) {
                if (nums[i + j] !== group[j]) {
                    match = false;
                    break;
                }
            }
            if (match) {
                i += group.length;
                found = true;
                break;
            }
            i++;
        }
        if (!found) return false;
    }
    return true;
};