给你一个非负整数数组 nums 。如果存在一个数 x ,使得 nums 中恰好有 x 个元素 大于或者等于 x ,那么就称 nums 是一个 特殊数组 ,而 x 是该数组的 特征值 。
注意: x 不必 是 nums 的中的元素。
如果数组 nums 是一个 特殊数组 ,请返回它的特征值 x 。否则,返回 -1 。可以证明的是,如果 nums 是特殊数组,那么其特征值 x 是 唯一的 。
解题思路:
感觉就是插入一个数 i 后,后面有 i 个大于或者等于 i 的数,如果存在这样一个 i 就将其返回,如果不存在就返回-1。
有了这个想法,就想到了 BinarySearch,它本身就是查找一个数在一个数组中出现的位置,因为二分查找的前提是有序,所以我们需要将数组排序。i 的边界值为不能超过数组的数量,判断条件就是数组长度-当前插入位置是否等于 i 。
BinarySearch的返回值的问题,由下面总结而来。需要注意的是返回值并不是 i 第一次出现的位置,它前面可能会有一样的重复值,我们需要向前遍历直到当前位置为第一次出现的位置。
[1] 搜索值不是数组元素,且在数组范围内,从1开始计数,得“ - 插入点索引值”;
[2] 搜索值是数组元素,从0开始计数,得搜索值的索引值;
[3] 搜索值不是数组元素,且小于数组内元素,索引值为 – 1;
[4] 搜索值不是数组元素,且大于数组内元素,索引值为 – (length + 1);
public int specialArray(int[] nums) {
int n = nums.length ;
Arrays.sort(nums);
for (int i = 1; i <= n; i++) {
int pos = Arrays.binarySearch(nums, i);
pos = pos >= 0 ? pos : -pos - 1;
// System.out.println(pos+" "+(n-pos+1)+" "+i);
while (pos>=1 && nums[pos-1]==i){
pos--;
}
if (n - pos == i) {
return i;
} else if (n - pos< i) {
return -1;
}
}
return -1;
}
这样的做法其实有点略显麻烦,我们并没有利用到后面有 i 个大于等于 i 的条件减轻解题难度,我们只是将其作为一个输出结果的判断条件。但其实我们可以由此直接得到插入点,当 nums[n-i]>=i 时,并且 nums[n-i-1]<i 时
,nums[n-i]
即为插入点。需要注意的是,如果 nums[0]>=n
时,那么必定会存在一个 i==n
。
public int specialArray(int[] nums) {
int n = nums.length ;
Arrays.sort(nums);
if(nums[0]>=n){return n;}
for (int i = 1; i < n; i++) {
if(nums[n-i]>=i&&nums[n-1-i]<i){
return i;
}
}
return -1;
}