劍指offer(面試題39):陣列中出現次數超過陣列長度一半的數字
阿新 • • 發佈:2019-01-28
方法1:
從數學角度看,所求的數一定的原陣列(有序化)的中位數,那麼,我們可以通過對陣列排序,這樣得到的時間複雜度是。而如果能夠優化到在的時間內找到,就更好了。基於快速排序的partition階段,如果我們可以通過這一方法找到陣列的中位數,那麼時間複雜度顯然是的。
#include<iostream>
#include<stdlib.h>
using namespace std;
//產生區間內的隨機整數
int randomInRange(int start, int end) {
return rand() % (end - start + 1) + start;
}
void swap(int& n1, int& n2) {
int tmp = n1;
n1 = n2;
n2 = tmp;
}
//快速排序的partition
int partition(int* numbers, int length, int start, int end) {
if(numbers == NULL || length <= 0 || start < 0 || end >= length)
return -1;
int index = randomInRange(start, end);
swap(numbers[index], numbers[end]);
int cursor = start - 1;
// cursor 指向當前掃過(或交換過後)的最近一個小於number[end]的元素
// 未交換前,cursor的下一個元素是比number[end]大的元素
for(index = start; index < end; index++) {
if(numbers[index] < numbers[end]) {
++cursor;
if (cursor != index) {
swap(numbers[cursor], numbers[index]);
}
}
}
++cursor;
swap(numbers[cursor], numbers[end]);
return cursor;
}
//檢查原陣列是否符合輸入規範
bool checkInvalidArray(int* numbers, int length) {
if(numbers == NULL || length <= 0)
return false;
return true;
}
//檢查演算法得到的結果是否在原陣列中符合要求
bool checkMoreThanHalf(int* numbers, int length, int result) {
int times = 0;
for(int i = 0; i < length; i++) {
if(numbers[i] == result)
++times;
}
if(times * 2 <= length)
return false;
return true;
}
// 找到排序後的numbers的中位數,就是題目要求的陣列的元素
int moreThanHalfNum(int* numbers, int length) {
// 檢查輸入的陣列是否符合題目要求
if(!checkInvalidArray(numbers, length))
return -1;
int middle = length >> 1; //除2
int start = 0;
int end = length - 1;
int index = partition(numbers, length, start, end);
while(index != middle) {
if(index < middle) {
start = index + 1;
index = partition(numbers, length, start, end);
} else {
end = index - 1;
index = partition(numbers, length, start, end);
}
}
int result = numbers[middle];
if(!checkMoreThanHalf(numbers, length, result))
result = -1;
return result;
}
int main() {
int* numbers = new int[9];
for(int i = 0; i < 9; i++) {
if(i % 2 == 0) {
numbers[i] = 2;
}
else
numbers[i] = i*2;
cout << numbers[i] << " ";
}
cout << endl;
int res = moreThanHalfNum(numbers, 9);
cout << "result:"<< res << endl;
}
方法2:
因為要找的數字在陣列中出現的次數比其他數字加起來的次數還要多,因此,在遍歷陣列時,只要維護兩個變數,一個是當前的數字,一個是當前的次數,如果遍歷到的數字和當前的相同,則次數加1,如果不同則次數減1,如果次數已經減為0,則重新設定當前的陣列並使次數為1。只要這樣做,最終保留的數字一定是出現次數超過一半的那個數字。
int moreThanHalfNumV2(int* numbers, int length) {
if(!checkInvalidArray(numbers, length))
return -1;
int result = numbers[0];
int times = 1;
for(int i = 1; i < length; i++) {
if(times == 0) {
result = numbers[i];
times = 1;
} else if(numbers[i] == result)
++times;
else {
--times;
}
}
if(!checkMoreThanHalf(numbers, length, result))
result = -1;
return result;
}