返回

破解难题的钥匙:剖析leetcode剑指 Offer 11-旋转数组的最小数字

前端

巧用二分查找,破解旋转数组最小数字之谜

各位算法爱好者们,欢迎来到我们今天的算法探索之旅,我们将共同踏上攻克 LeetCode 剑指 Offer 11-旋转数组的最小数字这一难题的征途。这道题看似平平无奇,但它暗藏玄机,是检验算法思维和代码实现能力的一块试金石。

旋转数组的奥秘

旋转数组的奥秘在于,当我们把一个数组的若干个元素从开头搬到末尾时,数组中的元素顺序会发生变化。例如,对于数组 [1, 3, 5, 1, 1, 1],如果我们把最开始的两个元素搬到末尾,就会得到 [1, 1, 1, 1, 3, 5]。

寻找最小数字的挑战

直觉告诉我们,找到旋转后数组的最小数字,应该可以像普通数组一样,直接遍历一遍,找出最小的那个元素。然而,当数组中存在重复元素时,这种方法就失效了。

以刚才的例子为例,如果我们直接遍历,就会找到最小的数字 1,但实际上这并不是旋转后数组的最小数字。真正的最小数字是 3。

二分查找闪亮登场

面对这一挑战,我们需要祭出二分查找这把算法利器。二分查找是一种极其高效的搜索算法,它的奥秘在于,它可以将搜索空间一分为二,不断缩小范围,直至找到目标元素。

二分查找算法步骤

下面就让我们来一步步剖析二分查找算法的步骤:

  1. 首先,我们将数组的左右边界分别设为 0 和数组长度减一。
  2. 接下来,计算出数组的中间索引。
  3. 然后,比较中间索引处的元素和右边界处的元素。
  4. 如果中间索引处的元素小于或等于右边界处的元素,那么最小数字一定在中间索引的左边,我们将右边界更新为中间索引减一。
  5. 否则,最小数字一定在中间索引的右边,我们将左边界更新为中间索引加一。
  6. 重复步骤 2 到 5,直到左边界大于或等于右边界。
  7. 最后,返回左边界处的元素,即旋转后数组的最小数字。

代码实现

知道了算法步骤,我们就可以将其转化为代码了。以下是用 Java 编写的代码示例:

public int findMin(int[] nums) {
    int left = 0;
    int right = nums.length - 1;

    while (left < right) {
        int mid = (left + right) / 2;
        if (nums[mid] <= nums[right]) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }

    return nums[left];
}

这段代码首先将数组的左右边界设置为 0 和数组长度减一。然后,它不断地计算数组的中间索引,比较中间索引处的元素和右边界处的元素,并根据比较结果更新左右边界。当左边界大于或等于右边界时,循环结束。最后,返回左边界处的元素,即旋转后数组的最小数字。

总结

通过这篇文章,我们深入了解了二分查找算法,并将其应用于 LeetCode 剑指 Offer 11-旋转数组的最小数字这道难题中。希望通过这篇讲解,你已经掌握了二分查找的精髓,并能够将其运用到更多的算法问题中。

常见问题解答

为了进一步巩固你的理解,这里有 5 个常见问题及其解答:

1. 什么情况下使用二分查找最有效?
当搜索空间很大且是有序时,使用二分查找最为有效。

2. 如果数组中有重复元素,二分查找还能正常工作吗?
是的,二分查找仍然可以正常工作,但它只能找到重复元素中最小或最大的一个。

3. 二分查找的平均时间复杂度是多少?
O(log n),其中 n 是数组的长度。

4. 如何确定二分查找算法何时终止?
当左边界大于或等于右边界时,二分查找算法终止。

5. 二分查找有哪些应用场景?
二分查找广泛用于各种应用中,例如查找元素、确定元素的存在、求解最大值或最小值问题等。