文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 前言
- 解法一
- 思路和算法
- 代码
- 复杂度分析
- 解法二
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:通过翻转子数组使两个数组相等
出处:1460. 通过翻转子数组使两个数组相等
难度
3 级
题目描述
要求
给定两个长度相同的整数数组 target \texttt{target} target 和 arr \texttt{arr} arr。每一步中,可以选择 arr \texttt{arr} arr 的任意非空子数组并将它翻转。可以执行此过程任意次。
如果能让 arr \texttt{arr} arr 变成与 target \texttt{target} target 相同,返回 true \texttt{true} true;否则,返回 false \texttt{false} false。
示例
示例 1:
输入:
target
=
[1,2,3,4],
arr
=
[2,4,1,3]
\texttt{target = [1,2,3,4], arr = [2,4,1,3]}
target = [1,2,3,4], arr = [2,4,1,3]
输出:
true
\texttt{true}
true
解释:可以按照如下步骤使
arr
\texttt{arr}
arr 变成
target
\texttt{target}
target:
1- 翻转子数组
[2,4,1]
\texttt{[2,4,1]}
[2,4,1],
arr
\texttt{arr}
arr 变成
[1,4,2,3]
\texttt{[1,4,2,3]}
[1,4,2,3]。
2- 翻转子数组
[4,2]
\texttt{[4,2]}
[4,2],
arr
\texttt{arr}
arr 变成
[1,2,4,3]
\texttt{[1,2,4,3]}
[1,2,4,3]。
3- 翻转子数组
[4,3]
\texttt{[4,3]}
[4,3],
arr
\texttt{arr}
arr 变成
[1,2,3,4]
\texttt{[1,2,3,4]}
[1,2,3,4]。
上述方法并不是唯一的,还存在多种将
arr
\texttt{arr}
arr 变成
target
\texttt{target}
target 的方法。
示例 2:
输入:
target
=
[7],
arr
=
[7]
\texttt{target = [7], arr = [7]}
target = [7], arr = [7]
输出:
true
\texttt{true}
true
解释:
arr
\texttt{arr}
arr 不需要做任何翻转已经与
target
\texttt{target}
target 相等。
示例 3:
输入:
target
=
[3,7,9],
arr
=
[3,7,11]
\texttt{target = [3,7,9], arr = [3,7,11]}
target = [3,7,9], arr = [3,7,11]
输出:
false
\texttt{false}
false
解释:
arr
\texttt{arr}
arr 没有数字
9
\texttt{9}
9,所以无法变成
target
\texttt{target}
target。
数据范围
- target.length = arr.length \texttt{target.length} = \texttt{arr.length} target.length=arr.length
- 1 ≤ target.length ≤ 1000 \texttt{1} \le \texttt{target.length} \le \texttt{1000} 1≤target.length≤1000
- 1 ≤ target[i] ≤ 1000 \texttt{1} \le \texttt{target[i]} \le \texttt{1000} 1≤target[i]≤1000
- 1 ≤ arr[i] ≤ 1000 \texttt{1} \le \texttt{arr[i]} \le \texttt{1000} 1≤arr[i]≤1000
前言
如果数组 target \textit{target} target 和 arr \textit{arr} arr 的元素不完全相同,则 target \textit{target} target 中至少有一个元素是 arr \textit{arr} arr 中没有的,因此不可能通过翻转 arr \textit{arr} arr 的子数组将 arr \textit{arr} arr 变成与 target \textit{target} target 相同。
如果数组 target \textit{target} target 和 arr \textit{arr} arr 的元素完全相同,则 target \textit{target} target 中的每一个元素都在 arr \textit{arr} arr 中有一个对应的元素。对于 i ≥ 0 i \ge 0 i≥0,第 i i i 次翻转子数组时,找到下标 j j j 使得 i ≤ j i \le j i≤j 且 target [ i ] = arr [ j ] \textit{target}[i] = \textit{arr}[j] target[i]=arr[j](如果有多个符合要求的下标 j j j,则任选其中一个下标),将 arr \textit{arr} arr 的下标范围 [ i , j ] [i, j] [i,j] 的子数组翻转,翻转之后有 target [ i ] = arr [ i ] \textit{target}[i] = \textit{arr}[i] target[i]=arr[i]。因此可以通过翻转使得两个数组中所有下标处的元素都对应相等,即可以通过翻转 arr \textit{arr} arr 的子数组将 arr \textit{arr} arr 变成与 target \textit{target} target 相同。
根据上述分析可知,判断是否可以通过翻转 arr \textit{arr} arr 的子数组将 arr \textit{arr} arr 变成与 target \textit{target} target 相同,实质是判断 target \textit{target} target 和 arr \textit{arr} arr 的元素是否相同。因此这道题和「有效的字母异位词」相似。
解法一
思路和算法
可以通过排序的方式判断两个数组的元素是否相同。对数组 target \textit{target} target 和 arr \textit{arr} arr 分别排序,并比较排序之后的两个数组是否相同。
-
如果排序之后的两个数组相同,则两个数组的元素相同,可以通过翻转 arr \textit{arr} arr 的子数组将 arr \textit{arr} arr 变成与 target \textit{target} target 相同。
-
如果排序之后的两个数组不同,则两个数组的元素不同,不能通过翻转 arr \textit{arr} arr 的子数组将 arr \textit{arr} arr 变成与 target \textit{target} target 相同。
代码
class Solution {
public boolean canBeEqual(int[] target, int[] arr) {
Arrays.sort(target);
Arrays.sort(arr);
return Arrays.equals(target, arr);
}
}
复杂度分析
-
时间复杂度: O ( n log n ) O(n \log n) O(nlogn),其中 n n n 是数组 target \textit{target} target 和 arr \textit{arr} arr 的长度。需要 O ( n log n ) O(n \log n) O(nlogn) 的时间对两个数组排序,排序后需要 O ( n ) O(n) O(n) 的时间比较两个数组是否相同,因此时间复杂度是 O ( n log n ) O(n \log n) O(nlogn)。
-
空间复杂度: O ( log n ) O(\log n) O(logn),其中 n n n 是数组 target \textit{target} target 和 arr \textit{arr} arr 的长度。排序需要 O ( log n ) O(\log n) O(logn) 的递归调用栈空间。
解法二
思路和算法
为了判断两个数组的元素是否相同,可以分别统计两个数组中每个元素的出现次数。只有当任意元素在两个数组中的出现次数相同时,两个数组的元素才相同。
使用哈希表存储每个元素的计数。首先遍历 target \textit{target} target,对于每个元素,将其在哈希表中对应的计数加 1 1 1。然后遍历 arr \textit{arr} arr,对于每个元素,将其在哈希表中对应的计数减 1 1 1。如果遍历 target \textit{target} target 和 arr \textit{arr} arr 之后,哈希表中的每个计数都是 0 0 0,则 target \textit{target} target 和 arr \textit{arr} arr 的元素相同。
实现方面,可以有以下两点优化。
-
由于在遍历 arr \textit{arr} arr 的过程中,哈希表中的计数只会减少,因此当哈希表中的计数出现负数时,该计数对应的元素在 arr \textit{arr} arr 中的出现次数大于在 target \textit{target} target 中的出现次数,此时两个数组的元素不同。
-
如果在遍历 arr \textit{arr} arr 的过程中,哈希表中的计数都没有出现负数,则遍历结束之后可以确定两个数组的元素相同,不需要再次遍历哈希表检查是否每个计数都是 0 0 0。理由如下。
-
遍历 arr \textit{arr} arr 的过程中,哈希表中的计数都没有出现负数,说明任何元素在 arr \textit{arr} arr 中的出现次数不超过在 target \textit{target} target 中的出现次数。
-
假设存在一个元素,该元素在 arr \textit{arr} arr 中的出现次数小于在 target \textit{target} target 中的出现次数,则 arr \textit{arr} arr 的长度小于 target \textit{target} target 的长度,与 arr \textit{arr} arr 的长度等于 target \textit{target} target 的长度矛盾。因此任何元素在 arr \textit{arr} arr 中的出现次数都等于在 target \textit{target} target 中的出现次数。
-
如果两个数组的元素相同,则可以通过翻转 arr \textit{arr} arr 的子数组将 arr \textit{arr} arr 变成与 target \textit{target} target 相同,否则不能通过翻转 arr \textit{arr} arr 的子数组将 arr \textit{arr} arr 变成与 target \textit{target} target 相同。
代码
class Solution {
public boolean canBeEqual(int[] target, int[] arr) {
Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
int length = target.length;
for (int i = 0; i < length; i++) {
int num = target[i];
counts.put(num, counts.getOrDefault(num, 0) + 1);
}
for (int i = 0; i < length; i++) {
int num = arr[i];
counts.put(num, counts.getOrDefault(num, 0) - 1);
if (counts.get(num) < 0) {
return false;
}
}
return true;
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 target \textit{target} target 和 arr \textit{arr} arr 的长度。需要遍历 target \textit{target} target 和 arr \textit{arr} arr 各一次并维护计数,每次遍历都需要 O ( n ) O(n) O(n) 的时间。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 target \textit{target} target 和 arr \textit{arr} arr 的长度。需要使用哈希表记录每个元素的计数,空间为 O ( n ) O(n) O(n)。



















