问题一:在排序数组中查找数字
问题描述:
统计一个数字在排序数组中出现的次数。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: 2
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: 0
解题思路:
解法一:暴力破解,循环遍历
遍历数组,统计目标值出现的个数,时间复杂度为O(n),n为数组的长度。
解法二:二分查找,两边扩展
由于数组是有序的,所以我们可以使用二分法找到目标值target,然后向两边扩散查找进行统计(因为数组是有序的,所以target一定是相邻在一起的),直到与target的值不相等为止。
代码实现:
解法一代码:
public int search(int[] nums, int target) {
int count = 0;
for(int i=0; i<nums.length; i++) {
if(nums[i]==target)
count++;
}
return count;
}
解法一提交结果:
解法二代码:
public static int search2(int[] nums, int target) {
int count = 0;
int l = 0;
int r = nums.length-1;
while(l<=r) {
int mind = (l+r)/2;
if(nums[mind]>target)
r = mind-1;
else if(nums[mind]<target)
l = mind+1;
else {
//找到之后向两边扩展,寻找是否还有目标值
count++;
int t = mind+1;
while(t<nums.length && nums[t++]==target)
count++;
t = mind-1;
while(t>=0 && nums[t--]==target)
count++;
break;
}
}
return count;
}
提交结果:
问题二:有序数组中缺失的数字
问题描述:
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
示例 1:
输入: [0,1,3]
输出: 2
示例 2:
输入: [0,1,2,3,4,5,6,7,9]
输出: 8
解题思路:
解法一:利用数组下标判断
由于数组是从0开始递增的,所以当第一次出现nums[i]
与数组下标i
不对应时,那么i
就是缺少的值。如果整个数组都对应,那么缺少的就是n,即数组的长度。
解法二:二分法,寻找边界值
用二分法寻找nums[i]
与数组下标i
开始不对应的边界,即可找出缺少的值。
代码实现:
解法一代码:
public int missingNumber(int[] nums) {
for(int i=0; i<nums.length; i++) {
if(i!=nums[i]) return i;
}
//如果数组是有序递增的,那么缺少的是n,即数组的长度
return nums.length;
}
解法一提交结果:
解法二代码:
public int missingNumber(int[] nums) {
int i = 0, 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;
}
解法二提交结果:
总结:问题二的解法二和解法一相差不大,因为解法一只有再最坏的情况下时间复杂度才是O(n)。nums[i]
与数组下标i
不相等的情况出现得越靠前解法一的效率就越高,甚至超过解法二。并且解法一再循环遍历的过程中不需要进行计算(相加运算)。从代码上看解法一也更简洁。