leetcode佛系刷题(无序)-第五天
1.搜索旋转排序数组
题目:
整数数组 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) 的算法解决此问题。
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
输入:nums = [1], target = 0
输出:-1
思路分析:
当我们看到这道题目时,首先要明确题目要求时间复杂度是O(logn)。这提示我们需要使用二分查找算法,因为二分查找的时间复杂度是O(logn)。但是,这道题有一个点我们一定要注意,就是数组进行了旋转,所以我们不能直接使用二分查找法。所以,我们需要对二分查找法加以改进,使其可以适用于旋转后的有序数组。
那么好,接下来,我们就要考虑如何实现了。
我们可以通过判断有序的子数组来确定下一步的查找范围。每次将数组从中间分开,必然存在一个有序的子数组,而另一个子数组不一定有序,我们可以先判断有序的那个子数组,如果目标值target在有序的那个子数组内,就在该子数组继续二分查找;如果目标值不在有序的那个子数组中,就在另一个子数组中继续二分查找。
嗨嗨害,分析至此,我们已经有了详细的思路,接下来就是用代码加以实现。
代码如下:
class Solution {public int search(int[] nums, int target) {int left = 0, right = nums.length - 1;while (left <= right) {int mid = left + (right - left) / 2;// 防止left+right溢出if (nums[mid] == target) {return mid;}if (nums[left] <= nums[mid]) { // 左半部分有序if (nums[left] <= target && target < nums[mid]) {right = mid - 1;} else {left = mid + 1;}} else { // 右半部分有序if (nums[mid] < target && target <= nums[right]) {left = mid + 1;} else { // target在左半部分right = mid - 1;}}}return -1;}
}
代码读完了吧,懂了吗,那么好,我们来举几个例子来模拟一下流程哈!
首先,来看一下数组长度为奇数的情况:
假设nums = [4,5,6,7,0,1,2],它是将原本有序数组
[0,1,2,4,5,6,7]在下表3处旋转得到的。我们给一个目标值target = 5。
第一步:我们将数组从中间分开,计算中间位置 mid:
left = 0, right = 6, mid = 3;
第二步:我们判断中间位置 mid 所在的元素是否等于目标值 5。由于 nums[mid] = 7,不等于目标值 target = 5,因此我们需要进一步缩小查找范围。
第三步:我们判断左半部分和右半部分哪一个是有序的。根据题目的定义,左半部分 [4, 5, 6,7] 是有序的,我们可以先在左半部分查找目标值target = 5。
第四步:我们根据左半部分的有序性,可以将查找范围缩小为 [4,5]。再次计算中间位置 mid:
left = 0, right = 1, mid = 0;
第五步:我们判断中间位置 mid 所在的元素是否等于目标值 5。由于 nums[mid] = 4,不等于目标值 5,因此我们需要进一步缩小查找范围。
第六步:此时左右两个下标重合,整个查找过程结束。由于target = 5在数组中,所以返回下标1。
数组长度为偶数的情况:
假设nums = [6,7,8,9,1,2,3,4],我们给一个目标值target = 3。
第一步:我们将数组从中间分开,计算中间位置 mid:
left = 0, right = 7, mid = 3;
第二步:我们判断中间位置 mid 所在的元素是否等于目标值 3。由于 nums[mid] 的值为 9,不等于目标值 3,因此我们需要进一步缩小查找范围。
第三步:我们判断左半部分和右半部分哪一个是有序的。根据题目的定义,左半部分 [6, 7, 8, 9] 是有序的,而右半部分 [1, 2, 3, 4] 是有序的。因此,我们可以先在右半部分查找目标值 3。
第四步:左半部分显然不存在3,这里我就跳过步骤了,直接看右半部分。
第五步:我们将[1,2,3,4]分开,计算中间位置mid:
left = 4, right = 7, mid = 5;
第六步:我们判断中间位置 mid 所在的元素是否等于目标值 3。由于 nums[mid] 的值为 2,不等于目标值 3,因此我们需要进一步缩小查找范围。
第七步:同样的过程,右半部分,left = 6,right = 7 ,mid = 6,此时
nums[mid] = tagert, 返回mid = 6。
感觉写的有点乱,但是大体就是这个意思,就写到这里吧!
2.在排序数组中查找元素的第一个和最后一个位置
题目:
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
emsp;&你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
输入:nums = [], target = 0
输出:[-1,-1]
思路分析:
首先,题目中要求时间复杂度为 O(logn),我们可以考虑二分查找。 其次,题目中要求找到给定目标值的开始位置和结束位置,因此我们需要对二分查找的结果进行一些额外的处理。具体来说,我们需要分别使用二分查找找到目标值第一次出现的位置和最后一次出现的位置。如果找到了目标值,那么根据二分查找的性质,它们一定是左右两个边界。如果没有找到目标值,则返回 [-1, -1]。
最后,我们需要考虑数组中元素的顺序。题目中说明了数组是按照非递减顺序排列的,因此我们需要在二分查找的过程中保持这个顺序。具体来说,我们可以通过比较中间元素和目标值的大小来确定查找的方向,从而保证每次查找的区间都是非递减的。
代码如下:
class Solution {public int[] searchRange(int[] nums, int target) {int[] result = { -1, -1 }; // 定义结果数组,初始值为[-1,-1]if (nums == null || nums.length == 0) { // 如果数组为空,则返回[-1,-1]return result;}int left = 0; // 左边界int right = nums.length - 1; // 右边界while (left <= right) { // 当左边界小于等于右边界时循环(注意这里是小于等于)int mid = left + (right - left) / 2; // 取中间值if (nums[mid] < target) { // 如果中间值小于目标值,则往右边查找left = mid + 1;} else if (nums[mid] > target) { // 如果中间值大于目标值,则往左边查找right = mid - 1;} else { // 如果中间值等于目标值,则确定左右边界,以此找到第一个和最后一个位置if (nums[left] == target && nums[right] == target) { // 如果左右边界都等于目标值,则找到了第一个和最后一个位置,直接返回结果result[0] = left;result[1] = right;return result;} else if (nums[left] != target) { // 如果左边界不等于目标值,则左边界加1left++;} else { // 如果右边界不等于目标值,则右边界减1right--;}}}return result; // 如果循环结束还没有找到,则返回[-1,-1]}
}
今天就写到这里吧,看论文去了!
leetcode佛系刷题(无序)-第五天相关推荐
- 2021.5.21开始的兔系刷题之路 根据LeetCode分类进行逐个击破 培养出自己的套路~
十二月了 再更一波 最近的题解都写在这个仓库中,另外仓库中也记录了自己学习前端过程中的收获~ 近期刷题情况-- 2021-11突然好多人看这篇XD 来更一波,依旧在保持刷题啦~ 目前是跟着一本前端算法 ...
- 力扣(LeetCode)打卡刷题交流计划(长期维护)
前言 忙忙活活暑期过去了一半,在即将升学的日子里,打算干点什么东西,由于实力以及经验的欠缺没有创群和大家讨论,但我更喜欢以更实在的方式--能作点什么--和大家一起从0打开力扣LeetCode, 对,没 ...
- leetcode 高薪_LeetCode刷题实战69:x 的平方根
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...
- Leetcode按Tag刷题
按照Leetcode的Tag来刷题,从easy到hard刷题 关于如何让Leetcode按难易程度排序,可按以下步骤: 1. 进入Leetcode后,点击code 2.点击code后,可查看所有题目, ...
- LeetCode:数组刷题(17道经典题目)
LeetCode 数组刷题(17道经典题目) 本文带来的是以数组为主题的经典题目,主要实现是C++,部分题目也用Python实现了. 704. 二分查找 35.搜索插入位置 34. 在排序数组中查找元 ...
- 力扣(LeetCode)怎么刷题,以排序算法为例
掌握 LeetCode 刷题方法再开始刷题,属于磨刀不误砍柴工.掌握正确方法是非常重要的. 如果你在刷题的时候发现怎么也写不出来,别担心,这是正常的.如果你还发现,之前明明刷过的题,过段时间再做的时候 ...
- 2022-12-16 leetcode与蓝桥刷题情况
一.leetcode题目 1.构成特定和需要添加的最少元素 题目描述 给你一个整数数组 nums ,和两个整数 limit 与 goal .数组 nums 有一条重要属性:abs(nums[i]) & ...
- IDEA LeetCode力扣刷题插件 中文类名 模板
在用idea力扣插件刷题时,用中文作为类名会出现空格或者其他符号,总所周知,变量名和类名是不能出现空格和其他符号的,在我查阅了官方文档后,发现模板的工具类是继承了Stringutils的,所以在代码模 ...
- LeetCode按知识点刷题,额外附带题解
刷题顺序转自:ACM金牌选手整理的[LeetCode刷题顺序]_清澈不在远方-CSDN博客 题解为本人自刷 数据结构 数组&双指针 LeetCode 1. 两数之和 /*** 给定一个整数数组 ...
最新文章
- 2018牛客暑假多校三 E(KMP运用)
- 简单的http服务器示例
- 11.context_suggester
- CSP2021NOIP2021游记
- BCH码和m序列参数估计(梅西迭代算法求多项式的MATLAB实现)
- git 配置免密登陆
- java double 的精度_Java Double的精度问题
- 近期 AI 领域招聘招生信息汇总
- 内核引导参数IOMMU与INTEL_IOMMU有何不同?
- 介绍10款常用的JAVA测试工具
- Adb refused a command 解决方法
- android studio 模拟器很慢,解决AndroidStudio模拟器卡慢的问题
- idm无法集成到谷歌浏览器怎么解决?
- android lomo设计与实现,拍静物 美图秀秀Android轻松调LOMO风格
- 开发一个App大概要多少钱?
- mysql utl_file_Oracle中utl_file包的使用
- Android异常之SIGABRT
- k-最近邻聚类k-Nearest Neighbor
- Java多位数字强可读性写法(数字中间添加下划线分开)
- Web开发基础_Servlet学习_0011_Servlet中的多线程安全问题与Servlet运行原理