leetcode
leetcode 2801 ~ 2850
搜索旋转数组

搜索旋转数组

难度:

标签:

题目描述

Given a sorted array of n integers that has been rotated an unknown number of times, write code to find an element in the array. You may assume that the array was originally sorted in increasing order. If there are more than one target elements in the array, return the smallest index.

Example1:

 Input: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
 Output: 8 (the index of 5 in the array)

Example2:

 Input: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 11
 Output: -1 (not found)

Note:

  1. 1 <= arr.length <= 1000000

代码结果

运行时间: 23 ms, 内存: 17.0 MB



/**
 * 使用 Java Stream 查找旋转数组中的某个元素。
 * 思路:
 * 1. 利用流操作来查找目标元素的索引。
 * 2. 使用IntStream.range来生成索引范围并在流中查找目标值。
 */
import java.util.stream.IntStream;

public class SolutionStream {
    public int search(int[] nums, int target) {
        return IntStream.range(0, nums.length)
                .filter(i -> nums[i] == target)
                .findFirst()
                .orElse(-1);
    }
}

解释

方法:

这道题涉及到在一个部分旋转的有序数组中寻找一个特定的元素。解题关键在于如何有效利用数组的部分有序特性来减少搜索范围。首先,通过比较数组首尾元素实现区间的切分。算法首先检查当前左边界元素是否是目标元素,如果是则直接返回。接着,计算中间索引,并检查中间元素是否为目标,如果是则更新右边界为中间,以缩小搜索范围并可能找到最小索引。然后,算法检查左半部分是否有序(即左端元素小于等于右端元素)。根据有序部分的情况,决定是向左还是向右继续搜索,从而不断缩小查找范围。通过这种方式,算法能够在对数时间内找到目标元素或确定其不存在。

时间复杂度:

O(log n) in best case, O(n) in worst case

空间复杂度:

O(1)

代码细节讲解

🦆
在算法中,为什么在检测到`arr[left] == target`时可以直接返回left而不继续查找可能存在的更小索引值?
在此算法中,一旦发现`arr[left] == target`,就可以直接返回`left`,因为算法每次循环都会从左边界开始检查,且左边界逐步右移。因此,当遇到`arr[left] == target`时,即意味着在当前搜索范围内,`left`已经是目标值的最小可能索引。继续搜索将不会找到一个更小的索引,因为左边界的更新已经排除了所有之前的元素。
🦆
在`arr[left] == arr[right]`的情况下,为什么选择通过`left += 1`来缩小范围,这样做有哪些潜在的风险?
当`arr[left] == arr[right]`时,意味着无法确定目标值位于左侧还是右侧,因为两端的值相同时,中间的值也可能相同,从而使得无法判断哪一部分是有序的。通过递增`left`索引,算法试图去掉一个潜在的重复元素,以希望破坏重复性,找到非重复区间以继续二分查找。潜在的风险是,如果目标值恰好在这些被逐步排除的重复元素中的位置,这种方式可能会错过目标值。
🦆
算法中提到,如果中间元素满足目标值,则将右边界更新为中间(`right = mid`),这种做法是否保证了在数组中找到的目标索引是最小的?
将右边界更新为`mid`是为了尝试在数组中找到目标值的最小索引。这种方法基于二分查找逻辑减少搜索范围,同时保持目标值在新的搜索范围内。这种做法确实有助于逐步缩小范围到最左端的目标值。然而,仅当循环每次都检查`left`端的值,并且左端索引在每次循环中都适当更新时,这种方法才保证找到最小索引。如果存在其他路径可能错过最左端的目标值(如不恰当的跳过某些检查),则这种保证不再成立。

相关问题