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
.
nums
must exactly match the corresponding group in groups
(order and values).nums
in the same order as in groups
, but may be separated by other numbers in nums
(i.e., gaps are allowed between groups).nums
can be reused across different groups.
The function should return True
if it is possible to form the concatenation of groups
within nums
as described, and False
otherwise.
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.
We can solve the problem efficiently with the following steps:
i
to the start of nums
.
groups
:
nums
starting from i
to find a subarray that matches the current group exactly (both values and order).
j
, move i
to j + len(group)
(just past the matched subarray).
False
immediately.
True
.
This approach works efficiently because:
nums
.
Let's consider the following example:
groups = [[1,2,3], [3,4]]
nums = [7,1,2,3,5,3,4,6]
[1,2,3]
. Scan nums
from the beginning:
[7,1,2]
(no match)[1,2,3]
(match!)[1,2,3]
).
[3,4]
. Start scanning from index 4:
[5,3]
(no match)[3,4]
(match!)True
.
Brute-force approach:
nums
and G is the number of groups.Optimized approach:
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).
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.
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;
};