面试题8:旋转数组的最小数字

本文介绍了一种高效算法用于查找旋转数组中的最小元素,通过分析数组特性,优化搜索过程,实现时间复杂度O(log n),适用于面试和算法优化场景。

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

题目描述:Online Judge

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

输入:

输入可能包含多个测试样例,对于每个测试案例,

输入的第一行为一个整数n(1<= n<=1000000):代表旋转数组的元素个数。

输入的第二行包括n个整数,其中每个整数a的范围是(1<=a<=10000000)。

输出:

对应每个测试案例,

输出旋转数组中最小的元素。

样例输入:
53 4 5 1 2
样例输出:
1

问题分析:

        1)常规的思路是从头到尾扫描一遍数组,然后得到最小值,这种思想的时间复杂度显然是O(n),但是这种思路达不到面试官的要求。                                                    

        2)数组前和尾分别设置一个指针,然后采用类似快速排序的方法得到解。其中要注意的有数组中可能存在最小值重复的情况。


java代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;


public class Problem_08 {
	
	public static void main(String[] args) throws IOException {
		BufferedReader bu= new BufferedReader( new InputStreamReader(System.in));
		StreamTokenizer str = new StreamTokenizer(bu);
		while(str.nextToken() != StreamTokenizer.TT_EOF){
			int n = (int)str.nval;
			int [] array = new int[n];
			for(int i = 0; i < n; i++){
				str.nextToken();
				array[i] = (int) str.nval;
			}// end for 
			System.out.println(findMin(array));			
		}//end while
	}//end main
	
	public static int findMin(int[] array){
		if(array.length == 0){
			return 0;
		}//end if 
		int start = 0;
		int end = array.length - 1;
		int mid = start;
		while(array[start] >= array[end]){
			if(end - start == 1){
				mid = end;
				break;
			}
			mid = (start + end )/2;		
			
			if( array[start] == array[end] && array[start] == array[mid] ){
				return minOrder(array,start,end);
			}//end if
			
			if(array[start] <= array[mid]){
				start = mid;				
			}else if (array[end] >= array[mid]){
				end = mid;
			}//end if
		}//end while
		return array[mid];
	}//end findMin
	
	public static int minOrder(int[] array, int start, int end){
		int result = array[start];
		for(int i = start + 1; i <=  end; i++){
			if(result > array[i]){
				result = array[i];
			}
		}//end for
		return result;
	}//end minOrder
}


C++代码:

#include "iostream"
#include "cstdio"
using namespace std;
 
int MinInOrder(int *a, int low, int high)
{
    int re = a[low];
    for(int i = low + 1; i <= high; ++i)
        if(re > a[i]) re = a[i];
    return re;
}
 
int MinSearch(int A[], int low, int high)
{
    int mid;
    mid = (low + high) / 2;
    if(A[low] <= A[mid] && A[mid] <= A[high]) mid = low;
    while(A[low] >= A[high])
    {
        if(high - low == 1) 
        {
            mid = high;
            break;
        }
        mid = (low + high) / 2;
        if(A[low] == A[mid] && A[mid] == A[high])
        {
            return MinInOrder(A, low, high);
        }
        if(A[mid] >= A[low]) low = mid;
        else if(A[mid] <= A[high]) high = mid;
    }
    return A[mid];
}
 
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int *a = new int[n];
        for(int i = 0; i < n; ++i)
            scanf("%d",&a[i]);
        int r = MinSearch(a, 0, n - 1);
        printf("%d\n",r);
        delete []a;
        a = NULL;
    }
    return 0;
}

C代码:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
        int left, right, mid, i, n, min, arr[1000001];
 
        while (scanf("%d", &n) != EOF) {
                for (i = 0; i < n; i ++)
                        scanf("%d", &arr[i]);
 
                left = 0;
                right = n - 1;
                mid = left;
 
                while (arr[left] >= arr[right]) {
                        if (left + 1 == right) {
                                mid = right;
                                break;
                        }
 
                        mid = (left + right) / 2;
 
                        // 特例情况
                        if (arr[left] == arr[mid] && arr[mid] == arr[right]) {
                                // 顺序查找
                                for (i = left + 1, min = arr[left]; i <= right; i ++) {
                                        if (arr[i] < min) {
                                                min = arr[i];
                                                mid = i;
                                        }
                                }
                                break;
                        }
 
                        if (arr[mid] >= arr[left]) {
                                left = mid;
                        } else if (arr[mid] <= arr[right]) {
                                right = mid;
                        }
                }
 
                printf("%d\n", arr[mid]);
        }
        return 0;
}

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

体会:
本题类似于快速排序的一次排序。


                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值