diff --git a/solution/3600-3699/3690.Split and Merge Array Transformation/README.md b/solution/3600-3699/3690.Split and Merge Array Transformation/README.md index 35d32ae1bd3b8..56535b92db351 100644 --- a/solution/3600-3699/3690.Split and Merge Array Transformation/README.md +++ b/solution/3600-3699/3690.Split and Merge Array Transformation/README.md @@ -74,32 +74,217 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3690.Sp -### 方法一 +### 方法一:BFS + +我们可以使用广度优先搜索(BFS)来解决这个问题。由于数组的长度最多为 6,我们可以通过枚举所有可能的拆分和合并操作来找到最少的操作次数。 + +我们首先定义一个队列 $\textit{q}$ 来存储当前的数组状态,并使用一个集合 $\textit{vis}$ 来记录已经访问过的数组状态,以避免重复计算。初始时,队列中只包含数组 $\textit{nums1}$。 + +然后,我们进行以下步骤: + +1. 从队列中取出当前的数组状态 $\textit{cur}$。 +2. 如果 $\textit{cur}$ 等于目标数组 $\textit{nums2}$,则返回当前的操作次数。 +3. 否则,枚举所有可能的拆分位置 $(l, r)$,将子数组 $\textit{cur}[l..r]$ 移除,得到剩余数组 $\textit{remain}$ 和子数组 $\textit{sub}$。 +4. 将子数组 $\textit{sub}$ 插入到剩余数组 $\textit{remain}$ 的所有可能位置,生成新的数组状态 $\textit{nxt}$。 +5. 如果新的数组状态 $\textit{nxt}$ 没有被访问过,将其加入队列和访问集合中。 +6. 重复上述步骤,直到找到目标数组或队列为空。 + +时间复杂度 $O(n! \times n^4)$,空间复杂度 $O(n! \times n)$,其中 $n$ 是数组的长度。 #### Python3 ```python - +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) ``` #### Java ```java - +class Solution { + public int minSplitMerge(int[] nums1, int[] nums2) { + int n = nums1.length; + List target = toList(nums2); + List start = toList(nums1); + List> q = List.of(start); + Set> 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 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 sub = cur.subList(l, r + 1); + for (int i = 0; i <= remain.size(); ++i) { + List 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 toList(int[] arr) { + List res = new ArrayList<>(arr.length); + for (int x : arr) { + res.add(x); + } + return res; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int minSplitMerge(vector& nums1, vector& nums2) { + int n = nums1.size(); + vector target = nums2; + vector> q{nums1}; + set> vis; + vis.insert(nums1); + + for (int ans = 0;; ++ans) { + vector> t = q; + q.clear(); + for (auto& cur : t) { + if (cur == target) { + return ans; + } + for (int l = 0; l < n; ++l) { + for (int r = l; r < n; ++r) { + vector remain; + remain.insert(remain.end(), cur.begin(), cur.begin() + l); + remain.insert(remain.end(), cur.begin() + r + 1, cur.end()); + vector sub(cur.begin() + l, cur.begin() + r + 1); + for (int i = 0; i <= (int) remain.size(); ++i) { + vector nxt; + nxt.insert(nxt.end(), remain.begin(), remain.begin() + i); + nxt.insert(nxt.end(), sub.begin(), sub.end()); + nxt.insert(nxt.end(), remain.begin() + i, remain.end()); + + if (!vis.count(nxt)) { + vis.insert(nxt); + q.push_back(nxt); + } + } + } + } + } + } + } +}; ``` #### Go ```go - +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 + } +} ``` diff --git a/solution/3600-3699/3690.Split and Merge Array Transformation/README_EN.md b/solution/3600-3699/3690.Split and Merge Array Transformation/README_EN.md index a795e6140ced0..ba5987f68559c 100644 --- a/solution/3600-3699/3690.Split and Merge Array Transformation/README_EN.md +++ b/solution/3600-3699/3690.Split and Merge Array Transformation/README_EN.md @@ -71,32 +71,217 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3600-3699/3690.Sp -### Solution 1 +### Solution 1: BFS + +We can use Breadth-First Search (BFS) to solve this problem. Since the array length is at most 6, we can enumerate all possible split and merge operations to find the minimum number of operations. + +First, we define a queue $\textit{q}$ to store the current array states, and use a set $\textit{vis}$ to record the visited array states to avoid duplicate computations. Initially, the queue contains only the array $\textit{nums1}$. + +Then, we perform the following steps: + +1. Remove the current array state $\textit{cur}$ from the queue. +2. If $\textit{cur}$ equals the target array $\textit{nums2}$, return the current number of operations. +3. Otherwise, enumerate all possible split positions $(l, r)$, remove the subarray $\textit{cur}[l..r]$ to obtain the remaining array $\textit{remain}$ and the subarray $\textit{sub}$. +4. Insert the subarray $\textit{sub}$ into all possible positions of the remaining array $\textit{remain}$ to generate new array states $\textit{nxt}$. +5. If a new array state $\textit{nxt}$ has not been visited, add it to the queue and the visited set. +6. Repeat the above steps until the target array is found or the queue is empty. + +The time complexity is $O(n! \times n^4)$, and the space complexity is $O(n! \times n)$, where $n$ is the length of the array. #### Python3 ```python - +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) ``` #### Java ```java - +class Solution { + public int minSplitMerge(int[] nums1, int[] nums2) { + int n = nums1.length; + List target = toList(nums2); + List start = toList(nums1); + List> q = List.of(start); + Set> 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 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 sub = cur.subList(l, r + 1); + for (int i = 0; i <= remain.size(); ++i) { + List 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 toList(int[] arr) { + List res = new ArrayList<>(arr.length); + for (int x : arr) { + res.add(x); + } + return res; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int minSplitMerge(vector& nums1, vector& nums2) { + int n = nums1.size(); + vector target = nums2; + vector> q{nums1}; + set> vis; + vis.insert(nums1); + + for (int ans = 0;; ++ans) { + vector> t = q; + q.clear(); + for (auto& cur : t) { + if (cur == target) { + return ans; + } + for (int l = 0; l < n; ++l) { + for (int r = l; r < n; ++r) { + vector remain; + remain.insert(remain.end(), cur.begin(), cur.begin() + l); + remain.insert(remain.end(), cur.begin() + r + 1, cur.end()); + vector sub(cur.begin() + l, cur.begin() + r + 1); + for (int i = 0; i <= (int) remain.size(); ++i) { + vector nxt; + nxt.insert(nxt.end(), remain.begin(), remain.begin() + i); + nxt.insert(nxt.end(), sub.begin(), sub.end()); + nxt.insert(nxt.end(), remain.begin() + i, remain.end()); + + if (!vis.count(nxt)) { + vis.insert(nxt); + q.push_back(nxt); + } + } + } + } + } + } + } +}; ``` #### Go ```go - +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 + } +} ``` diff --git a/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.cpp b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.cpp new file mode 100644 index 0000000000000..f75a500d6e310 --- /dev/null +++ b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.cpp @@ -0,0 +1,39 @@ +class Solution { +public: + int minSplitMerge(vector& nums1, vector& nums2) { + int n = nums1.size(); + vector target = nums2; + vector> q{nums1}; + set> vis; + vis.insert(nums1); + + for (int ans = 0;; ++ans) { + vector> t = q; + q.clear(); + for (auto& cur : t) { + if (cur == target) { + return ans; + } + for (int l = 0; l < n; ++l) { + for (int r = l; r < n; ++r) { + vector remain; + remain.insert(remain.end(), cur.begin(), cur.begin() + l); + remain.insert(remain.end(), cur.begin() + r + 1, cur.end()); + vector sub(cur.begin() + l, cur.begin() + r + 1); + for (int i = 0; i <= (int) remain.size(); ++i) { + vector nxt; + nxt.insert(nxt.end(), remain.begin(), remain.begin() + i); + nxt.insert(nxt.end(), sub.begin(), sub.end()); + nxt.insert(nxt.end(), remain.begin() + i, remain.end()); + + if (!vis.count(nxt)) { + vis.insert(nxt); + q.push_back(nxt); + } + } + } + } + } + } + } +}; diff --git a/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.go b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.go new file mode 100644 index 0000000000000..ecdc677f44ce7 --- /dev/null +++ b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.go @@ -0,0 +1,56 @@ +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 + } +} diff --git a/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.java b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.java new file mode 100644 index 0000000000000..2684667667925 --- /dev/null +++ b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.java @@ -0,0 +1,54 @@ +class Solution { + public int minSplitMerge(int[] nums1, int[] nums2) { + int n = nums1.length; + List target = toList(nums2); + List start = toList(nums1); + List> q = List.of(start); + Set> 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 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 sub = cur.subList(l, r + 1); + for (int i = 0; i <= remain.size(); ++i) { + List 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 toList(int[] arr) { + List res = new ArrayList<>(arr.length); + for (int x : arr) { + res.add(x); + } + return res; + } +} diff --git a/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.py b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.py new file mode 100644 index 0000000000000..43645f7aaa649 --- /dev/null +++ b/solution/3600-3699/3690.Split and Merge Array Transformation/Solution.py @@ -0,0 +1,25 @@ +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)