劍指Offer(面試題29~30)
面試題29:陣列中出現次數超過一半的數字
題目:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1,2,3,2,2,2,5,4,2}。由於數字2在陣列中出現了5次,超過陣列長度的一半,因此輸出2。
bool g_bInputInvalid = false;
bool CheckInvalidArray(int* numbers,int length)
{
g_bInputInvalid = false;
if(numbers == NULL || length <= 0)
g_bInputInvalid = true ;
return g_bInputInvalid;
}
bool CheckMoreThanHalf(int* numbers,int length,int number)
{
int times = 0;
for(int i=0;i<length;++i)
{
if(numbers[i] == number)
times++;
}
bool isMoreThanHalf = true;
if(times*2 <= length)
{
g_bInputInvalid = true ;
isMoreThanHalf = false;
}
return isMoreThanHalf;
}
int MoreThanHalfNum(int* numbers,int length)
{
if(CheckInvalidArray(numbers,length))
return 0;
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 = 0;
return result;
}
面試題30:最小的K個數
題目:輸入n個整數,找出其中最小的k個數。例如輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1、2、3、4。
解法一:O(n)的演算法,只有當我們可以修改輸入的陣列時可用
分析:可以基於陣列的第k個數字來調整,使得比第k個數字小的所有數字都位於陣列的左邊,比第k個數字大的所有數字都位於陣列的右邊。這樣調整之後,位於陣列中左邊的k個數字就是最小的k個數字(這k個數字不一定是排序的)。下面是參考程式碼:
void GetLeastNumbers(int* input,int n,int* output,int k)
{
if(input == NULL || output == NULL || k>n || n<=0 || k <= 0)
return;
int start = 0;
int end = n-1;
int index = partition(input,n,start,end);
while(index != k -1)
{
if(index > k-1)
{
end = index -1;
index = partition(input,n,start,end);
}
else
{
start = index + 1;
index = partition(input,n,start,end);
}
}
for(int i = 0;i < k;++i)
output[i] = input[i];
}
採用這種思路是有限制的。我們需要修改輸入的陣列,因為函式Partition會調整陣列中數字的順序。如果面試官要求不能修改輸入的陣列,則解法如下:
解法二:O(nlogk)的演算法,特別適合處理海量資料
先建立一個大小為k的資料容器來儲存最小的k個數字,接下來我們每次從輸入的n個整數中讀入一個數。如果容器中已有的數字少於k個,則直接把這次讀入的整數放入容器之中;如果容器中已有k個數字了,也就是容器已滿,此時我們不能再插入新的數字而只能替換已有的數字。找出這已有的k個數中的最大值,然後那這次待插入的整數和最大值進行比較。如果待插入的值比當前已有的最大值小,則用這個數替換當前已有的最大值;如果待插入的值比當前已有的最大值還要大,那麼這個數不可能是最小的k個整數之一,於是我們可以拋棄這個整數。
typedef multiset<int, greater<int> > intSet;
typedef multiset<int, greater<int> >::iterator setIterator;
void GetLeastNumbers(const vector<int>& data,intSet& leastNumbers,int k)
{
leastNumbers.clear();
if(k < 1 || data.size() < k)
return;
vector<int>::const_iterator iter =data.begin();
for(; iter != data.end();++ iter)
{
if((leastNumbers.size()) < k)
{
leastNumbers.insert(*iter);
}
else
{
setIterator iterGreatest = leastNumbers.begin();
if(*iter < *(leastNumbers.begin()))
{
leastNumbers.erase(iterGreatest);
leastNumbers.insert(*iter);
}
}
}
}
第二種解法雖然要慢一點,但它有兩個明顯得優點。一是沒有修改輸入的資料。我們每次只是從data中讀入數字,所有的寫操作都是容器leastNumbers中進行的。二是該演算法適合海量資料的輸入。假設題目是要求從海量的資料中找出最小的k個數字,由於記憶體的大小是有限的,有可能不能把這些海量的資料一次性全部載入記憶體。這時候,我們可以從輔助儲存空間(比如硬碟)中每次讀入一個數字,根據GetLeastNumbers的方式判斷是不是需要放入容器leastNumbers即可。這種思路只要求記憶體有足夠容納leastNumbers即可,因此它最適合的情形就是n很大並且k較小的問題。
參考資料:《劍指Offer》
相關推薦
劍指Offer(面試題29~30)
面試題29:陣列中出現次數超過一半的數字 題目:陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1,2,3,2,2,2,5,4,2}。由於數字2在陣列中出現了5次,超過陣列長度的一半,因此輸出2。 bool g_
劍指offer(面試題29):順時針列印矩陣
/* * 順時針列印矩陣 * 注意矩陣的維度 */ #include<iostream> using namespace std; //只要當前的起始行號小於終止行號或者起始列號小於終止列號,就可以繼續順時針列印 // 但是隨著順勢怎列印,剩下
劍指Offer(面試題43~45)
面試題43:n個骰子的點數 題目:把n個骰子仍在地上,所有骰子朝上一面的點數之和為s。輸入n,打印出s的所有可能的值出現的概念。 解法一:基於遞迴求骰子點數,時間效率不夠高 要想求出n個骰子的點數和,可以先把n個骰子分成兩堆:第一堆只有一個,另一堆有n-1
劍指Offer(面試題33~34)
面試題33:把陣列排成最小的數 題目:輸入一個正整數陣列,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。例如輸入陣列{3,32,321},則打印出這3個數字能排成的最小數字321323。 分析:一個非常直觀的解決大數問題的方法就是把
【劍指offer】面試題 29. 順時針打印矩陣
如果 clas for 輸入 offer ID amp 代碼實現 AR 面試題 29. 順時針打印矩陣 題目描述 題目:輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字,例如,如果輸入如下矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 1
劍指offer(面試題五)--從尾到頭列印單鏈表
程式碼如下(遞迴實現): /** * public class ListNode { * int val; * ListNode next = null; * * ListNode(int val) { *
劍指offer(面試題39):陣列中出現次數超過陣列長度一半的數字
方法1: 從數學角度看,所求的數一定的原陣列(有序化)的中位數,那麼,我們可以通過對陣列排序,這樣得到的時間複雜度是O(nlogn)O(nlogn)。而如果能夠優化到在O(n)O(n)的時間內找到,就更好了。基於快速排序的partition階段,如果我們可以
劍指offer(面試題35):複雜連結串列的複製
/* * 複雜連結串列的複製 * 複雜連結串列是指,結點的指標可能不規則地指向另一個結點 */ #include<iostream> using namespace std; struct ComplexListNode { int v
劍指offer(面試題38):字串的排列
分析: 求字串中所有字元的全排列,實際上按照全排列的計算公式來理解,第一步是求出所有可能出現在第一個位置的字元,即用首個字元分別後餘下的字元交換;第二步是固定首個字元,餘下字元組成的子串進行第一步的
劍指offer(面試題21):根據給定條件劃分陣列
/* * 題目 * 輸入一個數組,實現一個函式來調整該陣列中數字的順序,使得所有奇數位於陣列的前半部分 * 偶數位於陣列的後半部分 * 同時考慮程式碼的可擴充套件行 */ #include <i
劍指offer(面試題31):棧的壓入和彈出序列
/* * 給定兩個序列,一個是棧的壓入序列,一個是彈出序列,判斷彈出序列能否匹配壓入序列 */ #include<iostream> #include<stack> usi
《劍指offer》面試題39 二叉樹的深度(java)
設計模式 博客 rgs 歷史 存在 復制 pri 取值 今天 摘要: 今天翻到了《劍指offer》面試題39,題目二中的解法二是在函數的參數列表中通過指針的方式進行傳值,而java是沒有指針的,所以函數要進行改造。然而我翻了下別人的java版本(我就想看看有什麽高大上的改造
《劍指offer》 面試題43 n個骰子的點數 (java)
r+ nal ret 次循環 分而治之 源碼 ava 面試 ble 引言:寫這篇文章的初衷只是想做個筆記,因為這道題代碼量有點大,有點抽象,而書上並沒有詳細的註釋。為了加深印象和便於下次復習,做個記錄。 原題:把n個骰子扔到地上,所有骰子朝上一面的點數之後為s. 輸入n,打
【劍指offer】面試題57(1):和為S的數字
題目 輸入一個遞增排序的陣列和一個數字S,在陣列中查詢兩個數,是的他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。 ps: 對應每個測試案例,輸出兩個數,小的先輸出。 思路
《劍指offer》面試題答案彙總(Java版)
面試題2:實現Singleton模式 (1)餓漢模式 public class Singleton{ private static Singleton instance = new Singleton(); private Singleton(){}
《劍指offer》- 面試題3:陣列中重複的數字(java實現)
題目一: 在一個長度為n的數組裡的所有數字都在0到n-1的範圍內。 陣列中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出陣列中任意一個重複的數字。 例如,如果輸入長度為7的陣列{2,3,1,0,2,5,3},那麼對應的輸出是重複
【劍指offer】面試題32(2):分行從上到下列印二叉樹
完整程式碼地址 題目 從上到下按層列印二叉樹,同一層結點從左至右輸出。每一層輸出一行。 思路 用佇列來儲存要列印的節點。 同時我們需要兩個變數:一個變量表示在當前層中還沒有列印的節點數
劍指offer:面試題二:單例模式的實現(使用C++語言)
#include <iostream> #include <iomanip> #include <cstdio> #include <cstdlib>
【劍指offer】面試題50:(字元流中)第一個只出現一次的字元【C++版本】
題目:字串中第一個只出現一次的字元。 在字串中找出第一個只出現一次的字元。如輸入"abaccdeff" "abaccdeff",則輸出′ b ′ ′b′。 解題思路: 1.使用雜湊表來記錄每個字元出現的次數,因為字元char char為8位,
【劍指offer】面試題 2. 實現 Singleton模式
模式 試題 枚舉 生成 test hand true 方法 單例模式 面試題 2. 實現 Singleton模式 題目:設計一個類,我們只能生成該類的一個實例。 單例模式:確保一個類只有一個實例,並提供了一個全局訪問點。 Code 1.餓漢模式 //餓漢模式 publ