GitHub#algorithm#:《劍指offer》 的50道面試題

Koma_Wong發表於2018-06-14

《劍指offer》 這本書給出了50到面試題,涉及到字串處理,堆疊,連結串列,二叉樹等問題的處理。

  • 程式碼魯榜性:邊界條件,特殊輸入,異常處理:空指標
  • 分析方法:畫圖,舉例,分解
  • 查詢和排序是常考:重點掌握二分查詢,快速排序,歸併排序
  • 本書完整原始碼在:

賦值運算子函式

實現Singleton模式

二維陣列中的查詢

二維陣列中每一行從左到右遞增,每一列從上到下遞增,判斷陣列中是否包含該整數。

bool find(int *matrix,int rows,int columns,int numbers)

替換空格

如把字串中的每個空格替換成%20

二遍掃描

void replace_blank(char *str);

從尾到頭列印連結串列

void print_reversing(LinkList *head)

重建二叉樹

輸入某二叉樹的前序遍歷和中序遍歷的結果,重建該二叉樹

BinaryTree *construct(int *preorder,int inroder,int length);

用兩個棧實現佇列

佇列就是在尾部插入節點,頭部刪除節點。

旋轉陣列的最小數字

旋轉陣列是指把一個陣列最開始的若干個元素搬到陣列的末尾。輸入一個遞增排序的陣列的旋轉,比如{3,4,5,1,2}是{1,2,3,4,5}的一個旋轉。求該陣列的最小值。

int min(int *num, int length)

菲波那切數列

long long fabonacci(unsigned n)

二進位制中1的個數

輸入一個整數,輸出該數二進位制中1出現的次數。比如9的二進位制 10001,輸出是2

n=n&n-1

int one_appear_count(int n)

數值的整數次方

要求不得使用庫函式。這裡注意考慮指數是0和負數的情況

double power(double base,int exponent)

列印1到最大的n位數

比如n=3,就列印1到999

void print_to_max_with_length(int n)

在O(1)時間刪除連結串列節點

已經有一個頭節點指標,還有一個指向改刪除節點的指標

用下一個節點的內容覆蓋當前刪除節點的內容,刪除下一個節點

void deleteNode(LinkList *head,LinkList *targetToDelete);

調整陣列順序使奇數位於偶數前面

調整後,所有奇數在前半部分,偶數在後半部分

兩邊向中間掃描

void reorder(int *data,int length)

輸出連結串列中倒數第K個節點

使用兩個指標,一個先走k-1步

void print_lastK(LinkList *head);

反轉連結串列

三個指標

void reverse(LinkList *head);

反轉二叉樹呢?

合併2個排序的連結串列

要求合併以後連結串列任然排序

遞迴

LinkList *merge(LinkList *one,LinkList *two);

樹的子結構

考察二叉樹的基本操作。輸入2課二叉樹A和B,判斷B是不是A的子結構。

struct BinaryTreeNode{
    int m_value;
    BinaryTreeNode *m_pleft;
    BinaryTreeNode *m_pRight;
}
        8                   
       / \              10
      /   \             / \                        
     6     10   子結構 11  9   
    / \       / \            
   5   7  9  11           
bool subTree(BinaryTreeNode *root1,BinaryTreeNode *root2);

二叉樹翻轉

        8                     8
       / \                   / \
      /   \                 /   \                           
     6     10     翻轉後   10    6
    / \    / \            / \   / \
   5   7  9  11          11  9 7   5

交換每個節點的左右子樹

void reverse(BinaryTreeNode *root);

從外向裡順時針列印矩陣

void print_matrix_clockwise(int *matrix,int cols,int rows);

延伸:按大小順序列印矩陣

實現一個能找到棧的最小元素的函式

最小元素用輔助棧儲存

int min(Stack *stack)

棧的壓入,彈出序列

輸入2個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否為該棧的彈出順序。比如:

1,2,3,4,5是壓棧序列,4,5,3,2,1是彈棧序列,但是4,3,5,1,2就不是彈棧序列

bool is_pop_order(int *push,int *pop,int length)

從上往下列印二叉樹

輔助佇列

void print_binary_level(BinaryTreeNode *root)

二叉搜尋樹的後續遍歷序列

輸入一個整數陣列,判斷該陣列是不是某二叉查詢樹的後續遍歷序列的結果。比如【 5,7,6,9,11,10,8】 是下面二叉查詢樹的後續遍歷結果:

        8               
       / \                   
      /   \                                            
     6     10     
    / \    / \         
   5   7  9  11          

尋找規律

bool is_post_order(BST *root,int *data, int length);

二叉樹中和為某一值的路徑

       10               
       / \                   
      /   \                                            
     5     12     
    / \               
   5   7    

和為22的路徑有2條:10--5--7, 10--12

遞迴,棧

void print_path(BinaryTree *root,int n)

複雜連結串列的複製

在複雜連結串列結構中,每個節點都有一個指向下一個節點的m_pNext;還有一個指向任意節點的m_pSibling

