c_cpp 在已旋转未知次数的n个整数的递增顺序排序数组中查找元素。 #searching #CtCI
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp 在已旋转未知次数的n个整数的递增顺序排序数组中查找元素。 #searching #CtCI相关的知识,希望对你有一定的参考价值。
#include <cassert>
#include <iostream>
// Utilities
// ============================================================================
#define SIZE_OF_ARRAY(x) (sizeof(x)/sizeof(x[0]))
void printArray(int a[], int length) {
for (int i = 0 ; i < length ; ++i) {
std::cout << a[i] << " ";
}
std::cout << std::endl;
}
void shiftArray(int a[], int length) {
int last = a[length - 1];
for (int i = length - 1 ; i > 0 ; --i) {
a[i] = a[i-1];
}
a[0] = last;
}
// Binary search in a rotated sorted array
// ============================================================================
// The following algorithm fails when 2 2 2 2 3 4 2 or 2 3 4 2 2 2 2
// int findMaxIndex(int a[], int length)
// {
// int left = 0;
// int right = length - 1;
// int middle = -1;
// // Find the index of the 'last' max item.
// while (left <= right) {
// int middle = (left + right) / 2;
// // Check if a[middle] is the last max item.
// if (a[middle] > a[middle + 1]) { // a[middle] is the last max
// return middle;
// }
// // Otherwise, keep searching the last max item.
// if (a[middle] <= a[right]) { // middle to right is sorted,
// if (a[left] <= a[middle]) { // left to middle is sorted
// // left to right is sorted!
// assert(right == length - 1 || a[right] > a[right + 1]);
// return right;
// }
// // left to middle is unsorted, so the max item is in left side!
// assert(a[left] >= a[right]); // Make sure the max item is in left side.
// right = middle - 1;
// } else { // a[middle] > a[right] implies the max item is in right side!
// // assert(a[left] <= a[middle]); // Check the left side is sorted.
// left = middle + 1;
// }
// }
// return -1;
// }
int findMaxIndex(int a[], int length, int left, int right)
{
assert(left >= 0 && right < length);
if (left > right) {
return -1;
}
int middle = (left + right) / 2;
if (a[middle] > a[middle + 1]) { // the middle is the last max item!
return middle;
}
if (a[middle] < a[right]) { // middle to right is strictly sorted.
if (a[left] <= a[middle]) { // left to middle is sorted.
// then the max item must be in the rightmost!
return right;
}
// the max item must be in left side since the left to middle is unsorted.
return findMaxIndex(a, length, left, middle - 1);
}
if (a[middle] > a[right]) { // middle to right is unsorted,
// so left to middle must be sorted. Find the max item in the right side.
return findMaxIndex(a, length, middle + 1, right);
}
// when a[middle] == a[right]:
// if a[middle] != a[left] only left side are different.
// There are two possibilities: 3 4 5 2 2 2 2 or 3 4 5 6 6 6 6
if (a[middle] > a[left]) { // 3 4 5 6 6 6 6
// then the max item must be in the rightmost!
return right;
}
if (a[middle] < a[left]) { // 3 4 5 2 2 2 2
return findMaxIndex(a, length, left, middle - 1);
}
// if a[middle] == a[left]: the max item can be in both side
// (e.g., 2 2 2 2 3 4 2 or 2 3 4 2 2 2 2).
int index = findMaxIndex(a, length, left, middle - 1); // Find in left first.
if (index != -1) { // if the max item is in left, return it directly.
return index;
}
// find the max item in the right side if it's not in the left side.
return findMaxIndex(a, length, middle + 1, right);
}
int findOffset(int a[], int length)
{
// int index = findMaxIndex(a, length);
int index = findMaxIndex(a, length, 0, length - 1);
return (index + 1) % length;
}
int rotatedIndex(int index, int offset, int length)
{
return (index + offset) % length;
}
int binarySearch(int a[], int length, int offset, int target)
{
int left = 0;
int right = length - 1;
int middle = -1;
while(left <= right) {
int middle = (left + right) / 2;
int rotatedMid = rotatedIndex(middle, offset, length);
if(a[rotatedMid] == target) {
return rotatedMid;
}
if (a[rotatedMid] < target) {
left = middle + 1; // Search right
} else {
right = middle - 1; // Search left
}
}
return -1;
}
// Actually, we could apply the idea from recursive findMaxIndex
// to search the target directly.
int binarySearch(int a[], int length, int left, int right, int target)
{
assert(left >= 0 && right < length);
if (left > right) {
return -1;
}
int middle = (left + right) / 2;
if (a[middle] == target) {
return middle;
}
// when the middle is not the target:
if (a[middle] < a[right]) { // middle to right is strictly sorted.
// if middle < target <=right, then search it on right side.
if (a[middle] < target && target <= a[right]) {
return binarySearch(a, length, middle + 1, right, target);
}
// search target on left side.
return binarySearch(a, length, left, middle - 1, target);
}
if (a[middle] > a[right]) { // middle to right is unsorted,
// so left to middle must be sorted.
// if left <= target < middle, then search it on left side.
if (a[left] <= target && target < a[middle]) {
return binarySearch(a, length, left, middle - 1, target);
}
// search it on right side.
return binarySearch(a, length, middle + 1, right, target);
}
// if a[middle] == a[right]:
if (a[middle] != a[left]) { // if the values change between middle to right,
// then the left must be same as middle.
// Thus, if left is different from middle, all the values from middle to
// right must be same. Only left side have differences, so search on left
// side.(the middle is different from target, so all the same values from
// middle to right are also different from target.)
return binarySearch(a, length, left, middle - 1, target);
}
// if a[left] == a[middle] == a[right]: 2 3 4 2 2 2 2 or 2 2 2 2 3 4 2.
// The target may be in both side.
// Search on left side first.
int index = binarySearch(a, length, left, middle - 1, target);
if (index != -1) { // if target is found on left side, return it directly.
return index;
}
return binarySearch(a, length, middle + 1, right, target);
}
int binarySearch(int a[], int length, int target)
{
// int offset = findOffset(a, length);
// return binarySearch(a, length, offset, target);
return binarySearch(a, length, 0, length - 1, target);
}
int binarySearch(int a[], int length, int target)
{
return binarySearch(a, length, 0, length - 1, target);
}
// Test
// ============================================================================
bool sorted(int a[], int length)
{
for (int i = 0 ; i < length-1 ; ++i) {
if (a[i] > a[i+1]) {
return false;
}
}
return true;
}
int* allocateTable(int a[], int length)
{
int min = a[0] - 1;
int max = a[length - 1] + 1;
int len = max - min + 1;
if (!length) {
return nullptr;
}
int* table = new int[len];
for (int i = 0 ; i < len ; ++i) {
table[i] = -1;
}
for (int i = 0 ; i < length ; ++i) {
table[a[i] - min] = i;
}
return table;
}
void test(int a[], int length)
{
assert(length);
assert(sorted(a, length));
int min = a[0];
int max = a[length - 1];
int rotateTimes = length;
if (min == max) {
// if all the array elements are same,
// then we only need to test once!
rotateTimes = 1;
}
int* table = allocateTable(a, length);
assert(table);
min = min - 1;
max = max + 1;
int len = max - min + 1;
for (int shift = 0 ; shift < rotateTimes ; ++shift) {
std::cout << "offset: " << shift << std::endl;
printArray(a, length);
// Check findOffset
assert(findOffset(a, length) == shift);
// Check binarySearch
for(int target = min ; target <= max ; ++target) {
int index = binarySearch(a, length, target);
int answer = table[target - min];
std::cout << "find " << target << " at " << index << " (expect found: "
<< ((answer != -1) ? "Yes" : "No") << std::endl;
assert((index == -1) == (answer == -1));
}
shiftArray(a, length);
}
delete[] table;
}
// Main Program
// ============================================================================
int main()
{
int a1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
test(a1, SIZE_OF_ARRAY(a1));
int a2[] = { 3, 3, 3, 6, 7, 7, 7, 11, 12, 15, 15 };
test(a2, SIZE_OF_ARRAY(a2));
int a3[] = { -5, -2, -2, -2, 4, 4, 4, 4, 10, 10, 10, 13, 13, 14 };
test(a3, SIZE_OF_ARRAY(a3));
int a4[] = { 7, 7, 7, 7, 7 };
test(a4, SIZE_OF_ARRAY(a4));
int a5[] = { 2, 2, 2, 2, 2, 3, 4 };
test(a5, SIZE_OF_ARRAY(a5));
int a6[] = { 2, 3, 4, 4, 4, 4, 4 };
test(a6, SIZE_OF_ARRAY(a6));
return 0;
}
以上是关于c_cpp 在已旋转未知次数的n个整数的递增顺序排序数组中查找元素。 #searching #CtCI的主要内容,如果未能解决你的问题,请参考以下文章
c_cpp 有一个长度为n个(n <= 100)的数列,该数列定义为从2开始的递增有序偶数(公差为2的等差数列),现在要求你按照顺序每米个数求出一个平均值,如果最后不足m个,则以实际数量求平均值
写一个函数,使N个整数按由小到大的顺序排列,要求在主函数中输入10个数,并输出排好序的数