Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given two integer arrays nums1 and nums2, each of length n. You may perform the following split-and-merge operation on nums1 any number of times:
nums1[L..R].nums1[0..L-1] (empty if L = 0) and the suffix nums1[R+1..n-1] (empty if R = n - 1).Return the minimum number of split-and-merge operations needed to transform nums1 into nums2.
Example 1:
Input: nums1 = [3,1,2], nums2 = [1,2,3]
Output: 1
Explanation:
[3] (L = 0, R = 0); the remaining array is [1,2].[3] at the end; the array becomes [1,2,3].Example 2:
Input: nums1 = [1,1,2,3,4,5], nums2 = [5,4,3,2,1,1]
Output: 3
Explanation:
[1,1,2] at indices 0 - 2; remaining is [3,4,5]; insert [1,1,2] at position 2, resulting in [3,4,1,1,2,5].[4,1,1] at indices 1 - 3; remaining is [3,2,5]; insert [4,1,1] at position 3, resulting in [3,2,5,4,1,1].[3,2] at indices 0 - 1; remaining is [5,4,1,1]; insert [3,2] at position 2, resulting in [5,4,3,2,1,1].Constraints:
2 <= n == nums1.length == nums2.length <= 6-105 <= nums1[i], nums2[i] <= 105nums2 is a permutation of nums1.Problem summary: You are given two integer arrays nums1 and nums2, each of length n. You may perform the following split-and-merge operation on nums1 any number of times: Choose a subarray nums1[L..R]. Remove that subarray, leaving the prefix nums1[0..L-1] (empty if L = 0) and the suffix nums1[R+1..n-1] (empty if R = n - 1). Re-insert the removed subarray (in its original order) at any position in the remaining array (i.e., between any two elements, at the very start, or at the very end). Return the minimum number of split-and-merge operations needed to transform nums1 into nums2.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
[3,1,2] [1,2,3]
[1,1,2,3,4,5] [5,4,3,2,1,1]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3690: Split and Merge Array Transformation
class Solution {
public int minSplitMerge(int[] nums1, int[] nums2) {
int n = nums1.length;
List<Integer> target = toList(nums2);
List<Integer> start = toList(nums1);
List<List<Integer>> q = List.of(start);
Set<List<Integer>> vis = new HashSet<>();
vis.add(start);
for (int ans = 0;; ++ans) {
var t = q;
q = new ArrayList<>();
for (var cur : t) {
if (cur.equals(target)) {
return ans;
}
for (int l = 0; l < n; ++l) {
for (int r = l; r < n; ++r) {
List<Integer> remain = new ArrayList<>();
for (int i = 0; i < l; ++i) {
remain.add(cur.get(i));
}
for (int i = r + 1; i < n; ++i) {
remain.add(cur.get(i));
}
List<Integer> sub = cur.subList(l, r + 1);
for (int i = 0; i <= remain.size(); ++i) {
List<Integer> nxt = new ArrayList<>();
for (int j = 0; j < i; ++j) {
nxt.add(remain.get(j));
}
for (int x : sub) {
nxt.add(x);
}
for (int j = i; j < remain.size(); ++j) {
nxt.add(remain.get(j));
}
if (vis.add(nxt)) {
q.add(nxt);
}
}
}
}
}
}
}
private List<Integer> toList(int[] arr) {
List<Integer> res = new ArrayList<>(arr.length);
for (int x : arr) {
res.add(x);
}
return res;
}
}
// Accepted solution for LeetCode #3690: Split and Merge Array Transformation
func minSplitMerge(nums1 []int, nums2 []int) int {
n := len(nums1)
toArr := func(nums []int) [6]int {
var t [6]int
for i, x := range nums {
t[i] = x
}
return t
}
start := toArr(nums1)
target := toArr(nums2)
vis := map[[6]int]bool{start: true}
q := [][6]int{start}
for ans := 0; ; ans++ {
nq := [][6]int{}
for _, cur := range q {
if cur == target {
return ans
}
for l := 0; l < n; l++ {
for r := l; r < n; r++ {
remain := []int{}
for i := 0; i < l; i++ {
remain = append(remain, cur[i])
}
for i := r + 1; i < n; i++ {
remain = append(remain, cur[i])
}
sub := []int{}
for i := l; i <= r; i++ {
sub = append(sub, cur[i])
}
for pos := 0; pos <= len(remain); pos++ {
nxtSlice := []int{}
nxtSlice = append(nxtSlice, remain[:pos]...)
nxtSlice = append(nxtSlice, sub...)
nxtSlice = append(nxtSlice, remain[pos:]...)
nxt := toArr(nxtSlice)
if !vis[nxt] {
vis[nxt] = true
nq = append(nq, nxt)
}
}
}
}
}
q = nq
}
}
# Accepted solution for LeetCode #3690: Split and Merge Array Transformation
class Solution:
def minSplitMerge(self, nums1: List[int], nums2: List[int]) -> int:
n = len(nums1)
target = tuple(nums2)
start = tuple(nums1)
q = [start]
vis = set()
vis.add(start)
for ans in count(0):
t = q
q = []
for cur in t:
if cur == target:
return ans
for l in range(n):
for r in range(l, n):
remain = list(cur[:l]) + list(cur[r + 1 :])
sub = cur[l : r + 1]
for i in range(len(remain) + 1):
nxt = tuple(remain[:i] + list(sub) + remain[i:])
if nxt not in vis:
vis.add(nxt)
q.append(nxt)
// Accepted solution for LeetCode #3690: Split and Merge Array Transformation
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #3690: Split and Merge Array Transformation
// class Solution {
// public int minSplitMerge(int[] nums1, int[] nums2) {
// int n = nums1.length;
// List<Integer> target = toList(nums2);
// List<Integer> start = toList(nums1);
// List<List<Integer>> q = List.of(start);
// Set<List<Integer>> vis = new HashSet<>();
// vis.add(start);
// for (int ans = 0;; ++ans) {
// var t = q;
// q = new ArrayList<>();
// for (var cur : t) {
// if (cur.equals(target)) {
// return ans;
// }
// for (int l = 0; l < n; ++l) {
// for (int r = l; r < n; ++r) {
// List<Integer> remain = new ArrayList<>();
// for (int i = 0; i < l; ++i) {
// remain.add(cur.get(i));
// }
// for (int i = r + 1; i < n; ++i) {
// remain.add(cur.get(i));
// }
// List<Integer> sub = cur.subList(l, r + 1);
// for (int i = 0; i <= remain.size(); ++i) {
// List<Integer> nxt = new ArrayList<>();
// for (int j = 0; j < i; ++j) {
// nxt.add(remain.get(j));
// }
// for (int x : sub) {
// nxt.add(x);
// }
// for (int j = i; j < remain.size(); ++j) {
// nxt.add(remain.get(j));
// }
// if (vis.add(nxt)) {
// q.add(nxt);
// }
// }
// }
// }
// }
// }
// }
//
// private List<Integer> toList(int[] arr) {
// List<Integer> res = new ArrayList<>(arr.length);
// for (int x : arr) {
// res.add(x);
// }
// return res;
// }
// }
// Accepted solution for LeetCode #3690: Split and Merge Array Transformation
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #3690: Split and Merge Array Transformation
// class Solution {
// public int minSplitMerge(int[] nums1, int[] nums2) {
// int n = nums1.length;
// List<Integer> target = toList(nums2);
// List<Integer> start = toList(nums1);
// List<List<Integer>> q = List.of(start);
// Set<List<Integer>> vis = new HashSet<>();
// vis.add(start);
// for (int ans = 0;; ++ans) {
// var t = q;
// q = new ArrayList<>();
// for (var cur : t) {
// if (cur.equals(target)) {
// return ans;
// }
// for (int l = 0; l < n; ++l) {
// for (int r = l; r < n; ++r) {
// List<Integer> remain = new ArrayList<>();
// for (int i = 0; i < l; ++i) {
// remain.add(cur.get(i));
// }
// for (int i = r + 1; i < n; ++i) {
// remain.add(cur.get(i));
// }
// List<Integer> sub = cur.subList(l, r + 1);
// for (int i = 0; i <= remain.size(); ++i) {
// List<Integer> nxt = new ArrayList<>();
// for (int j = 0; j < i; ++j) {
// nxt.add(remain.get(j));
// }
// for (int x : sub) {
// nxt.add(x);
// }
// for (int j = i; j < remain.size(); ++j) {
// nxt.add(remain.get(j));
// }
// if (vis.add(nxt)) {
// q.add(nxt);
// }
// }
// }
// }
// }
// }
// }
//
// private List<Integer> toList(int[] arr) {
// List<Integer> res = new ArrayList<>(arr.length);
// for (int x : arr) {
// res.add(x);
// }
// return res;
// }
// }
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.