题目:
先给出可整合数组的定义。如果一个数组在排序之后,每相邻两个数差的据对值都为1,则该数组为可整合数组。例如,[5,3,4,6,2]排序之后为[2,3,4,5,6],符合每相邻两个数差的绝对值都为1,所以这个数组为可整合数组。
给定一个整型数组arr,请返回其中最大可整合子数组的长度。例如,[5,5,3,2,6,4,3]的最大可整合子数组为[5,3,2,6,4],所以返回5。
解答:
时间复杂度搞但容易理解的做法。对arr中的每一个子数组arr[i...j](0<=i<=j<=N-1),都验证一下是否符合可整合数组的定义,也就是把arr[i..j]排序一下,看是否一次递增且每次都递增1。然后在所有符合可整合数组定义的子数组中,记录最大的那个长度,返回即可。
需要注意的是,在考查每一个arr[i..j]是否符合可整合数组定义的时候,都得把arr[i..j]单独复制成一个新的数组,然后把这个新的数组排序、验证,而不能直接改变arr中元素的顺序。所以大体过程如下:
1、依次考查每一个子数组arr[i..j](0<=i<=j<=N-1),一共有O(N^2)个。
2、对每一个子数组arr[i..j],复制成一个新的数组,记为newArr,把newArr排序,然后验证是否符合可整合数组的定义,这一步代价为O(NlogN)。
3、步骤2中符合条件的、最大的那个子数组的长度就是结果。
public 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(isIntegerated(arr,i,j)){len = Math.max(len,j-i+1);}}}return len;
}public boolean isIntegrated(int[] arr,int left,int right){int[] newArr = Arrays.copyOfRange(arr,left,right + 1);Arrays.sort(newArr);for(int i = 1; i< newArr.length; i++){if(newArr[i-1] != newArr[i] - 1){return false;}}return true;
}
判断一个数组是否可整合数组还可以用以下方法来判断,一个数组中如果没有重复元素,并且如果最大值减去最小值,再加1的结果等于元素个数(max-min+1==元素个数),那么这个数组就是可整合数组。比如[3,2,5,6,4],max-min+1 = 6 -2 +1=5==元素个数,所以这个数组是可整合数组。
public 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<Integer>();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;
}