typedef struct LinkListNode{
    int m_value;
    LinkListNode *m_pNext;
    LinkListNode *m_pSlbling;
}LinkList;
LinkList * copy(LinkList *head);

二叉搜尋樹與雙向連結串列

將二叉搜尋樹轉換成一個排序的雙向連結串列,只調整樹中節點的指標指向

遞迴 分解問題

BST *transform(BST *root);

字串的排列

輸入一個字串,列印該字串中字元的所有排列

遞迴,分解

void print_full_permutation(char *string)

陣列中出現次數超過一半的數字

遍歷陣列,下一個數字和之前儲存的數字一樣就+1,否則就-1

int find_more_than_half_num(int *nums ,int length)

n個整數中最小的K個數

快速排序 最大堆

void find_least_k(int *data,int n,int *ouput,int k)

最大的K個數呢?

連續子陣列的最大和

輸入一個整數陣列,有正有負,求所有子陣列的和的最大值

分析規律 動態規劃

int max_of_subarray(int *data,int length)

從1到n整數中,1出現的次數

比如 12,從1到12這些整數中,包含1的數字有 1, 10,11,12 ,1出現了5次

int one_appear_count(int n)

把陣列排成最小的數

輸入一個正整數陣列,把所有數字拼起來排出一個最小數

int minSort(int *nums, int length);

醜數

只包含因子 2,3,5的數叫做醜數

求按從小到大的順序,第1500個醜數

int ugly(int n)

第一個只出現一次的字元

在字串中查詢第一個只出現一次的字元

雜湊表:值為出現的次數 二次掃描

char find_appear_once_char(char *string)

陣列中的逆序對

陣列中的兩個數字如果前面一個數字大於後面的數字,這兩個數字組成一個逆序對。如:[7,5,6,4] 的逆序對:(7,5)(7,6)(7,4)(5,4)(6,4)

輸入一個陣列,求出這個陣列逆序對總數。

歸併排序 O(nlogn),空間O(n)

int reversePairs(int *data,int length)

兩個連結串列的第一個公共節點

長的連結串列先走k步

LinkListNode *common_node(LinkList *head1,LinkList head2);

數字在排序陣列中出現的次數

比如 {1,2,3,3,3,3,4,5}, 數字 3出現了4次

使用二分查詢找第一個3,和最後一個3出現的位置

int appear_count(int *nums,int length,int n);

二叉樹的深度

遞迴

int tree_depth(BTree *root);

陣列中只出現一次的數字

陣列中除了2個數字之外,其他的陣列都出現了2次,找出這兩個數

異或 二進位制

如果是隻有1個數字只出現一次,我們可以通過對陣列依次做異或運算。

如果我們能把原陣列分成2個子陣列,每個子陣列都包含一個只出現一次的數字,問題就能解決了。我們把陣列中的所有數字依次做異或操作,如果有2個數字不一樣,結果肯定不是0,且異或結果數字的二進位制表示中至少有一位是1(不然結果不就是0了)

  1. 在結果數字二進位制表示中找到第一個為1的位的位置,標記n
  2. 以二進位制表示中第n位是不是1為標準,把原陣列分成2個子陣列
void find_two_numbers_appear_once(int *data,int length,int *ouput)

和為s的兩個數字 VS 和為s的連續正數序列

有一個遞增排序陣列,和一個數字s,找出陣列中的2個數,使得和等於s。輸出任意一對即可

兩邊向中間掃描

void print_two_numbers(int *data,int length,int sum)

反轉單詞順序 VS 左旋轉字串

a. 翻轉句子中單詞的順序,但單詞內字元不變。如 『I am a student』 -> 『student. a am I』

先以單詞為單位翻轉,整個句子再次翻轉

char *reverse_by_word(char *string)

b. 左旋轉字串是把字串其那面的若干位轉義到字串的尾部。比如"abcedfsz"和數字2,結果是"cedfszab"

char *left_rotate_string(char *s,int n)

n個色子的點數

把n個色子丟地上,朝上一面的點數之和為s。輸入n,列印可能的值出現的概率

void print_sum_probability(int n)

撲克牌中的順子

從撲克牌從隨機抽5張牌,判斷是不是順子。A是1,JK是1113,大小王可以看出任意數字。

bool is_straight(int *data,int length)

圓圈中最後剩下的數字(約瑟夫問題)

0,1,...,n-1 這n個數字排成一個圓圈,從數字0開始從這個圓圈裡面刪除第m個數字,求出這個圓圈裡最後剩下的數字。

int last_remaining(unsigned int n,unsigned int m)

求 1+2+...+n

要求不用乘除法,for/while/if/else/switch等關鍵字及條件判斷語句

long long sum(unsigned int n);

不用加減乘除做加法

求2個整數之和

位運算

int sum(int,int)

不能被繼承的類


把字串轉換成整數

比如 "12343567754" -> 12343567754

NULL,空串,正負號,溢位

int strToInt(char str);

樹中2個結點的最低公共祖先

如果這個樹是二叉排序樹
如果不是二叉排序樹,但是有父節點指標
如果不是二叉樹,也沒有父節點指標

相關文章