旋转数组的最小值

发布于:2023-10-25 ⋅ 阅读:(107) ⋅ 点赞:(0)

1 题目

将一个数组最开始的若干元素搬到数组的末尾,称之为数组的旋转。输入一个已排好序数组的一个旋转,求该旋转数组的最小元素。如,数组{3,4,,5,1,2}为有序数组{1,2,3,4,5}的一个旋转数组,该数组的最小值为1。

2 思路

2.1 思路1

暴力遍历数组,求出数组的最小元素。

时间复杂度:O(n)
空间复杂度:O(1)

2.2 思路2

将旋转后的数组看成两个升序的子序列,即查找一个元素(使用二分查找法),满足的条件为比相邻左边的元素小,也比相邻右边的元素小(如果存在的话)。

算法1详细(方便理解):

  • 用l指针指向第一个序列的第一个元素,用r指针指向第二个序列的最后一个元素;
    • 当l = mid时,r为最小元素(特殊处理当最小元素位于末尾的情况),例如{2,3,4,5,1},此时最小元素为r指向的元素,而不是mid指向的元素;
    • 当元素满足比左边元素小,比右边元素小时,即为最小元素;
    • 如果中间指针mid((l+r)/2)在第一个序列中(即A[mid] < A[l]),则要寻找的元素在后半段中,把l改为mid;
    • 如果中间指针mid第二个序列中(即A[mid]<A[r]),则要寻找的元素在前半中;
  • 当l=r时,返回最小元素A[r];否则,返回最小元素A[mid]。

算法2详细(上一种算法的改进版本):

  • 用l指针指向第一个序列的第一个元素,用r指针指向第二个序列的最后一个元素;
    • 如果中间指针mid((l+r)/2)在第一个序列中(即A[mid] < A[l]),则要寻找的元素在后半段中,把l改为mid;
    • 如果中间指针mid第二个序列中(即A[mid]<A[r]),则要寻找的元素在前半中。
  • 当l和r相邻时(此时mid=l),最小元素在r指向的元素。

时间复杂度:O(logn)
空间复杂度:O(1)

在这里插入图片描述

例如:原数组{1,2,3,4,5},
旋转后的数组{2,3,4,5,1},1比左边的5小,无右边的元素;
旋转后的数组{3,4,5,1,2},1比左边的5小,比右边2小;
旋转后的数组{4,5,1,2,3},1比左边的5小,比右边2小。

3 实现

3.1 暴力

#include<cstdio>

int solution(int *A, int n){
    int ans = A[0];
    for(int i = 1;i < n;i++)
        if(A[i] < ans) ans = A[i];
    return ans;
}

int main(){
    
    int A[] = {2,3,4,5,1};
    //int A[] = {3,4,5,1,2};
    //int A[] = {4,5,1,2,3};
    //int A[] = {5,1,2,3,4};
    
    printf("%d", solution(A, sizeof(A)/sizeof(A[0])));
    return 0;
}

3.2 二分查找

#include<cstdio>

int solution(int *A, int n){
    int l = 0, r = n - 1, mid;
    while(l <= r){
        mid = (l + r)/2;
        printf("值   %d %d %d \n", A[l], A[mid], A[r]);
        printf("序号 %d %d %d \n", l, mid, r);
        
        //特殊处理最小元素位于最后一个的情况,例如2,3,4,5,1的情况,此时mid=l=3,r=4
        if(l == mid && A[r] < A[mid]) break;
        
        //如果比左边相邻的元素小
        //同时也比右边相邻的元素小(如果右边元素不存在,则和自己比较)
        if((A[mid] < A[mid-1] && A[mid] <= A[mid+1])
        ) break;
        
        if(A[mid] < A[r]) r = mid;
        else l = mid;
    }
    return (l == mid)?A[mid+1]:A[mid];
}

int solution2(int *A, int n){
    int l = 0, r = n - 1, mid;
    while(A[l] >= A[r]){
        if(r -l ==1){
            mid = r;
            break;
        }
        mid = (l + r)/2;
        printf("值   %d %d %d \n", A[l], A[mid], A[r]);
        printf("序号 %d %d %d \n", l, mid, r);
        
        if(A[mid] < A[r]) r = mid;
        else l = mid;
    }
    return A[mid];
}

int main(){
    
    int A[] = {2,3,4,5,1};
    //int A[] = {3,4,5,1,2};
    //int A[] = {4,5,1,2,3};
    //int A[] = {5,1,2,3,4};
    
    printf("%d", solution(A, sizeof(A)/sizeof(A[0])));
    return 0;
}

网站公告

今日签到

点亮在社区的每一天
去签到