-
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{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)特殊数组测试(空指针输入)
体会:本题类似于快速排序的一次排序。
题目描述:Online Judge