《剑指Offer》面试题8:旋转数组的最小数字
1 快速排序
include <ctime> // ctime
#include <iostream>
using namespace std;
//生成low和high之间的随机数
int RandomInRange(int low,int high)
{
srand(time(NULL));
int rnum = rand() % (high - low + 1) + low;
return rnum;
}
int Partition(int data[], int length, int start, int end)
{
if (data == NULL || length <= 0 || start < 0 || end >= length)
throw new exception("Invalid Parameters");
int index = RandomInRange(start, end);
swap(data[index], data[end]);
int small = start - 1;
for (int index = start; index < end; ++index)
{
if (data[index] < data[end])
{
++small;
if (small!=index)
swap(data[index], data[small]);
}
}
++small;
swap(data[small], data[end]);
return small;
}
接下来,用递归实现快速排序。
void QuickSort(int data[], int length, int start, int end)
{
if (start == end)
return;
int index = Partition(data, length, start, end);
if (index>start)
QuickSort(data, length, start, index - 1);
if (index<end)
QuickSort(data, length, index+1, end);
}
int main()
{
int data[] = { 3, 8, 7, 1, 2, 5, 6, 4 };
int length = 8;
int start = 0;
int end = 7;
QuickSort(data, length, start, end);
for (int i = 0; i < length; i++)
{
cout << data[i];
}
system("pause");
return 0;
}
2 对公司年龄排序
#include <iostream>
using namespace std;
void SortAges(int ages[], int length)
{
if (ages == NULL || length <= 0)
return;
const int oldestAge = 99;
int timesOfAge[oldestAge + 1];
for (int i = 0; i <= oldestAge; i++)
timesOfAge[i] = 0;
for (int i = 0; i < length; i++)
{
int age = ages[i];
if (age<0 || age>oldestAge)
throw new exception("age out of range.");
++timesOfAge[age];
}
int index = 0;
for (int i = 0; i <= oldestAge; ++i)
{
for (int j = 0; j < timesOfAge[i]; j++)
{
ages[index] = i;
index++;
}
}
}
3 面试题8:旋转数组的最小数字
知识点
二分查找
题目描述
把一个数组的最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增数组的旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
解题思路
测试用例
代码(原书)
/* 《剑指Offer——名企面试官精讲典型编程题》代码
著作权所有者:何海涛 */
#include "stdio.h"
#include<exception>
int MinInOrder(int* numbers, int index1, int index2); //顺序查找函数声明
int Min(int* numbers, int length)
{
if (numbers == NULL || length <= 0)
throw new std::exception("Invalid parameters");
int index1 = 0;
int index2 = length - 1;
int indexMid = index1;
while (numbers[index1] >= numbers[index2])
{
// 如果index1和index2指向相邻的两个数,
// 则index1指向第一个递增子数组的最后一个数字,
// index2指向第二个子数组的第一个数字,也就是数组中的最小数字
if (index2 - index1 == 1)
{
indexMid = index2;
break;
}
// 如果下标为index1、index2和indexMid指向的三个数字相等,
// 则只能顺序查找
indexMid = (index1 + index2) / 2;
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];
}
//顺序查找函数
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;
}
// ====================测试代码====================
void Test(int* numbers, int length, int expected)
{
int result = 0;
try
{
result = Min(numbers, length);
for (int i = 0; i < length; ++i)
printf("%d ", numbers[i]);
if (result == expected)
printf("\tpassed\n");
else
printf("\tfailed\n");
}
catch (...)
{
if (numbers == NULL)
printf("Test passed.\n");
else
printf("Test failed.\n");
}
}
int main()
{
// 典型输入,单调升序的数组的一个旋转
int array1[] = { 3, 4, 5, 1, 2 };
Test(array1, sizeof(array1) / sizeof(int), 1);
// 有重复数字,并且重复的数字刚好的最小的数字
int array2[] = { 3, 4, 5, 1, 1, 2 };
Test(array2, sizeof(array2) / sizeof(int), 1);
// 有重复数字,但重复的数字不是第一个数字和最后一个数字
int array3[] = { 3, 4, 5, 1, 2, 2 };
Test(array3, sizeof(array3) / sizeof(int), 1);
// 有重复的数字,并且重复的数字刚好是第一个数字和最后一个数字
int array4[] = { 1, 0, 1, 1, 1 };
Test(array4, sizeof(array4) / sizeof(int), 0);
// 单调升序数组,旋转0个元素,也就是单调升序数组本身
int array5[] = { 1, 2, 3, 4, 5 };
Test(array5, sizeof(array5) / sizeof(int), 1);
// 数组中只有一个数字
int array6[] = { 2 };
Test(array6, sizeof(array6) / sizeof(int), 2);
// 输入NULL
Test(NULL, 0, 0);
system("pause");
return 0;
}
代码(牛客网)
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.empty()) //若数组大小为0,返回0
return 0;
int length = rotateArray.size();
int index1 = 0;
int index2 = length-1;
int indexMid = index1; //若将0个元素搬到末尾,即仍为原数组,此时数组的第一个数字即为最小数字,故将indexMid初始化为index1
while(rotateArray[index1] >= rotateArray[index2]) // 若旋转
{
if(index2 - index1 == 1) //分界点
{
indexMid = index2;
break;
}
indexMid = (index1 + index2)/2;
// rotateArray[index1] rotateArray[index2] rotateArray[indexMid]三者相等
// 无法确定中间元素是属于前面还是后面的递增子数组
// 只能顺序查找
if(rotateArray[index1] == rotateArray[index2] && rotateArray[index1] == rotateArray[indexMid])
{
// 顺序寻找最小值
int minNumber = rotateArray[index1];
for(int i = index1 + 1; i <= index2; i++)
{
if(minNumber > rotateArray[i])
minNumber = rotateArray[i];
}
indexMid = minNumber;
}
// 中间元素位于前面的递增子数组
// 此时最小元素位于中间元素的后面
if(rotateArray[indexMid] >= rotateArray[index1])
index1 = indexMid;
// 中间元素位于后面的递增子数组
// 此时最小元素位于中间元素的前面
if(rotateArray[indexMid] <= rotateArray[index2])
index2 = indexMid;
}
return rotateArray[indexMid];
}
};