题解
暴力法
很容易想到,如果需要重新连接pieces
构成arr
,则需要遍历arr
中的元素arr[idx]
,在pieces[i]
中找到一个满足arr[idx] == pieces[i][0]
的下标i
。
- 如果没有找到该下标
i
,则肯定无法重新连接称为arr
,因为pieces[i]
中的元素是不可重新排序的,直接返回false
即可; - 若找到了该下标
i
,则仍需要去遍历pieces[i]
中的元素,使得pieces[i][0]...pieces[i][n-1]
与arr[idx]...arr[idx+n-1]
的元素和顺序均相同,其中n = pieces[i].length
。若存在其中的某一个元素不同,则可直接返回false
。
依次遍历arr
中的元素,直至idx == arr.length
,即arr
中的元素被遍历完,则说明其可以被pieces
重排后构成,返回true
。
代码如下:
public class Solution {
//纯暴力解法
public boolean canFormArray(int[] arr, int[][] pieces) {
int idx = 0; //指向arr中的数,arr[0] ... arr[idx-1]的数都能够通过pieces拼接而成
int i = 0;
while(idx < arr.length){
//去pieces中找arr[idx]
for (i=0; i < pieces.length; i++) {
if (pieces[i][0] == arr[idx]){
idx++;
//吧pieces[i]遍历完
for (int j = 1; j < pieces[i].length; j++, idx++) {
//无法遍历完,说明顺序有问题,直接返回false
if (pieces[i][j] != arr[idx]){
return false;
}
}
// 当前pieces[i]可以构成arr中的一部分,重新寻找下一个arr[idx]
break;
}
}
//遍历完一轮没有找到arr[idx] == pieces[i][0]的下标i
if (i == pieces.length){
return false;
}
}
return true;
}
}
哈希表
从上面的分析中可以看出,我们需要在pieces
中找到一个满足arr[idx] == pieces[i][0]
的下标i
,在暴力方法中是通过循环遍历来得到该下标i
的,这比较耗时。
我们需要注意到pieces
扁平化后所有元素都是不相同的,因此我们可以利用哈希表来存储pieces[i][0]
与其下标i
的映射关系,从而提升搜索的时间。
代码实现如下:
public class Solution1640v1 {
public boolean canFormArray(int[] arr, int[][] pieces) {
Map<Integer, Integer> map = new HashMap<>();
int idx = 0;
//需要按顺序遍历arr, 然后去pieces中寻找是否存在满足当前顺序的pieces[i]
//因此map中应该存放的是pieces[i][0]的下标志
for (int i = 0; i < pieces.length; i++) {
map.put(pieces[i][0], i);
}
while(idx < arr.length){
Integer i = map.get(arr[idx]);
if (i == null){
//说明pieces[i]中没有以arr[idx]开头的数,无法构成arr,直接返回false
return false;
}
int[] piece = pieces[i];
//arr[idx] == piece[0] 已经成立了,继续往下判断
idx++;
for (int j = 1; j < piece.length; j++, idx++) {
if (arr[idx] != piece[j]){
//顺序不同,无法构成arr,直接返回
return false;
}
}
}
return true;
}
}