前言
本博文部分图片, 思路来自于剑指offer 或者编程珠玑
问题描述
思路
对于这个问题, 书中给出了一种思路 [大小鬼使用数字0来表示]
思路一 : 先将数组进行排序, 然后获取到第一个非0元素的位置, 然后获取之后的元素的每两个相邻元素之间的差值[“空白元素部分”], 相邻两个元素相同为剪枝条件[根据题目的需求], 可以直接返回false, 统计所有的”空白元素”的个数, 最后比较总的”空白元素”的个数 和数组前面”0的个数”, 如果“空白元素”个数大于”0的个数”, 返回false[通配符都填充不满]
后面两种思路是我的
思路一 : 其实 和上面书中的思路基本上一致, 不过 我这里换了一种方式来统计, 使用的是标志数组
思路二 : 直接使用逻辑判定, 令”最大元素 和第一个非0元素的差值”为deltaVal, “最大元素的索引 和第一个非0元素的索引差值”为deltaIdx
如果 delta大于了arr.length 表示就算吧所有的”0元素”都去补充空白, 仍然会存在空白, 返回false
如果 deltaVal小于deltaIdx 表示”最大元素 和第一个非0元素”之间存在重复的数据, 返回false
其他场景返回true
参考代码
/**
* file name : Test19IsContinuousSeq.java
* created at : 3:04:00 PM Jun 9, 2015
* created by 970655147
*/
package com.hx.test05;
public class Test19IsContinuousSeq {
// 可以表示任意数字
static int ALL_MATCH = 0;
// 判断给定的序列是否是连续的 0可以表示任意数
public static void main(String []args) {
int[] arr = new int[] {3, 5, 4, 7 };
isContinuousSeq(arr);
isContinuousSeq02(arr);
}
// 思路 : 先将arr排序, 获取第一个非0的数字的索引
// 获取最大的数和第一个非0数之差, 获取最大数的索引和第一个非0数索引之差
// 先进行剪枝, 如果最大的差值大于了(索引差值+0的个数), 或者差值小于索引的差值, 则视为不可能连续, 直接返回false,
// 然后 利用一个长度为(deltaVal+1)的辅助数组 空间, 来记录那些数据存在 如果数组中空缺的数字个数大于了0的个数, 则视为, 即使使用了所有的0, 任然会存在空缺, 返回false
// 否则 返回true
public static void isContinuousSeq(int[] arr) {
Arrays.sort(arr);
int firstNonZeroIdx = getFirstNonAllMatchIdx(arr);
int deltaVal = arr[arr.length-1] - arr[firstNonZeroIdx];
int deltaIdx = arr.length-1 - firstNonZeroIdx;
// 数据的值相差太大的, 用0都不可能弥补的, 或者相差太小, 存在一个或多个一样的
if((deltaVal > deltaIdx + firstNonZeroIdx) || (deltaVal < deltaIdx) ) {
Log.log(false);
return ;
}
// 记录数据的存在情况
boolean[] isExists = new boolean[deltaVal + 1];
int falseNum = isExists.length;
boolean isContinuous = false;
for(int i=firstNonZeroIdx; i<arr.length; i++) {
if(arr[i] != ALL_MATCH) {
if(!isExists[arr[i] - arr[firstNonZeroIdx]]) {
isExists[arr[i] - arr[firstNonZeroIdx]] = true;
falseNum --;
}
}
}
isContinuous = falseNum <= firstNonZeroIdx;
Log.log(isContinuous);
}
// 在初始剪枝条件之后, 只需要判断是否存在重复的元素就好了
public static void isContinuousSeq02(int[] arr) {
Arrays.sort(arr);
int firstNonZeroIdx = getFirstNonAllMatchIdx(arr);
int deltaVal = arr[arr.length-1] - arr[firstNonZeroIdx];
int deltaIdx = arr.length-1 - firstNonZeroIdx;
// 数据的值相差太大的, 用0都不可能弥补的, 或者相差太小, 存在一个或多个一样的
if((deltaVal > deltaIdx + firstNonZeroIdx) || (deltaVal < deltaIdx) ) {
Log.log(false);
return ;
}
Log.log(true);
}
// 获取arr中第一个非0 的数据的索引
private static int getFirstNonAllMatchIdx(int[] arr) {
int idx = -1;
for(int i=0; i<arr.length; i++) {
if(arr[i] != ALL_MATCH) {
idx = i;
break ;
}
}
return idx;
}
}
效果截图
总结
对于排序的操作, 因为差值范围不大, 可以采用O(n)的桶排序
查找非0元素的操作, 因为是有序嘛, 可以采用二分查找的思路针对当前场景进行改写
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!