劍指offer練習
寫一個程序要注意:
1. 功能性測試(完成基本功能)
2. 邊界值測試(單獨處理邊界)
3. 負面測試(處理無效數據)
其餘的還有:
1. 變量命名規範化,可讀化
2. 釋放一個內存時,要記得把引用這塊內存的指針置爲NULL
通知函數的調用者函數出錯有三種方式,比如第16題涉及到如果對0求負數冪,由於不能對0求倒數,應該提示調用出錯:
1. 返回值
2. 全局變量
3. 拋出異常
基本概念:
1. 魯棒性(健壯性)指程序能夠判斷輸入是否合乎規範要求,並對不符合要求的輸入予以合理的處理。
1. 賦值運算符
}
{
if(this == &s) return this;
char* temp = new char[s.size + 1];
if(temp){ // 如果分配成功了
delete m_pData;
m_pData = temp;
size = s.size;
}
return *this;
}
CMyString& operator = (const CMyString& s)
{
if(this != &s)
{
CMyString temp = CMyString(s);
// 交換自身的數據指針和臨時對象的數據指針
char* tp = s.m_pData;
s.m_pData = m_pData;
m_pData = tp;
} // 出了if塊之後,會調用temp的析構,釋放它的內存
return *this;
}
2. 單例模式
3. 找數組中重複的數字
using namespace std;
#define SIZE 10
int hashTable[SIZE] = {0};
int main()
{
int num[SIZE] = {1, 2, 2, 3, 4, 5, 5 ,6, 7};
int repNum = -1;
for (int i = 0; i < SIZE; i++)
{
if (hashTable[num[i]] != 0)
{
repNum = num[i];
break;
}
hashTable[num[i]] ++;
}
cout << repNum;
}
using namespace std;
#define SIZE 10
int main()
{
int n[SIZE] = { 1, 2, 3, 4, 2, 5, 5 ,6, 7 };
#define swap(x, y)\
do {\
int t = x;\
x = y;\
y = t;\
}while(0)
int res = -1;
for (int i = 0; i < SIZE; )
{
if (n[i] != i)
{
if (n[n[i]] == n[i])
{
res = n[i];
break;
}
// 把數字放到它應在的位置
int v = n[i];
// 注意這裏不能n[n[i]],一旦n[i]改了,結果就不對了
swap(n[i], n[v]);
}
}
cout << res;
}
4. 二維數組中的查找
問題描述:有一個二維數組,每行都按照從左到右遞增,每一列按照從上到下遞增。寫一個函數,接受一個二維數組和一個整數,判斷二維數組中是否有該整數。
比如有一個二維數組:
1 2 8 9
2 4 9 12
4 7 10 13
6 8 11 15
查找7, 5...
解決方案:從右上角(比如9)開始縮小查找區域,如果右上角的值大於目標值,則該列不可能有目標值,剔除一列,接着判斷左邊一列。如果某列第一個值小於目標值,則目標值有可能在此列,且不可能在此行,剔除此行(因爲更左邊更不可能有了,而右邊的已經剔除了),規模立馬縮小了。接着就是重複這個步驟,知道找到目標值,或者列到底,或者行到頭,表示沒有這個值。也就是說,每次我們只會去那右上角和目標值比較,不會去遍歷整個表,或者某行某列。
using namespace std;
#define SIZE 4
bool find(int n[][SIZE], int num, int i, int j)
{
if (i > SIZE || j < 0) // 遞歸終點
return false;
if (n[i][j] > num)
return find(n, num, i, j - 1);
else if (n[i][j] == num)
return true;
else
return find(n, num, i + 1, j);
}
int main()
{
int n[][SIZE] = {
{1, 2, 8, 9},
{2, 4, 9, 12},
{4, 7, 10, 13},
{6, 8, 11, 15},
};
if (find(n, 14, 0, 3))
{
cout << "find number " << endl;
}
else
{
cout << "didnt find number" << endl;
}
}
5. 替換空格
using namespace std;
#define SIZE 1024 // buffer size
int main()
{
char strbuf[SIZE] = "We are happy.";
//cout << sizeof(strbuf); // 1024
int originalLen = strlen(strbuf) + 1; // 13 + 1, 包含結尾0
int newlen = originalLen;
for (int i = 0; strbuf[i] != 0; i++)
{
if (strbuf[i] == ' ')
newlen += 2;
}
if (newlen > SIZE)
return 0;
int pre = originalLen - 1;
int beh = newlen - 1;
while (pre >= 0)
{
if (strbuf[pre] == ' ')
{// 替換
strbuf[beh--] = '0';
strbuf[beh--] = '2';
strbuf[beh--] = '%';
}
else
{// 直接覆蓋
strbuf[beh--] = strbuf[pre];
}
--pre;
}
cout << strbuf;
return 0;
}
6. 從尾到頭打印鏈表
{
if(root == NULL) return ;
PrintListReversingly(root->m_pNext);
cout << root->m_pData << endl;
}
{
if(root == NULL) return ;
stack<ListNode*> nodes;
while(root)
{
nodes.push(root);
root = root->next;
}
while(!nodes.empty())
{
ListNode* p = nodes.top();
nodes.pop();
cout << p->m_pData;
}
}
7. 重建二叉樹
Node* left;
using namespace std;
struct Node
{
int value;
Node* right;
Node* left;
};
//
Node* rebuild(int dlr[], int dlr_p, int s,// 前序遍歷和區間, dir_p表示前序遍歷中的子序列索引,s表示中序和前序序列的大小
int ldr[], int ldr_l, int ldr_r) // 中序遍歷和區間, ldr_l,ldr_r分別表示中序遍歷中子樹的範圍
{
// 邊界
if (dlr_p < 0 || dlr_p >= s) return NULL;
if (ldr_l > ldr_r) return NULL;
// 判斷
Node* node = new Node;
node->value = dlr[dlr_p]; // 前序遍歷的第一個點就是根結點
// 從中序遍歷中尋找根結點的位置
int pos = -1;
for (int i = ldr_l; i <= ldr_r; i++)
{
if (ldr[i] == node->value)
{
pos = i;
break;
}
}
int lsize = pos - ldr_l; // 左子樹寬度
int rsize = ldr_r - pos; // 右子樹寬度
node->left = rebuild(dlr, dlr_p + 1, s, ldr, ldr_l, pos - 1);
node->right = rebuild(dlr, dlr_p + lsize + 1, s, ldr, pos + 1, ldr_r);
return node;
}
// 後續遍歷
void lrd(Node* root)
{
if (root == NULL)return;
lrd(root->left);
lrd(root->right);
cout << root->value << endl;
}
int main()
{
const int size = 8;
int dlr[size] = {1, 2, 4, 7, 3, 5, 6, 8};
int ldr[size] = {4, 7, 2, 1, 5, 3, 8, 6};
Node* root = rebuild(dlr, 0, size, ldr, 0, size - 1);
lrd(root);
}
8. 二叉樹的下一個節點
{
if(node == NULL) return NULL;
Node* parent = node->parent;
if(parent->left == node) return parent;
else
{// 是右節點
Node* next = node->right ;
if(next)
{//,從右子樹中找最左節點,一直遍歷left,知道->left爲空
while(next->left)
next = next->left;
}
else
{
next = findNext(node->parent);
}
return next;
}
}
9. 用兩個棧實現一個隊列、用兩個隊列實現一個棧
#include <stack>
using namespace std;
// MyQueue適配器
class MyQueue
{
public:
MyQueue():s1(), s2()
{
}
stack<int> s1;
stack<int>s2;
void push(int n)
{
s1.push(n);
}
void pop()
{
if (!s2.empty())
{
s2.pop();
return;
}
while (!s1.empty())
{
int n = s1.top();
s2.push(n);
s1.pop();
}
s2.pop();
}
int front()
{
if (!s2.empty())
{
return s2.top();
}
while (!s1.empty())
{
int n = s1.top();
s2.push(n);
s1.pop();
}
return s2.top();
}
bool empty()
{
return s1.empty() && s2.empty();
}
};
int main()
{
MyQueue q;
q.push(1);
q.push(3);
q.push(2);
q.push(5);
q.push(4);
cout << q.front() << endl;
q.pop();
cout << q.front() << endl;
while (!q.empty())
{
cout << q.front();
q.pop();
}
}
#include <iostream>
#include <queue>
using namespace std;
class MyStack
{
public:
MyStack() :q1(), q2()
{
}
// 每次只會有一個隊列非空
queue<int> q1;
queue<int> q2;
void push(int n)
{
// 當前操縱隊列
queue<int>* cur = &q1;
if (!q2.empty()) cur = &q2;
cur->push(n);
}
void pop()
{
if (empty()) return;
queue<int>* cur = &q1;
queue<int>* another = &q2;
if (!q2.empty())
{
cur = &q2;
another = &q1;
}
// 將前面的那些轉移到另一個隊列中
while (cur->size() > 1)
{
int n = cur->front();
another->push(n);
cur->pop();
}
if(!cur->empty())
cur->pop();
}
int top()
{
if (empty()) return 0;
queue<int>& cur = q1;
queue<int>& another = q2;
if (!q2.empty())
{
another = q1;
cur = q2;
}
// 將前面的那些轉移到另一個隊列中
int n ;
while (!cur.empty())
{
n = cur.front();
another.push(n);
cur.pop();
}
return n;
}
bool empty()
{
return q1.empty() && q2.empty();
}
};
int main()
{
MyStack s;
s.push(1);
s.push(2);
s.push(3);
s.push(4);
cout << s.top();
s.pop();
s.push(5);
while (!s.empty())
{
cout << s.top();
s.pop();
}
}
10. 斐波那契數列
using namespace std;
int main()
{
for (;;)
{
int n;
cin >> n;
if (n == 1)
{
cout << 1 << endl;
continue;
}
int fibMinusOne = 1;
int fibMinusTow = 0;
int fibN = 0;
for (int i = 2; i <= n; i++)
{
fibN = fibMinusTow + fibMinusOne;
fibMinusTow = fibMinusOne;
fibMinusOne = fibN;
}
cout << fibN << endl;
}
return 0;
}
11. 旋轉數組的最小數字
using namespace std;
// l指針一定在左子序列
// r指針一定在右子序列
int find(int *n, int l, int r)
{
if (n[l] < n[r]) return n[l]; // 處理 自身有序這種情況,可以直接返回
if (r - l == 1) return n[r]; // 左右兩指針相遇,只差一個,則最小值是右子序列的第一個數字
int mid = (l + r) / 2.f;
if (n[mid] >= n[l]) return find(n, mid, r);
if (n[mid] <= n[r]) return find(n, l, mid);
}
int main()
{
int n[] = {3, 4, 5, 1, 2};
cout << find(n, 0, sizeof(n)/ sizeof(int) - 1);
}
12. 矩陣中的路徑
using namespace std;
#define SIZE 4
// i, j 是當前點的位置
bool traceback(bool mask[][SIZE], char n[][SIZE], int r, int c, int i, int j, const char* s)
{
if (i < 0 || i >= r || j < 0 || j >= c)
return false;
if (mask[i][j]) return false; // 不能重複訪問一個節點
if (n[i][j] == s[0])
{// 找下一部分
mask[i][j] = true; // 標記這個節點已經被訪問過
if (strlen(s) == 1) return true; // 已經相等
if (traceback(mask, n, r, c, i, j - 1, s + 1) // 向左走
|| traceback(mask, n, r, c, i, j + 1, s + 1) // 向右走
|| traceback(mask, n, r, c, i - 1, j, s + 1) // 向上走
|| traceback(mask, n, r, c, i + 1, j, s + 1) // 向下走
)
return true;
else
{// 沒有此路徑
mask[i][j] = false;
return false;
}
}
else
return false;
}
bool find(bool mask[][SIZE], char n[][SIZE], int r, int c, const char* s)
{
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
if (n[i][j] == s[0])
if (traceback(mask, n, r, c, i, j, s))
return true;
}
}
return false;
}
int main()
{
char n[][SIZE] = {
{'a', 'b', 't', 'g'},
{'c', 'f', 'c', 's'},
{'j', 'd', 'e', 'h' },
};
bool mask[][SIZE] = {
{0},
{ 0 },
{ 0 },
};
const char* s = "bfce";
//const char* s2 = "abfb";
if (find(mask, n, 3, 4, s))
cout << "the string is found" << endl;
else
cout << "can't find string" << endl;
}
13. 機器人的運動範圍
using namespace std;
int sum(int i, int j)
{
int res = 0;
while (i > 0)
{
res += i % 10;
i /= 10;
}
while (j > 0)
{
res += j % 10;
j /= 10;
}
return res;
}
void find(int m, int n,int i, int j, int k, int& count, bool* visited)
{
if (i < 0 || i >= m || j < 0 || j >= n) return;
if (visited[n * i + j]) return;
if (sum(i, j) > k) return ;
if (!visited[n * i + j])
{
visited[n * i + j] = true;
count += 1;
}
find(m, n, i - 1, j, k, count, visited); // 向上走
find(m, n, i + 1, j, k, count, visited); // 向下走
find(m, n, i, j - 1, k, count, visited); // 向左走
find(m, n, i, j + 1, k, count, visited); // 向右走
}
int main()
{
for (;;)
{
int m, n, k;
m = 5;
n = 5;
k = 3;
int count = 0;
bool* visited = new bool[m *n];
for (int i = 0; i < m*n; i++)
visited[i] = 0;
find(m, n, 0, 0, k, count, visited);
cout << count;
}
}
14. 剪繩子
using namespace std;
int main()
{
int n = 8;
int *product = new int[n + 1];
// 邊界
product[0] = 0;
product[1] = 1;
product[2] = 2;
product[3] = 3;
int max = 0;
for (int i = 4; i <= n; i++)
{
max = 0;
for (int j = 0; j <= i/2; j++)
{
int p = product[j] * product[i - j];
if (p > max) max = p;
product[i] = max;
}
}
max = product[n];
delete[] product;
cout << max;
}
15. 位運算
#include <string>
#include <math.h>
using namespace std;
int f(const string s)
{
int n = s.size();
int res = 0;
for (int i = 0; i < s.size(); i++)
{
char c = s[i];
int num = c - 'A' + 1;
res += num * pow((double) 26, (double)(--n));
}
return res;
}
int main()
{
for (;;)
{
string s;
cin >> s;
cout << f(s);
}
}
using namespace std;
int countOne(int n)
{
int res = 0;
while (n > 0)
{
res += (n & 1);
n = n >> 1;
}
return res;
}
int main()
{
for (;;)
{
int n;
cin >> n;
cout << countOne(n) << endl;
}
}
using namespace std;
int countOne(int n)
{
int count = 0;
unsigned int flag = 1;
while (flag)
{
if ((n & flag) != 0) count++;
flag = flag << 1;
}
return count;
}
int main()
{
for (;;)
{
int n;
cin >> n;
cout << countOne(n) << endl;
}
}
using namespace std;
int countOne(int n)
{
int count = 0;
while (n)
{
++count;
n = (n - 1) & n;
}
return count;
}
int main()
{
for (;;)
{
int n;
cin >> n;
cout << countOne(n) << endl;
}
}
16. 數值的整數次方
bool g_InvalidInput = false; // 保存錯誤信息
double PowerWithUnsignedExponent(double base, unsigned int exponent) // 計算正數冪
{
double result = 1.0;
for (int i = 1; i <= exponent; ++i)
result *= base;
return result;
}
double Power(double base, int exponent)
{
g_InvalidInput = false;
if (base == 0.0 && exponent < 0)
{// 不能對0求負冪,因爲不能對0求倒數
g_InvalidInput = true;
return 0.0;
}
unsigned int absExponent = (unsigned int)exponent;
if (exponent < 0)
absExponent = (unsigned int)(-exponent);
double result = PowerWithUnsignedExponent(base, exponent);
if (exponent < 0)
// 如果是負數冪,就取倒數
result = 1.0 / result;
return result;
}
int main()
{
}
17. 打印從1到最大的n位數
using namespace std;
// 給n +1
bool Increment(char* n)
{
bool isOverflow = false;
int nTakeOver = 0; // 進位
int nLength = strlen(n);
for (int i = nLength - 1; i >= 0; i--)
{
int nSum = n[i] - '0' + nTakeOver; // 加上進位
if (i == nLength - 1)
nSum++;
if (nSum >= 10) // 需要進位
{
if (i == 0) // 如果已經到最高位了,即最後一個數字
isOverflow = true;
else
{
nSum -= 10;
nTakeOver = 1;
n[i] = '0' + nSum; //刷新
}
}
else
{
n[i] = '0' + nSum;
break;
}
}
return isOverflow;
}
// 輸出數字,注意別輸出補位的零
void PrintNumber(const char* n)
{
int len = strlen(n);
bool isBeginningZero = true;
for (int i = 0; i < len; i++)
{
if (n[i] == '0' && isBeginningZero)
{
continue;
}
isBeginningZero = false;
cout << n[i];
}
cout << '\n';
}
//
void PrintToMaxOfNDigits(int n)
{
if (n <= 0)
return;
char* number = new char[n + 1];
memset(number, '0', n);
number[n] = '\0';// 此時 字符串應該是 0000...000\0, n個0, 結尾一個\0
while (! Increment(number)) // 輸出,直到位數已滿
{
PrintNumber(number);
}
delete[] number;
}
int main()
{
for (;;)
{
int n;
cin >> n;
PrintToMaxOfNDigits(n);
}
}
using namespace std;
void PrintToMaxOfNDigits(int n)
{
if (n <= 0) return;
char* number = new char[n + 1];
number[n] = '\0';
for (int i = 0; i <= 9; i++)
{
number[0] = i + '0';
PrintToMaxOfNDigitsRecursively(number, n, 0);
}
}
// 輸出數字,注意別輸出補位的零
void PrintNumber(const char* n)
{
int len = strlen(n);
bool isBeginningZero = true;
for (int i = 0; i < len; i++)
{
if (n[i] == '0' && isBeginningZero)
{
continue;
}
isBeginningZero = false;
cout << n[i];
}
cout << '\n';
}
void PrintToMaxOfNDigitsRecursively(char* number, int length, int index)
{
if (index == length - 1)
{
PrintNumber(number);
}
for (int i = 0; i < 10; i++)
{
number[index + 1] = i + '0';
PrintToMaxOfNDigitsRecursively(number, length, index + 1);
}
}
int main()
{
for (;;)
{
int n;
cin >> n;
PrintToMaxOfNDigits(n);
}
}
18. 刪除鏈表的結點
{
if(*head == NULL || node == NULL) return ;
// 如果要刪除的不是尾結點
if(node->next != NULL)
{
ListNode* next= node->next;
node->m_pDate = next->m_pData;
node->next = next->next;
delete next;
next = NULL;
}
// 如果只有一個結點,刪除這個節點
else if(*head == node)
{
delete node;
node = NULL;
*head= NULL:
}
else
{// 鏈表有多個節點,且刪除尾結點,則尾結點的上一個節點的next應該是0,
// 這時候只能老老實實遍歷了
ListNode* n = *head;
while(n->next != node)
{
n = n->next;
}
n->next = NULL;
delete node;
node = NULL;
}
}
19. 正則表達式匹配
using namespace std;
bool matchCore(char* str, char* pattern)
{
// 遞歸終點
if (*str == '\0' && *pattern == '\0') // 當兩者都走完時,匹配
return true;
if (*str != '\0' && * pattern == '\0') // 當模式已經走完時,字符串還沒走完,不匹配。(題目要求字符串中的所有字符匹配整個模式);翻過來的情況在下面的代碼中判斷,即*str = '\0’返回false。
return false;
if (*(pattern + 1) == '*')
{// 如果模式的第二個字符是* 或者模式允許任意字符出現任意多次即".*"模式
if (*str == *pattern || *pattern == '.' && *str != '\0')
{// 如果str的第一個字符和pattern的第一個匹配,則str跳過一個,或者pattern跳過這個*匹配(即匹配0次),或者兩者都跳過
return matchCore(str + 1, pattern)
|| matchCore(str, pattern + 2)
|| matchCore(str + 1, pattern + 2);
}
else
{ // 如果不匹配,則跳過這個* 匹配(因爲*允許出現0次前面的字符)
return matchCore(str, pattern + 2);
}
}
if (*str == *pattern || (*pattern == '.' && *str != '\0'))
return matchCore(str + 1, pattern + 1);
}
bool match(char* str, char* pattern)
{
if (str == NULL || pattern == NULL) return false;
return matchCore(str, pattern);
}
20. 表示數值的字符串
21. 調整數組順序使得奇數位於偶數前面
using namespace std;
int main()
{
int n[] = {0, 1,2,3,4,5,6,7,8};
int size = sizeof(n) / sizeof(int);
int l = 0;
int r = size - 1;
while (l < r)
{
while ((n[r] & 1) == 0) --r; // 位運算符優先級低於比較運算符。位運算優先級一般很低,移位最低
while ((n[l] & 1) == 1) ++l;
if (l >= r) break;
n[r] ^= n[l];
n[l] ^= n[r];
n[r] ^= n[l];
l++;
r--;
}
for (int i = 0; i < size; i++)
cout << n[i] << " " << endl;
}
22. 獲得鏈表中倒數第k個節點
{
if (k == 0 || pHead == NULL) // 這裏k的計數是從1開始的,若k爲0或鏈表爲空返回NULL
return NULL;
ListNode * pAhead = pHead;
ListNode * pBehind = pHead;
while (k > 1 && pAhead != NULL) // 前面的指針先走到正向第k個結點, 走了k-1步
{
k--;
pAhead = pAhead->m_pNext;
}
if (k > 1 || pAhead == NULL) // 結點個數小於k,返回NULL
return NULL;
while (pAhead->m_pNext != NULL) // 前後兩個指針一起向前走,直到前面的指針指向最後一個結點
{
pBehind = pBehind->m_pNext;
pAhead = pAhead->m_pNext;
}
return pBehind; // 後面的指針所指結點就是倒數第k個結點
}
23. 鏈表中環的入口結點
24. 反轉鏈表
25. 合併兩個已排序的鏈表
26. 樹的子結構
27. 翻轉二叉樹
* 28. 對稱的二叉樹
{
return isSymmetraical(pRoot, pRoot);
}
bool isSymmetraical(BinaryNode* pRoot1, BinaryNode* pRoot2) // root1往左走,root2往右走
{
if(pRoot1 == NULL && pRoot2 == NULL)
return true;
if(pRoot1 == NULL || pRoot2 == NULL) // 有一個不爲空
return false;
if(pRoot1->m_Value != pRoot2->m_Value)
return false;
return isSymmetraical(pRoot1->m_left, pRoot2->m_right)
&& isSymmetraical(pRoot1->m_right, pRoot2->m_left);
}
29. 順時針打印矩陣
30. 包含min函數的棧
31. 棧的壓入、彈出序列
32. 從上到下打印二叉樹(二叉樹層次遍歷/廣度優先遍歷)
33. 二叉搜索樹的後序遍歷序列
34. 二叉樹中和爲某一值的路徑
35. 複雜鏈表的複製
36. 二叉搜索樹轉化爲雙向鏈表
37. 序列化二叉樹
* 38. 字符串的排列
void Permutation(char* pStr, char* pBegin);\
void Permutation(char* pStr)
{
if(pStr == nullptr)
return;
Permutation(pStr, pStr);
}
void Permutation(char* pStr, char* pBegin)
{
if(*pBegin == '\0')
{
printf("%s\n", pStr);
}
else
{
for(char* pCh = pBegin; *pCh != '\0'; ++ pCh)
{
char temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
Permutation(pStr, pBegin + 1); // 處理後面的
temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
}
}
}
// ====================測試代碼====================
void Test(char* pStr)
{
if(pStr == nullptr)
printf("Test for nullptr begins:\n");
else
printf("Test for %s begins:\n", pStr);
Permutation(pStr);
printf("\n");
}
int main(int argc, char* argv[])
{
Test(nullptr);
char string1[] = "";
Test(string1);
char string2[] = "a";
Test(string2);
char string3[] = "ab";
Test(string3);
char string4[] = "abc";
Test(string4);
return 0;
}
* 39. 數組中出現次數超過一半的數字
* 40. 最小的k個數(TOP K問題)
其實很簡單,大家都知道Quicksort每次分割後即把比軸小的值和比軸大的值給cut開了。那麼,假如是想求前k小(以下源碼即是),我就只關心比軸小的一邊,繼續分割這一邊,直到如果分割後的元素沒有k個了,就結束循環。我們用源碼說話:
快速排序的思想是使用一個基準元素將數組劃分成兩部分,左側都比基準數小,右側都比基準數大。
給定數組array[low…high],一趟快排劃分後的結果有三種:
1)如果基準數左側元素個數Q剛好是K-1,那麼在基準數左側(包含基準數本身),即爲TopK的所有元素。
2)如果基準數左側元素個數Q小於K-1,那麼說明基準數左側的Q個數都是TopK裏的元素,只需要在基準數的右側找出剩下的K-Q個元素即可。問題轉化成了以基準數下標爲起點,高位(high)爲終點的Top(K-Q)。遞歸下去即可。
3)如果基準數左側元素個數Q大於K-1,說明第K個位置,在基準數的左側,需要縮小搜索範圍,在低位(low)至基準數位置重複遞歸即可,最終問題會轉化成上面兩種情況。