开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
引言
算法的技能对于程序员是百益而无一害,作为程序员无论是前端还是后端算法技能对于我们都是十分十分的重要,我将陆续整理并讲解前端程序员必须掌握的经典算法。
题目描述
整数数组 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
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
示例 3:
输入: nums = [1], target = 0
输出: -1
提示:
1 <= nums.length <= 5000-104 <= nums[i] <= 104nums中的每个值都 独一无二- 题目数据保证
nums在预先未知的某个下标上进行了旋转 -104 <= target <= 104
分析
先找到 「153. 寻找旋转排序数组中的最小值」的索引,由此可以将数组分为升序的两段。 根据 nums[0] 与 target 的关系判断 target 在左段还是右段,再对升序数组进行二分查找即可。 同样的思路可以解决「1095. 山脉数组中查找目标值」,即先找到山脉数组的峰顶「852. 山脉数组的峰顶索引」, 通过峰顶将山脉数组分为两段有序的数组,接下来就可以在有序数组中查找目标值了。
解答
public int search(int[] nums, int target) { int lo = 0, hi = nums.length - 1, mid = 0; while (lo <= hi) { mid = lo + (hi - lo) / 2; if (nums[mid] == target) { return mid; } // 先根据 nums[mid] 与 nums[lo] 的关系判断 mid 是在左段还是右段 if (nums[mid] >= nums[lo]) { // 再判断 target 是在 mid 的左边还是右边,从而调整左右边界 lo 和 hi if (target >= nums[lo] && target < nums[mid]) { hi = mid - 1; } else { lo = mid + 1; } } else { if (target > nums[mid] && target <= nums[hi]) { lo = mid + 1; } else { hi = mid - 1; } } } return -1; }
总结
上面的算法思路让我学到了许多知识啊