[算法]最长的可整合数组的长度
题目:
如果一个数组再排序之后,每相邻两个数差的绝对值都为1,则该数组为可整合数组。例如,[5,3,4,6,2]排序之后为[2,3,4,5,6],符合每相邻两个数差的绝对值为1,所以这个数组为可整合数组。
给定一个整型数组,请返回其中最大可整合子数组的长度。例如,[5,5,3,2,6,4,3]的最大可整合子数组为[5,3,2,6,4],所以返回5.
方法一:
1.依次考察每一个子数组arr[i…j],一共有O(N^2)个。
2.对于每一个子数组,复制成一个新的数组,记为newArr,把newArr排序,然后验证是否符合可整合数组的定义,这一步的代价为O(NlogN).
3.步骤2中符合条件的、最大的那个子数组的长度就是结果。
时间复杂度为:O(N^3logN)
public static int getLIL1(int[] arr) { if (arr == null || arr.length == 0) { return 0; } int len = 0; for (int i = 0; i < arr.length; i++) { for (int j = i; j < arr.length; j++) { if (isIntegrated(arr, i, j)) { len = Math.max(len, j - i + 1); } } } return len; } public static boolean isIntegrated(int[] arr, int left, int right) { int[] newArr = Arrays.copyOfRange(arr, left, right + 1); // O(N) Arrays.sort(newArr); // O(N*logN) for (int i = 1; i < newArr.length; i++) { if (newArr[i - 1] != newArr[i] - 1) { return false; } } return true; }
方法二:
第一种方法严格按照题目的意思来验证每一个子数组是否是可整合数组,但是判断数组是否是可整合数组还可以使用以下方法判断,一个数组中如果没有重复元素,并且如果最大值减去最小值,再加上1的结果等于元素的个数(max-min+1=元素个数),那么这个数组就是可整合数组。
这样,验证一个数组是否是可整合数组的时间复杂度可以从第一种方法的O(NlogN)减少至O(1),整个过程的时间复杂度为O(N^2)
public static int getLIL2(int[] arr) { if (arr == null || arr.length == 0) { return 0; } int len = 0; int max = 0; int min = 0; HashSet<Integer> set = new HashSet<>(); //判断重复 for (int i = 0; i < arr.length; i++) { max = Integer.MIN_VALUE; min = Integer.MAX_VALUE; for (int j = i; j < arr.length; j++) { if (set.contains(arr[j])) { break; } set.add(arr[j]); max = Math.max(max, arr[j]); min = Math.min(min, arr[j]); if (max - min == j - i) { len = Math.max(len, j - i + 1); } } set.clear(); } return len; }