遇到有序数组,第一反应就是二分法。
二分法主要思路:
分别在数字头和尾建两个指针,重点比较两个指针中位值与目标值的大小,当中央值比目标值小,说明目标值在中值右边,则可以直接不考虑中值左侧的那些值。
在排序数组中查找数字个数:
方法一:
普通二分法:
public int search(int[] nums, int target) {
int i = 0;
int j = nums.length - 1;
while (i <= j) {
int m = (i + j) / 2;
if (nums[m] <= target) {
i = m + 1;
} else {
j = m - 1;
}
}
int right = i;
if (j >= 0 && nums[j] != target) {
return 0;
}
i = 0;
j = nums.length - 1;
while (i <= j) {
int m = (i + j) / 2;
if (nums[m] < target) {
i = m + 1;
} else {
j = m - 1;
}
}
return right - j - 1;
}
先查找这几个目标数的右边界,再查找左边界,最后用右边界-左边界+1即为该数字个数。
方法二:
在方法一上进行优化,在查找目标数的左边界,实际等效于在查找目标数-1的右边界,哪怕目标数-1不存在,也会查到比目标数小一级的数的右边界,再用两个边界相减+1
public int search2(int[] nums, int target) {
return right(nums, target) - right(nums, target - 1);
}
public int right(int[] nums, int target) {
int i = 0;
int j = nums.length - 1;
while (i <= j) {
int m = (i + j) / 2;
if (nums[m] <= target) {
i = m + 1;
} else {
j = m - 1;
}
}
return i;
}
0~n-1中缺少的数字:
方法一:
将数字依次加入到数组中,当该数字与下标不同,说明缺少了数。
public int missingNumber(int[] nums) {
int index = 0;
for (int i : nums) {
if (i != index) {
return index;
}
index++;
}
return index;
}
这个方法在数少时候可以实现,数多了效率低。
方法二:
二分法:以缺少的数字将数组分为两部分,当缺少数字,后续数字都将比本身的下标要小,以这点为切入点进行二分法的判断。
public int missingNumber2(int[] nums) {
int i = 0;
int j = nums.length - 1;
while (i <= j) {
int m = (i + j) / 2;
if (nums[m] == m) {
i = m + 1;
} else {
j = m - 1;
}
}
return i;
}
当中央值与下标相同,则说明缺少的数在右侧。
当中央值比下标小,则说明缺少的数在左侧。
遍历最后的结果应该i>j,即j为最后一个值与下标相同的数,i为缺少数的下标。