在排序数组中查找数字I
统计一个数字在排序数组中出现的次数。
题解
-
暴力(罢了)
-
二分查找
- 算法思想
- 使用二分查找,找到算法中target 存在的一个位置,然后再向 target 两边遍历,直到小于或大于 target,返回索引
- 复杂度分析
- 时间复杂度 O(logn):但是在 target 个数接近于 n 的时候复杂度会退化为 O(n) (待优化)
- 空间复杂度 O(1)
class Solution { int[] nums; public int search(int[] nums, int target) { this.nums = nums; int left = 0,right = nums.length - 1,length = nums.length; while(left <= right){ int mid = (left + right)/2; if(nums[mid] > target)right = mid-1; else if(nums[mid] < target)left = mid + 1; else return searchTarget(mid,target,length); } return 0; } int searchTarget(int index,int target,int length){ int left = index-1,right = index,res = 0; while(left >= 0){ if(nums[left] == target)res++; else break; left--; } while(right < length){ if(nums[right] == target)res++; else break; right++; } return res; } }
- 算法思想
-
优化的二分查找
- 算法思想
- 通过二分查找直接找到第一个和最后一个 target 的位置
- 重点是使用二分查找找到第一个和最后一个 target 的位置
- 复杂度分析
- 时间复杂度 O(logn)
- 空间复杂度 O(1)
- 缺点
- 较为复杂,容易写错
class Solution { public int search(int[] nums, int target) { int left = 0,right = nums.length - 1; int first = getFirstK(nums,left,right,target); int last = getLastK(nums,left,right,target); if(first != -1)return last - first + 1; else return 0; } int getFirstK(int[] nums,int left,int right,int target){ if(left > right)return -1; int mid = left + (right - left)/2; if(nums[mid] < target)left = mid + 1; else if(nums[mid] > target)right = mid -1; else{ //此处为查找 target 第一个 target 索引的逻辑,如果后面的位置与前面相同,则不是最后一个 if(mid > 0 && nums[mid] == target && nums[mid-1] == target)right = mid-1; else return mid; } return getFirstK(nums,left,right,target); } int getLastK(int[] nums,int left,int right,int target){ if(left > right)return -1; int mid = left + (right - left)/2; if(nums[mid] < target)left = mid + 1; else if(nums[mid] > target)right = mid -1; else{ if(mid < nums.length - 1 && nums[mid] == target && nums[mid+1] == target)left = mid + 1; else return mid; } return getLastK(nums,left,right,target); } }
- 算法思想
0~n-1中缺失的数字 II
一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。
输入: [0,1,3] 输出: 2
题解
-
二分查找
- 算法思想
- 在索引为 n 并且 n 前没有缺失数字的情况下,nums[n] = n
- 如前缺失数字,nums[n] = n+1
- 利用此特征进行二分查找
- 复杂度分析
- 时间复杂度 O(logn)
- 空间复杂度 O(1)
class Solution { public int missingNumber(int[] nums) { int left = 0,right = nums.length - 1; while(left <= right){ int mid = left + (right - left) / 2; if(nums[mid] != mid){ if(mid == 0 || nums[mid-1] == mid -1)return mid; else right = mid -1; } if(nums[mid] == mid)left = mid + 1; } //当缺失的数字是最后一个时,left 会等于 nums.length if(left == nums.length)return left; //当没有缺失时,无效输入 return -1; } }
- 算法思想
总结
-
二分搜索容易写错呀哈哈哈哈,记住二分搜索在 target 有重复的时候可以进行优化
-
二分查找真的要小心,非常非常容易写错
-
if else if 不要使用太多
-
如(这样很容易出错,最好换成下面的方式)
if else if else if else if if{ if() else } else
-