搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7]
可能变为 [4,5,6,7,0,1,2]
)。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -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
题目分析:
首先看看二分查找,二分查找又称折半查找,是查找算法中比较常见的一种,它是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半。
示例代码:
public class S { public static int search(int[] nums, int target) { int left = 0; int right = nums.length - 1; if (nums.length == 0) return -1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] == target) return mid; else if (nums[mid] < target) left = mid + 1; else right = mid - 1; } return -1; } public static void main(String[] args) { int res = search(new int[]{1,2,3,4,5,6}, 4); System.out.println(res); } }
运行结果:
3
参照最基本的二分查找,看到数据结构是排序的数组,且目标是查找数据,则就会想到用二分查找,但是此题中的数组虽然是排序好的数组,但是它可能是按照某个点旋转过的,所以算法也需要有改进。
想到,既然数组是按照某点旋转过的,且数组升序排列,没有重复元素,那么旋转后的数组肯定分为两部分,数据大的与数据小的,这样就要分情况讨论:
以旋转数组[4,5,6,7,8,0,1,2,3]为例,前一段代表4,5,6,7,8,后一段代表0,1,2,3:
此时,根据target和nums[mid]的大小关系进行讨论
一、target > nums[mid],此时还需考虑nums[mid]和nums[0]的关系:
1.nums[mid] > nums[0],这种情况下
所以,要找到target,则left = mid + 1;
2.nums[mid] < nums[0],这种情况下又要分情况讨论target和nums[0]的关系:
(1).target < nums[0]
所以,要找到target,则left = mid + 1;
(2).target > nums[0]
所以,要找到target,则right = mid - 1;
二、target < nums[mid],此时也需考虑nums[mid]和nums[0]的关系::
1.nums[mid] < nums[0],这种情况下
所以,要找到target,则right = mid - 1;
2.nums[mid] > nums[0],这种情况下又要分情况讨论target和nums[0]的关系:
(1).target > nums[0]
所以,要找到target,则right = mid - 1;
(2).target < nums[0]
所以,要找到target,则left = mid + 1;
代码实现:
public int search(int[] nums, int target) { if (nums.length == 0) return -1; int left = 0; int right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[left] == target) return left; else if (nums[right] == target) return right; else if (nums[mid] == target) return mid; else { if (target > nums[mid]) { if (nums[mid] > nums[0]) left = mid + 1; else { if (target > nums[0]) right = mid - 1; else left = mid + 1; } } else { if (nums[mid] < nums[0]) right = mid - 1; else { if (target < nums[0]) left = mid + 1; else right = mid - 1; } } } } return -1; }
主函数:
public static void main(String[] args) { S1 s = new S1(); int res = s.search(new int[]{4, 5, 6, 7, 0, 1, 2}, 6); System.out.println(res); }
运行结果:
2