[leetcode笔记002]二分查找

题目

  • 打算先跟着代码随想录刷题,最后补补hot100,剑指offer,每天最少两题,最后可能合计200多道题吧,应该够用了。
  • 704.二分查找
  • 解法总结:1.反应出使用二分查找,有序,无重复元素,碰到这个情况要想到使用二分;2.记住条件 left<=right
  • 时间复杂度O(logn),最好O(1),最坏O(logn)

代码

var search = function(nums, target) {
	let left = 0;
	let mid = 0;
	let right = nums.length-1;  

	while (left <= right) {

		// 别人算法的借鉴,使用了位运算 + 防止大数溢出
		// mid = left + ((right - left) >> 1);

		mid = parseInt(left + right); 

		if (nums[mid] === target){
			return mid;
		} else if (nums[mid] > target){
			right=mid-1;
		} else if (nums[mid] < target){
			left=mid+1;
		}
	}
	return -1;
};

一些自己的分析

  • 时间复杂度O(logn),最好O(1),最坏O(logn)
  • 复习了parseInt,学到了相加防大数的位运算操作和(right - left) / 2 + left;
  • 二分法前提:有序,无重复元素,碰到这个情况要想到使用二分
  • 边界问题,第一次提交没考虑left = right的情况
  • 看了下分析,两种定义情况
  1. 如果target 是在一个在左闭右闭的区间里,也就是[left, right],那么while (left <= right) 要使用 <= , if (nums[middle] > target) right 要赋值为 middle - 1
  2. 如果target 是在一个在左闭右开的区间里,也就是[left, right),那么while (left < right) 要使用 < , if (nums[middle] > target) right 要赋值为 middle
  • 所以我的解法是第一种,更明确了呢。

其他相关题型

35.搜索插入位置
var searchInsert= function(nums, target) {
	let left = 0;
	let mid = 0;
	let right = nums.length-1;  

	while (left <= right) {
		mid = left + ((right - left) >> 1);
		if (nums[mid] === target){
			return mid;
		} else if (nums[mid] > target){
			right=mid-1;
		} else if (nums[mid] < target){
			left=mid+1;
		}
	}
	  
	//自己写的
	// if (nums[mid] > target) {
	// 	return mid; //此时mid=left
	// } else if (nums[mid] < target) {
	// 	return mid+1; //此时mid+1=left
	// }  

	//优化版
	return left
};
34. 在排序数组中查找元素的第一个和最后一个位置
  • 我自己的想法,先找到一个目标值,再以目标值为起点向两边逐个遍历
  • 虽然过了,但最后分析了下,O(n)了,看了下答案,要用二分法分别找左右边界
//我自己的
var searchRange = function(nums, target) {
	let left = 0;
	let mid = 0;
	let right = nums.length-1;
	let targetStart=-1;
	let targetEnd=-1;  

	while (left <= right) {
		mid = left + ((right - left) >> 1);
		if (nums[mid] === target){
			targetStart = mid;
			targetEnd = mid;
			for ( ; targetEnd < nums.length; targetEnd++) {
				if (nums[targetEnd] !== target) {
					targetEnd--;
					break;
				}
			}
			for ( ; targetStart > -1; targetStart--) {
				if (nums[targetStart] !== target) {
					targetStart++;
					break;
				}
			}
			if (targetEnd === nums.length) targetEnd=nums.length-1;
			if (targetStart === -1) targetStart=0;
			break;
		} else if (nums[mid] > target){
			right=mid-1;
		} else if (nums[mid] < target){
			left=mid+1;
		}
	}
	return [targetStart, targetEnd];
};
//参考答案后
/**
* 思路,找到相等的给变量赋个值
* 然后继续找,找右边界就让left=mid+1,找左边界就让right=mid-1
* 最后判断有没有赋过值,赋过那就是最右/左端的,没赋过那就是没有这个值,输出-1;
*/
const searchBorder = (nums, target, startOrEnd) => {
	let left = 0;
	let mid = 0;
	let right = nums.length-1;
	//标识下有没有被赋值过
	let result = -2;  

	while (left <= right) {
		mid = left + ((right - left) >> 1);
		if (nums[mid] === target){
			if (startOrEnd === 'start') {
				right = mid-1;
				result = mid;
			} else {
				left = mid+1;
				result = mid;
			}
		} else if (nums[mid] > target){
			right = mid-1;
		} else {
			left = mid+1;
		}
	}
	if (result!==-2) {
		return result;
	} else {
		return -1;
	}
};  

var searchRange = function(nums, target) {
	let targetStart = searchBorder(nums, target, 'start');
	let targetEnd = searchBorder(nums, target, 'end');
	return [targetStart, targetEnd];
};
69. x 的平方根
  • 二分查找一次过
  • 看了官方解析,回想起了被牛顿迭代支配的恐惧
var mySqrt = function(x) {
	let left = 0
	let right = x
	let mid
	
	while (left <= right) {
		mid = parseInt(left + (right - left) / 2)
		if (mid * mid === x){
			return mid
		}else if (mid * mid > x){
			right = mid -1
		}else {
			left = mid + 1
		}
	}
	if (mid * mid > x){
		return mid-1
	} else{
		return mid
	}
};
//牛顿迭代法,迭代公式:1.x0 = C = x 2. xi = 0.5 * (x0 + C / x0)
var mySqrt = function(x) {
	if (x === 0){
		return 0
	}
	let C = x
	let x0 = x
	let xi
	while (true) {
		xi = 0.5 * (x0 + C / x0)
		if (Math.abs( x0 - xi ) < 1e-7){
			break
		}
		x0 = xi
	}
	return parseInt(x0)
};
367. 有效的完全平方数
  • 和上题代码基本相同,判断下true和false即可
  • 官方使用牛顿法,在取整之后再迭代似乎有点问题,x0-xi加上绝对值之后会陷入死循环。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值