9.29lc
本来想着继续刷递归 和 回溯呢: 谁知 被 二分查找吸引
简单介绍 二分: 一个有序的数组 找寻一个数字的方法
时间复杂度 log n: 优于普通的直接遍历
区别于 双指针:
35. 搜索插入位置 - 力扣(LeetCode) (leetcode-cn.com)
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1;
while(left <= right) {
int mid = (left + right) / 2;
if(nums[mid] == target) {
return mid;
} else if(nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode) (leetcode-cn.com)
:要求复杂度 longn
上来的思路: 先找到 目标值。 然后 线性查找左右找边界 。。。 这样复杂度 为 n了
:真正的做法: 以左右边界来做文章, 我们去人为的 规定 左右边界:
找到第一个 找到最后一个 就可以了 很巧妙~~
class Solution {
public int[] searchRange(int[] nums, int target) {
int[] res = new int[] {-1, -1};
res[0] = binarySearch(nums, target, true);
res[1] = binarySearch(nums, target, false);
return res;
}
//leftOrRight为true找左边界 false找右边界
public int binarySearch(int[] nums, int target, boolean leftOrRight) {
int res = -1;
int left = 0, right = nums.length - 1, mid;
while(left <= right) {
mid = left + (right - left) / 2;
if(target < nums[mid])
right = mid - 1;
else if(target > nums[mid])
left = mid + 1;
else {
res = mid;
//处理target == nums[mid]
//控制边界问题
if(leftOrRight)
right = mid - 1;
else
left = mid + 1;
}
}
return res;
}
}
33. 搜索旋转排序数组 - 力扣(LeetCode) (leetcode-cn.com)
上边我们说到 二分用在 有序中:
这道题 是个旋转后的结果。 也是 部分有序的
思路: 中间值 和 左右 树 作比较 确定 有序的范围 从而进行寻找
class Solution {
public int search(int[] nums, int target) {
int l=0,r=nums.length-1;
while (l<=r){
int mid =(l+r)/2;
if (nums[mid] == target){
return mid;
}else if (nums[mid]<nums[r]){
if (nums[mid] < target && target <=nums[r]){
l=mid+1;
}else {
r=mid-1;
}
}else {
if (nums[l] <= target && nums[mid] >target){
r =mid-1;
}else {
l=mid+1;
}
}
}
return -1;
}
}
81. 搜索旋转排序数组 II - 力扣(LeetCode) (leetcode-cn.com)
新花样: 重复元素…
思路: 上文一样: 只不过 当
左右边界 和 中间值 相等时 记得 缩小边界
if(arr[mid] == arr[left] && arr[mid] == arr[right]){
l++;
r--;
}
class Solution {
public boolean search(int[] nums, int target) {
int n=nums.length;
int l=0;
int r=n-1;
if(n == 0 ) return false;
if(n == 1){
return nums[0] == target;
}
while(l<=r){
int mid = (l+r)/2;
if(nums[mid] == target){
return true;
}
// 找了半天 是中间值的 = 左 右 子树
if(nums[l] == nums[mid] && nums[r] == nums[mid]){
++l;
--r;
}else if(nums[l]<=nums[mid]){
if(nums[l]<= target && target < nums[mid]){
r=mid-1;
}else{
l=mid+1;
}
}else{
if(target <= nums[n-1] && target> nums[mid]){
l=mid+1;
}else{
r=mid-1;
}
}
}
return false;
}
}
153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode) (leetcode-cn.com)
思路: 关于旋转的 题: 都可以试一下 边界 的比较~
发现和 有边界有关
class Solution {
public int search(int[] nums, int target) {
int l=0,r=nums.length-1;
while (l<=r){
int mid =(l+r)/2;
if (nums[mid] == target){
return mid;
}else if (nums[mid]<nums[r]){
if (nums[mid] < target && target <=nums[r]){
l=mid+1;
}else {
r=mid-1;
}
}else {
if (nums[l] <= target && nums[mid] >target){
r =mid-1;
}else {
l=mid+1;
}
}
}
return -1;
}
}
idea:
- 比较中间值 和 有边界 只有大小 如果大
- 、最小值再 右边 l=mid+1;
- else r=mid;
减 治 思想