8、旋转数组中最小数字

本文介绍了一种在旋转数组中查找最小元素的高效算法。通过使用二分查找法,可以在O(logn)的时间复杂度内找到旋转数组中的最小值。文章详细解释了不同情况下指针移动的逻辑,并提供了完整的C++代码实现及测试用例。

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

  题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。

  思路:设两个指针p1,p2,p1指向首元素,p2指向最尾,让p1一直在前面递增的数组中,p2在后面递增的数组中。然后查找中间数,与首元素和尾元素进行比较。有如下几种情况:

  1.中间数 > 首元素。[3,4,5,1,2],p1指3,p2指2,中间数指5,5大于3,所以最小数肯定在5后面,且5位于前面这个递增数组中,所以移动p1指向5。

  2.中间数 < 首元素。然后5和2的中间数为1,1小于2,所以1在后面的递增数组中,所以移动p2到1。此时p1和p2距离1,所以p1指向第一个递增数组的末尾,p2指向第二个递增数组的开头,,所以p2指的为该数组的最小值。

  3.尾元素 > 首元素。这该数组一定为递增数组,无须变动,直接返回第一个元素。

  4.首元素 = 尾元素 = 中间元素。此时应用顺序查找。

  测试用例
  1.功能测试(输入的数组是升序排序数组的一个旋转,数组中有重复数字或者没有重复数字)。
  2.边界值测试(输入的数组是一个升序排序的数组、只包含一个数字的数组)。
  3.特殊输入册数(输入NULL指针)。

  时间复杂度:顺序查找:O(n),二分法查找:O(logn)。

  代码

#include<iostream>
using namespace std;

int MinInOrder(int* numbers, int index1, int index2)
{
    int result = numbers[index1];
    for (int i = index1 + 1; i <= index2; ++i)
    {
        if (result > numbers[i])
        {
            result = numbers[i];
        }
    }

    return result;
}


int Min(int* numbers, int length)
{
    if (numbers == NULL || length <= 0)
    {
        cout << "无效输入" << endl;
        return 0;
    }

    int index1 = 0;
    int index2 = length - 1;
    int indexMid = index1;  //indexMid为最小值
    while (numbers[index1] >= numbers[index2])
    {
        if (index2 - index1 == 1)
        {
            indexMid = index2;
            break;
        }

        indexMid = (index1 + index2) / 2;

        //如果下标为index1、index2和indexMid指向的三个数字相等,则顺序查找
        if (numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])
        {
            return MinInOrder(numbers, index1, index2);
        }

        if (numbers[indexMid] >= numbers[index1])
        {
            index1 = indexMid;
        }
        else if (numbers[indexMid] <= numbers[index2])
        {
            index2 = indexMid;
        }
    }

    return numbers[indexMid];
}

//测试
void test1()
{
    int a[5] = {3,4,5,1,2};
    int min = Min((int*)a, 5);
    if (min == 1)
    {
        cout << "passed!" << endl;
    }
    else
    {
        cout << "failed!" << endl;
    }
}

void test2()
{
    int a[5] = {1,2,3,4,5};
    int min = Min((int*)a, 5);
    if (min == 1)
    {
        cout << "passed!" << endl;
    }
    else
    {
        cout << "failed!" << endl;
    }
}

void test3()
{
    int a[1] = {1};
    int min = Min((int*)a, 1);
    if (min == 1)
    {
        cout << "passed!" << endl;
    }
    else
    {
        cout << "failed!" << endl;
    }
}

void test4()
{

    int min = Min(NULL, 1);

}

int main()
{
    test1();
    test2();
    test3();
    test4();

    return 0;
}

 

转载于:https://my.oschina.net/134596/blog/1793300

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值