Given a list of arrays arrays, return all combinations where each combination picks exactly one element from each input array. This is the Cartesian product of the input arrays.
Two common approaches are: (1) recursive backtracking that builds combinations in-place, and (2) iterative expansion that folds arrays into the running result.
Treat each input arrays[i] as a decision point: choose one element from arrays[i] and recurse to fill the rest. This is like walking down a tree of depth m (number of arrays) where each level branches by the size of the corresponding array.
import java.util.*;
classSolution {
public List<List<Integer>>permutationsOfArrays(List<List<Integer>> arrays) {
int m = arrays.size();
for (List<Integer> a : arrays) if (a.isEmpty()) return Collections.emptyList();
if (m == 0) return Collections.emptyList();
List<Integer> curr =new ArrayList<>(Collections.nCopies(m, 0));
List<List<Integer>> ans =new ArrayList<>();
dfs(arrays, 0, curr, ans);
return ans;
}
privatevoiddfs(List<List<Integer>> arrays, int i, List<Integer> curr, List<List<Integer>> ans) {
if (i == arrays.size()) { ans.add(new ArrayList<>(curr)); return; }
for (int v : arrays.get(i)) {
curr.set(i, v);
dfs(arrays, i+1, curr, ans);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
classSolution {
funpermutationsOfArrays(arrays: List<List<Int>>): List<List<Int>> {
val m = arrays.size
arrays.forEach { if (it.isEmpty()) return emptyList() }
if (m ==0) return emptyList()
val curr = MutableList(m) { 0 }
val ans = mutableListOf<List<Int>>()
fundfs(i: Int) {
if (i == m) { ans.add(curr.toList()); return }
for (v in arrays[i]) {
curr[i] = v
dfs(i+1)
}
}
dfs(0)
return ans
}
}
classSolution:
defpermutations_of_arrays(self, arrays: list[list[int]]) -> list[list[int]]:
m = len(arrays)
for a in arrays:
ifnot a:
return []
if m ==0:
return []
curr: list[int] = [0] * m
ans: list[list[int]] = []
defdfs(i: int) ->None:
if i == m:
ans.append(curr.copy())
returnfor v in arrays[i]:
curr[i] = v
dfs(i+1)
dfs(0)
return ans
⏰ Time complexity: O(m * Π_{i=0..m-1} s_i) where m is number of arrays and s_i is the size of arrays[i] — there are Π s_i combinations and building each combination costs O(m).
🧺 Space complexity: O(Π_{i} s_i * m) to store output; auxiliary recursion stack O(m).
Start with res = [[]] and for every input array append each element to each partial combination in res. After processing all arrays, res contains every combination.
defpermutations_of_arrays_iter(arrays: list[list[int]]) -> list[list[int]]:
ifnot arrays: return []
if any(not a for a in arrays): return []
res: list[list[int]] = [[]]
for arr in arrays:
nxt: list[list[int]] = []
for t in res:
for v in arr:
nxt.append(t + [v])
res = nxt
return res