算法题总结(一)——二分查找专题

server/2024/9/22 12:24:47/

二分查找

我们二分查找的本质就是每次能够通过中间值来进行分割,能够比较判断,查找到或者接近需要的数据,然后把一部分的数据丢弃掉。

原题

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1

左闭右闭:

class Solution {public int search(int[] nums, int target) {// 避免当 target 小于nums[0]  大于nums[nums.length - 1]时多次循环运算if (target < nums[0] || target > nums[nums.length - 1]) {return -1;}int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + ((right - left) >> 1);  //分割点if (nums[mid] == target)return mid;else if (nums[mid] < target)  //丢弃一部分left = mid + 1;else if (nums[mid] > target)right = mid - 1;}return -1;}
}

35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

我们使用二分法查不存在的数据时,最后left就是应该插入的位置!

class Solution {public int searchInsert(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + ((right - left) >> 1);if (nums[mid] == target)return mid;else if (nums[mid] < target)left = mid + 1;else if (nums[mid] > target)right = mid - 1;return left;// 最终的left返回了应该插入的位置}}

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

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

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

示例 2:

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

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

//左右指针移动,先用二分法找到一个位置,然后左右移动判断

class Solution {public int[] searchRange(int[] nums, int target) {int[] result ={-1,-1};int index=binarySearch(nums,target);if(index==-1)return result;int left=index;int right=index;while(left-1>=0 && nums[left-1]==nums[index]){left--;}while(right+1<nums.length && nums[right+1]==nums[index]){right++;}result[0]=left;result[1]=right;return result;}public int binarySearch(int[] nums,int target){int l=0;int r=nums.length-1;while(l<=r){int mid=l+(r-l)/2;if(nums[mid]==target){return mid;}else if(nums[mid]<target){l=mid+1;}else if(nums[mid]>target){r=mid-1;}}return -1;} 
}

69.X的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

使用二分法查找符合条件的元素

即找到一个平方比x小的 最大的一个就行

即使用二分查找的方法 在0-x之间找到一个符合的最大元素,由于是找一个符合的最大的元素,因此当小于号的时候,l=mid+1,即往右边去查找。

使用long进行类型转换是因为x的平方根相乘可能无法用int表示。

class Solution {public int mySqrt(int x) {  //二分方法通用思想int l=0;int r=x;int ans=-1;while(l<=r){int mid=l+(r-l)/2;if((long)mid*mid<=x)  //既满足ans=mid的条件,又满足l=mid+1的条件。{ans=mid;l=mid+1;}else{r=mid-1;}}return ans;}
}

367.有效的完全平方数

给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false 。

完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。

不能使用任何内置的库函数,如 sqrt 。

示例 1:

输入:num = 16
输出:true
解释:返回 true ,因为 4 * 4 = 16 且 4 是一个整数。

示例 2:

输入:num = 14
输出:false
解释:返回 false ,因为 3.742 * 3.742 = 14 但 3.742 不是一个整数。
class Solution {public boolean isPerfectSquare(int num) { //二分查找从0-num中间的数int left = 0;int right =num;while(left<=right){int mid=left+(right-left)/2;if((long)mid*mid==num)return true; else if((long)mid*mid>num)   //分割right=mid-1;   //注意不要写成 right-1else if((long)mid*mid<num)left = mid + 1;}return false;}
}

74、搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵:

  • 每行中的整数从左到右按非严格递增顺序排列。
  • 每行的第一个整数大于前一行的最后一个整数。

给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。

示例 1:

输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:true

和上面平方根那个题目一样,相当于不是精确的找,只是找到比target小的 最大的一个就行

按照行查找的时候,不需要一定相等,只需要找到比target小的 最大的一个就行。

class Solution {//两次二分查找,先搜索合适的行,再在这一行中搜索列。public boolean searchMatrix(int[][] matrix, int target) {int index=search1(matrix,target);if(index==-1)   return false;return search2(matrix[index],target);}public int search1(int[][] matrix,int target){int low=0;int high=matrix.length-1;int ans=-1;   //和上面平方根那个题目一样,相当于不是精确的找,只是找到比target小的 最大的一个就行while(low<=high){int mid=low+(high-low)/2;if(matrix[mid][0]<=target){   ans=mid;  //记录low=mid+1;  //分割缩小范围}else{high=mid-1;}}return ans;}public boolean search2(int[] row,int target){int left=0;int right=row.length-1;while(left<=right){int mid=left+(right-left)/2;if(row[mid]==target)    return true;else if(row[mid]>target)right=mid-1;else if(row[mid]<target)left=mid+1;}return false;}
}

33、搜索旋转排序数组

整数数组 nums 按升序排列,数组中的值 互不相同

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

旋转数组使用中间值被分成有序和无序两部分,这样利用有序比较大小,就可以判断target的具体位置。

我们二分查找的本质就是每次能够通过中间值来进行分割,能够比较判断,查找到或者接近需要的数据,然后把一部分的数据丢弃掉。

class Solution {//分为有序数组和旋转数组public int search(int[] nums, int target) {int left=0;int right=nums.length-1;while(left<=right){int mid=left+(right-left)/2;if(nums[mid]==target)return mid;//注意此时用小于等于,因为mid可能和left相等//左边的有序if(nums[left]<=nums[mid]){//target在前半部分if(target>=nums[left] &&target<nums[mid])right=mid-1;elseleft=mid+1;}else  //后半部分有序{//且target在后半部分if(target<=nums[right]&&target>nums[mid])left=mid+1;elseright=mid-1;}}return -1;}
}

153、寻找旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], …, a[n-1]]旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

右旋,上一题是左旋。

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 4 次得到输入数组。

其实左旋右旋本质上都是一样的:我们可以模仿上一题,利用mid来分割数组,如果nums[left]<=nums[mid],说明mid左边是有序的,所以左边的最小值就是nums[left],否则,mid的右边就是有序的,那么mid的右边部分nums[mid]就是最小值。

即我们二分查找的本质就是每次能够通过判断分割,能够查找到或者接近需要的数据,然后把一部分的数据丢弃掉。

class Solution {public int findMin(int[] nums) {//模仿第33题的思路,数组被分为有序和无序两个数组int left=0;int right=nums.length-1;int ans=nums[0];while(left<=right){int mid=left+(right-left)/2;//mid左边是有序的,知道mid左边是有序的,那么我们可以记录下来左边的最小值,然后就可以吧左边的丢弃了if(nums[left]<=nums[mid]){ans=Math.min(ans,nums[left]);  //记录left=mid+1;  //丢弃左边的}//mid右边是有序的else{ans=Math.min(ans,nums[mid]);right=mid-1;}}return ans;}
}

http://www.ppmy.cn/server/120274.html

相关文章

GPT-4o在matlab编程中性能较好,与智谱清言相比

边标签由矩阵给出 s [1 2 3 3 3 3 4 5 6 7 8 9 9 9 10]; t [7 6 1 5 6 8 2 4 4 3 7 1 6 8 2]; G graph(s,t); plot(G) ------------------- GPT-4o给出的代码可用&#xff0c; clc;clear; % 定义边的起点和终点 s [1 2 3 3 3 3 4 5 6 7 8 9 9 9 10]; t [7 6 1 5 6 8 2 …

vulkano (rust) 画一个三角形 (vulkan 渲染窗口初始化 (Linux) 下篇)

上文说到, vulkan 相比 OpenGL (ES), 更加贴近底层硬件, 许多东西需要应用软件手动管理, 所以 vulkan 的初始化过程比较麻烦, 或者说学习曲线比较陡峭. 但是, 这种麻烦是一次性的, 一旦学会了, 就能开始享受 vulkan 的诸多好处啦 ~ 本文以绘制一个三角形为例, 介绍 vulkan 的初…

Hadoop的安装和使用

1. Hadoop简介 Hadoop是一个能够对大量数据进行分布式处理的软件框架&#xff0c;并且是以一种可靠、高效、可伸缩的方式进行处理的&#xff0c;它具有以下几个方面的特性。 高可靠性。高效性。高可扩展性。高容错性。成本低。运行在Linux平台上。支持多种编程语言。 2. 分布…

chromedriver下载与安装方法

chromedriver下载地址&#xff1a; 版本在114及以下&#xff1a;http://chromedriver.storage.googleapis.com/index.html 版本在128&#xff1a;https://googlechromelabs.github.io/chrome-for-testing/#stable 其他版本下载方法&#xff1a; 如版本128.0.6613.137位下载地址…

Kafka 为什么这么快?

Kafka 是一款性能非常优秀的消息队列&#xff0c;每秒处理的消息体量可以达到千万级别。今天来聊一聊 Kafka 高性能背后的技术原理。 1 批量发送 Kafka 收发消息都是批量进行处理的。我们看一下 Kafka 生产者发送消息的代码&#xff1a; private Future<RecordMetadata>…

VMware安装rustdesk服务器

一、准备 首先准备服务器镜像&#xff1a;22.04 虚拟机硬件配置选1G RAM 20G ROM就行 二、虚拟机安装过程 安装过程中选最小体积安装&#xff0c;并勾选安装SSH 安装完成后在SSH工具中连接&#xff08;步骤可视实际情况跳过&#xff09;&#xff1a; //需要先连接外网 1.安…

电脑ip会因为换了网络改变吗

在当今数字化时代&#xff0c;IP地址作为网络世界中的“门牌号”&#xff0c;扮演着至关重要的角色。它不仅是设备在网络中的唯一标识&#xff0c;也是数据交换和信息传递的基础。然而&#xff0c;对于普通用户而言&#xff0c;一个常见的问题便是&#xff1a;当电脑连接到不同…

GO GIN SSE DEMO

文章目录 接口描述&#xff1a;1.1 /events/time - 时间流1.2 /events/numbers - 数字流 2. 用户管理接口2.1 /user/:id - 获取用户信息2.2 /user - 创建用户 项目结构1. main.go2. 创建 handlers/event_time.go3. 创建 handlers/event_number.go4. handlers/user.go5. 运行服务…