LeetCode进34-二分查找

闲聊

在开算法博客至今,曾经有读者在评论中质疑过博客中大厂面试题的真实性,在以前某一篇知乎评论中我曾经回复过而且列出了某些依据,如今看来以为彻底不必。在此声明一下,全部算法题都是经过我的精心整理查阅,有些是源于一些开源社区,有些是来自某些开发者面试经验(面经),还有些则是从某些技术网站获取...这些算法题选的题的依据是我的判断理解一些对与算法学习进阶比较有表明性的典型问题。后续相似面试题的真实性问题将再也不回复,最后再次声明本人开算法博客的初衷是帮助有须要的人,有任何技术方面的问题欢迎交流,非诚勿扰~java

概要

二分查找也称折半查找,是典型的分治思想的应用,是一种效率较高的查找方法。折半查找要求线性表必须采用顺序存储结构,并且表中元素按关键字有序排列。以前的一篇博客LeetCode进阶4-分而治之也介绍过度治法,本篇进一步介绍其思想应用的经典算法—二分查找。面试

34. Find First and Last Position of Element in Sorted Array (Medium)

Given an array of integers nums sorted in ascending order, find the starting and ending position of a given target value.算法

Your algorithm's runtime complexity must be in the order of O(log n).数组

If the target is not found in the array, return [-1, -1].bash

Example 1:学习

Input: nums = [5,7,7,8,8,10], target = 8 Output: [3,4] Example 2:网站

Input: nums = [5,7,7,8,8,10], target = 6 Output: [-1,-1]编码

34. 在排序数组中查找元素的第一个和最后一个位置(中等)

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。spa

你的算法时间复杂度必须是 O(log n) 级别。指针

若是数组中不存在目标值,返回 [-1, -1]。

示例 1:

输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4] 示例 2:

输入: nums = [5,7,7,8,8,10], target = 6 输出: [-1,-1]

  • 分类:二分查找(Binary Search)

分析&&思路

按照正常的二分查找思路,循环找到匹配目标数字的下标,继续将右指针变小查找到第一个目标数字。用新的循环从找到的第一个目标数字下标从左往右查找直到最后一个目标数字。(具体的查找思路见伪代码)

伪代码

一、相关声明
   1.一、声明搜索用的左右指针,初始左指针下标0,右指针下标数组末位nums.length-1;
   1.二、获取数组中间下标mid = (l + r) / 2;
   1.三、声明建立结果数组,初始化赋值-1;
二、循环二分查找,直到左指针大于右指针查找结束
   2.一、若中间位置数字小于目标数字,说明目标数字在mid右边,将左指针l右移赋值为mid+1;
   2.二、若中间位置数字大于目标数字,说明目标数字在mid左边,将右指针r左移赋值为mid-1;
   2.三、若中间位置数字等于目标数字:
      2.3.一、将mid做为第一次出现位置存入数组;
      2.3.二、右指针r左移赋值为mid-1,继续查找相等的数字直到找到第一次出现的位置;
   2.四、更新mid;
三、从第一次出现的位置开始,循环往右查找最后一次出现的位置:
   3.一、声明pr指针初始赋值为第一次出现位置下标;
   3.二、当二分查找已找到目标数字时
      3.2.一、循环直到数组越界或者数组当前元素不等于目标元素时结束:
        3.2.1.一、更新最后一次出现位置下标;
        3.2.1.二、更新以后往右移动指针;
四、最终返回已存储位置的结果数组;
          
复制代码

编码实践

public int[] searchRange(int[] nums, int target) {
		int l = 0, r = nums.length - 1;
		int mid = (l + r) / 2;
		int res[] = { -1, -1 };
		while (l <= r) {
			if (nums[mid] < target) {
				l = mid + 1;
			} else if (nums[mid] > target) {
				r = mid - 1;
			} else {
				res[0] = mid;
				r = mid - 1;
			}
			mid = (l + r) / 2;
		}
		int pr = res[0];
		if (pr != -1) {
			while (pr <= nums.length - 1 && target == nums[pr]) {
				res[1] = pr++;
			}
		}
		return res;
	}
复制代码

1.jpg

扩展延伸

本题实际在头条笔试题中也曾经出现过

有序数组二分查找,返回查找元素最后一次出现的位置,若不存在则返回-1

感兴趣能够结合上面思路思考,下面是题解参考代码:

public static int searchRange(int[] nums, int target) {
		int l = 0, r = nums.length - 1;
		int mid = (l + r) / 2;
		int res = -1;
		while (l <= r) {
			if (nums[mid] < target) {
				l = mid + 1;
			} else if (nums[mid] > target) {
				r = mid - 1;
			} else {
				res = mid;
				l = mid + 1;
			}
			mid = (l + r) / 2;
		}

		return res;
	}
复制代码

Alt

关注订阅号 获取更多干货~
相关文章
相关标签/搜索