lintcode寻找旋转排序数组中的最小值/循环有序数组的查找

本文介绍了一种在旋转排序的循环有序数组中查找最小值的方法。通过使用改进的二分查找算法,可以在O(log n)的时间复杂度内找到数组中的最小元素。文章还提供了一段C++代码实现,展示了如何利用这种算法解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

循环有序数组

假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2)。

你需要找到其中最小的元素。

你可以假设数组中不存在重复的元素。

笔记

还是要用二分查找。再加一点细节处理。参考《剑指offer》

我们用两个指针分别指向数组的第一个元素和最后一个元素。按照题目中旋转的规则,第一个元素应该是大于或者等于最后一个元素的(这其实不完全对,还有特例,后面再加以讨论)

接着我们可以找到数组中间的元素。如果该中间元素位于前面的递增子数组,那么它应该大于或者等于第一个指针指向的元素。此时数组中最小的元素应该位于该中间元素的后面。我们可以把第一个指针指向该中间元素,这样可以缩小寻找的范围。移动之后的第一个指针仍然位于前面的递增子数组之中。

同样,如果中间元素位于后面的递增子数组,那么它应该小于或者等于第二个指针指向的元素。我们可以把第二个指针指向该中间元素。这样也可以缩小寻找的范围。移动之后的第二个指针仍然位于后面的递增子数组之中。

不管是移动第一个指针还是第二个指针,查找范围都会缩小到原来的一半。接下来我们再用更新之后的两个指针,重复做新一轮的查找。

代码

class Solution {
public:
    /**
     * @param num: a rotated sorted array
     * @return: the minimum number in the array
     */
    int findMin(vector<int> &num) {
        // write your code here
        int start = 0;
        int end = num.size() - 1;
        int res = 0;
        while (num[start] >= num[end])
        {
            if (start == end - 1)
            {
                res = end;
                break;
            }
            int mid = (start + end) / 2;
            if (num[start] == num[mid] && num[mid] == num[end])
            {
                int tmp = num[start];
                for (int i = start + 1; i <= end; i++)
                {
                    if (num[i] < tmp)
                        return num[i];
                }
            }
            if (num[mid] >= num[start])
                start = mid;
            if (num[mid] <= num[end])
                end = mid;
        }

        return num[res];
    }
};

相关题目

在循环有序数组中寻找某个数

代码

//
//  main.cpp
//  rotate_array
//
//  Created by SteveWong on 26/09/2016.
//  Copyright © 2016 SteveWong. All rights reserved.
//

#include <iostream>
#include <vector>
using namespace std;

int binsearch(vector<int> a, int tar, int lo, int hi)
{
    while (lo <= hi)
    {
        int mid = (lo + hi) / 2;
        if (a[mid] == tar)
        {
            return mid;
        }
        else if (a[mid] < tar)
        {
            lo = mid + 1;
        }
        else
        {
            hi = mid - 1;
        }
    }
    return -1;
}

int find(vector<int> a, int tar, int lo, int hi)
{
    while (a[lo] > a[hi])
    {
        int mid = (lo + hi) / 2;
        if (a[mid] == tar)
            return mid;
        if (a[lo] < a[mid])//前一半是正常有序,后一半是循环有序
        {
            if (a[lo] <= tar && tar < a[mid])//目标在前一半,可以直接二分
            {
                return binsearch(a, tar, lo, mid-1);
            }
            else//在后一半循环有序数组中查找
            {
                lo = mid + 1;
            }
        }
        else if (a[mid] < a[hi])//后一半正常有序,前一半循环有序
        {
            if (a[mid] < tar && tar <= a[hi])
            {
                return binsearch(a, tar, mid+1, hi);
            }
            else
            {
                hi = mid - 1;
            }
        }
    }
    //跳出循环,代表a[lo] < a[hi]
    return binsearch(a, tar, lo, hi);
}

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    vector<int> a = {4, 5, 6, 7, 1, 2, 3};
//    int tar = 2;
    cout << find(a, 2, 0, 6) << endl;
    cout << find(a, 3, 0, 6) << endl;
    cout << find(a, 4, 0, 6) << endl;
    cout << find(a, 5, 0, 6) << endl;
    cout << find(a, 6, 0, 6) << endl;
    cout << find(a, 7, 0, 6) << endl;
    cout << find(a, 1, 0, 6) << endl;
    cout << find(a, -8, 0, 6) << endl;
    cout << find(a, 9, 0, 6) << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值