剑指offer——面试题11:旋转数组的最小数字
1 #include"iostream" 2 using namespace std; 3 4 int GetMinNumber(int *data,int len) 5 { 6 int left=0,right=len-1,mid; 7 8 while(left<right-1) 9 { 10 mid=(left+right)/2; 11 if(data[mid]>=data[left]) 12 left=mid; 13 else if(data[mid]<data[right]) 14 right=mid; 15 } 16 return data[right]; 17 } 18 19 void Test1() 20 { 21 cout<<"Test1:"; 22 int data[]={3,4,5,1,2}; 23 if(GetMinNumber(data,5)==1) 24 cout<<"passed."<<endl; 25 else 26 cout<<"failed."<<endl; 27 } 28 29 void Test2() 30 { 31 cout<<"Test2:"; 32 int data[]={3,4,5,6,1,2}; 33 if(GetMinNumber(data,6)==1) 34 cout<<"passed."<<endl; 35 else 36 cout<<"failed."<<endl; 37 } 38 39 void Test3() 40 { 41 cout<<"Test3:"; 42 int data[]={2,1}; 43 if(GetMinNumber(data,2)==1) 44 cout<<"passed."<<endl; 45 else 46 cout<<"failed."<<endl; 47 } 48 49 int main() 50 { 51 Test1(); 52 Test2(); 53 Test3(); 54 return 0; 55 }
官方答案:
1 // 面试题11:旋转数组的最小数字 2 // 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 3 // 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组 4 // {3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。 5 6 #include <cstdio> 7 #include <exception> 8 9 int MinInOrder(int* numbers, int index1, int index2); 10 11 int Min(int* numbers, int length) 12 { 13 if(numbers == nullptr || length <= 0) 14 throw new std::exception("Invalid parameters"); 15 16 int index1 = 0; 17 int index2 = length - 1; 18 int indexMid = index1; 19 while(numbers[index1] >= numbers[index2]) 20 { 21 // 如果index1和index2指向相邻的两个数, 22 // 则index1指向第一个递增子数组的最后一个数字, 23 // index2指向第二个子数组的第一个数字,也就是数组中的最小数字 24 if(index2 - index1 == 1) 25 { 26 indexMid = index2; 27 break; 28 } 29 30 // 如果下标为index1、index2和indexMid指向的三个数字相等, 31 // 则只能顺序查找 32 indexMid = (index1 + index2) / 2; 33 if(numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1]) 34 return MinInOrder(numbers, index1, index2); 35 36 // 缩小查找范围 37 if(numbers[indexMid] >= numbers[index1]) 38 index1 = indexMid; 39 else if(numbers[indexMid] <= numbers[index2]) 40 index2 = indexMid; 41 } 42 43 return numbers[indexMid]; 44 } 45 46 int MinInOrder(int* numbers, int index1, int index2) 47 { 48 int result = numbers[index1]; 49 for(int i = index1 + 1; i <= index2; ++i) 50 { 51 if(result > numbers[i]) 52 result = numbers[i]; 53 } 54 55 return result; 56 } 57 58 // ====================测试代码==================== 59 void Test(int* numbers, int length, int expected) 60 { 61 int result = 0; 62 try 63 { 64 result = Min(numbers, length); 65 66 for(int i = 0; i < length; ++i) 67 printf("%d ", numbers[i]); 68 69 if(result == expected) 70 printf("\tpassed\n"); 71 else 72 printf("\tfailed\n"); 73 } 74 catch (...) 75 { 76 if(numbers == nullptr) 77 printf("Test passed.\n"); 78 else 79 printf("Test failed.\n"); 80 } 81 } 82 83 int main(int argc, char* argv[]) 84 { 85 // 典型输入,单调升序的数组的一个旋转 86 int array1[] = { 3, 4, 5, 1, 2 }; 87 Test(array1, sizeof(array1) / sizeof(int), 1); 88 89 // 有重复数字,并且重复的数字刚好的最小的数字 90 int array2[] = { 3, 4, 5, 1, 1, 2 }; 91 Test(array2, sizeof(array2) / sizeof(int), 1); 92 93 // 有重复数字,但重复的数字不是第一个数字和最后一个数字 94 int array3[] = { 3, 4, 5, 1, 2, 2 }; 95 Test(array3, sizeof(array3) / sizeof(int), 1); 96 97 // 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字 98 int array4[] = { 1, 0, 1, 1, 1 }; 99 Test(array4, sizeof(array4) / sizeof(int), 0); 100 101 // 单调升序数组,旋转0个元素,也就是单调升序数组本身 102 int array5[] = { 1, 2, 3, 4, 5 }; 103 Test(array5, sizeof(array5) / sizeof(int), 1); 104 105 // 数组中只有一个数字 106 int array6[] = { 2 }; 107 Test(array6, sizeof(array6) / sizeof(int), 2); 108 109 // 输入nullptr 110 Test(nullptr, 0, 0); 111 112 return 0; 113 }
与官方答案相比较,我少考虑了很多种特殊情况,相差甚远。