程序員面試題精選100題:11-40解題報告

程序員面試題精選100題(11)-求二元查找樹的鏡像[數據結構]  

題目:輸入一顆二元查找樹,將該樹轉換爲它的鏡像,即在轉換後的二元查找樹中,左子樹的結點都大於右子樹的結點。用遞歸和循環兩種方法完成樹的鏡像轉換。

例如輸入:

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

輸出:

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

非遞歸就是使用棧模擬。

=====================================================================

程序員面試題精選100題(12)-從上往下遍歷二元樹[數據結構]

 題目:輸入一顆二元樹,從上往下按層打印樹的每個結點,同一層中按照從左往右的順序打印。

例如輸入

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

輸出8   6   10   5   7   9   11。

分析:層次遍歷,使用隊列存儲數據。

我們知道樹是圖的一種特殊退化形式。同時如果對圖的深度優先遍歷和廣度優先遍歷有比較深刻的理解,將不難看出這種遍歷方式實際上是一種廣度優先遍歷。因此這道題的本質是在二元樹上實現廣度優先遍歷

 

==============================================================================

程序員面試題精選100題(13)-第一個只出現一次的字符[算法]  

題目:在一個字符串中找到第一個只出現一次的字符。如輸入abaccdeff,則輸出b

 

 

分析:1.hash_map

2.因爲是字符0-255,所以我們可以用256長度的數組作爲hash,每個元素記錄對應ascii碼個數。

==============================================================================

程序員面試題精選100題(14)-圓圈中最後剩下的數字[算法]  

題目:n個數字(0,1,…,n-1)形成一個圓圈,從數字0開始,每次從這個圓圈中刪除第m個數字(第一個爲當前數字本身,第二個爲當前數字的下一個數字)。當一個數字刪除後,從被刪除數字的下一個繼續刪除第m個數字。求出在這個圓圈中剩下的最後一個數字。

分析:這是著名的約瑟夫環問題。其實自己推也不太會,先記下遞歸關係吧。

f(n,m)=f’(n-1,m)=[f(n-1,m)+m]%n

 

========================================================================

程序員面試題精選100題(15)-含有指針成員的類的拷貝[C/C++/C#]  

分析:指針淺拷貝導致的指針懸掛問題

解決方法:1.私有化,不能複製構造,賦值操作,這肯定不是上策

2.每個對象保留一份數據副本

3.自己實現引用計數,多個對象共同指向同一數據內存

4.直接使用boost的shard_ptr

有時間要總結下boost的智能指針了。

========================================================================

 

程序員面試題精選100題(16)-O(logn)求Fibonacci數列[算法]  

分析:

1.純遞歸 O(2^n)

2.記憶化遞歸,空間換時間O(n)

3.遞推,類似於DP,時間O(n),空間O(1)

4.logn的真想不到,智商拙計啊,還是看答案吧:

{f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0}n-1

f(n)爲矩陣的第一個元素

        /  an/2*an/2                     n爲偶數時
an=
        \  a(n-1)/2*a(n-1)/2            n爲奇數時

========================================================================

 

程序員面試題精選100題(17)-把字符串轉換成整數[算法]  

分析:這個真不一定能寫對,我想說能直接用atoi嗎?哈

========================================================================

程序員面試題精選100題(18)-用兩個棧實現隊列[數據結構]  

已經提過了在第二題

 

========================================================================

程序員面試題精選100題(19)-反轉鏈表[數據結構]  

題目:輸入一個鏈表的頭結點,反轉該鏈表,並返回反轉後鏈表的頭結點。

分析:假設n之前的n-1個都已經逆序了,pnext=n->next,n->next=ppre;

然後更新ppre爲n,n爲pnext

========================================================================

 

程序員面試題精選100題(20)-最長公共子串[算法]  

典型DP,算法導論上有詳細介紹

如果我們記字符串Xi和Yj的LCS的長度爲c[i,j],我們可以遞歸地求c[i,j]:

          /      0                               if i<0 or j<0
c[i,j]=          c[i-1,j-1]+1                    if i,j>=0 and xi=xj
         \       max(c[i,j-1],c[i-1,j]           if i,j>=0 and xi≠xj

 

 

擴展:

如果題目改成求兩個字符串的最長公共子字符串,應該怎麼求?

最長公共字串:不連續;最長公共子字符串:連續

DP[i][j]定義爲以I,j爲結尾的最長公共子字符串長度。

狀態轉移方程爲DP[i][j]=DP[i-1][j-1]if a[i]==b[j] else = 0;

最終結果爲max{DP[i][j]},其中可以放入到狀態遞推中不必單獨O(n^2)循環。

初始:DP[0][j],DP[i][0]=0,浪費一個空間,從1開始有效。

結果序列也好求:記錄max對應的i和j,然後依次遞減,知道不等即結束。

 

========================================================================

程序員面試題精選100題(21)-左旋轉字符串[算法]  

翻轉句子中的單詞已經討論過了。

 

========================================================================

程序員面試題精選100題(22)-整數二進制表示中1的個數[算法]  

位操作果然很奇妙。

int NumberOf1_Solution1(int i)
{
      int count = 0;
      while(i)
      {
            if(i & 1)
                  count ++;

            i = i >> 1;
      }

      return count;
}

這個思路當輸入i是正數時沒有問題,但當輸入的i是一個負數時,不但不能得到正確的1的個數,還將導致死循環。以負數0x80000000爲例,右移一位的時候,並不是簡單地把最高位的1移到第二位變成0x40000000,而是0xC0000000。這是因爲移位前是個負數,仍然要保證移位後是個負數,因此移位後的最高位會設爲1。如果一直做右移運算,最終這個數字就會變成0xFFFFFFFF而陷入死循環。

解決方法:

不右移I,可以等價的左移1。。。。很巧妙

上述算法複雜度爲i的位數,下面方法可以降到i中1的個數:

另外一種思路是如果一個整數不爲0,那麼這個整數至少有一位是1。如果我們把這個整數減去1,那麼原來處在整數最右邊的1就會變成0,原來在1後面的所有的0都會變成1。其餘的所有位將不受到影響。舉個例子:一個二進制數1100,從右邊數起的第三位是處於最右邊的一個1。減去1後,第三位變成0,它後面的兩位0變成1,而前面的1保持不變,因此得到結果是1011。

我們發現減1的結果是把從最右邊一個1開始的所有位都取反了。這個時候如果我們再把原來的整數和減去1之後的結果做與運算,從原來整數最右邊一個1那一位開始所有位都會變成0。如1100&1011=1000。也就是說,把一個整數減去1,再和原整數做與運算,會把該整數最右邊一個1變成0。那麼一個整數的二進制有多少個1,就可以進行多少次這樣的操作。

擴展:

如何用一個語句判斷一個整數是不是二的整數次冪?

是2的次冪,就是之含有一個1,那就判斷i&(i-1)是不是0就可以了。。。。

========================================================================

程序員面試題精選100題(23)-跳臺階問題[算法]  

Fibonacci序列,怎麼這麼像奧數題。。。。主要考察分析抽象問題能力,遞推關係。。。

========================================================================

程序員面試題精選100題(24)-棧的push、pop序列[數據結構]  

題目:輸入兩個整數序列。其中一個序列表示棧的push順序,判斷另一個序列有沒有可能是對應的pop順序。爲了簡單起見,我們假設push序列的任意兩個整數都是不相等的。

比如輸入的push序列是1、2、3、4、5,那麼4、5、3、2、1就有可能是一個pop系列。因爲可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,這樣得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。

這道題的一個很直觀的想法就是建立一個輔助棧,每次push的時候就把一個整數push進入這個輔助棧,同樣需要pop的時候就把該棧的棧頂整數pop出來。

如果我們希望pop的數字正好是棧頂數字,直接pop出棧即可;如果希望pop的數字目前不在棧頂,我們就到push序列中還沒有被push到棧裏的數字中去搜索這個數字,並把在它之前的所有數字都push進棧。如果所有的數字都被push進棧仍然沒有找到這個數字,表明該序列不可能是一個pop序列。

========================================================================

 

程序員面試題精選100題(25)-在從1到n的正數中1出現的次數[算法]  

題目:輸入一個整數n,求從1到n這n個整數的十進制表示中1出現的次數。

例如輸入12,從1到12這些整數中包含1 的數字有1,10,11和12,1一共出現了5次。

分析:這是一道廣爲流傳的google面試題。用最直觀的方法求解並不是很難,但遺憾的是效率不是很高;而要得出一個效率較高的算法,需要比較強的分析能力,並不是件很容易的事情。當然,google的面試題中簡單的也沒有幾道。

我只會暴力解法,智商拙計啊。。。。高效的推導,略

========================================================================

程序員面試題精選100題(26)-和爲n連續正數序列[算法]  

題目:輸入一個正數n,輸出所有和爲n連續正數序列。

例如輸入15,由於1+2+3+4+5=4+5+6=7+8=15,所以輸出3個連續序列1-5、4-6和7-8。

分析:起始值不超過(n+1)/2,最小2個元素

1.      暴力:sum(I,i+1…n)判斷是否爲n,對於(n+1)/2個I,複雜度爲O(n^2)

2.      沒有使用連續這個特徵。(i+j)(j-i+1)/2=n,可以解出j,循環i判斷j是否合理即可解決,複雜度O(n)

3.      這種接法是爲了引出下面的擴展問題,同樣的思路而且不用有序。這道題和本面試題系列的第10有些類似。我們用兩個數small和big分別表示序列的最小值和最大值。首先把small初始化爲1,big初始化爲2。如果從small到big的序列的和大於n的話,我們向右移動small,相當於從序列中去掉較小的數字。如果從small到big的序列的和小於n的話,我們向右移動big,相當於向序列中添加big的下一個數字。一直到small等於(1+n)/2,因爲序列至少要有兩個數字。這種方法相對於第二種複雜度一樣的,但big會多走一些步。

擴展:

google面試題:無序數組是否存在連續幾個數的和等於N

有一串沒有排好序的正整數,中間可能有重複,查看這串數中是否存在連續的幾個數之和爲N

分析:1.暴力O(n^3)

2.優化下f(I,n)=f(I,n-1)+a[i][n]一趟O(n),對於n個i總複雜度爲O(n^2)

3.快慢指針I,j。如果小於K,j增加;否則i增加,需要注意I==J的情況(當sumN時,要分兩種情況,i==j,或者i!=j,主要是因爲可能數組中的某個元素自己就比N大,這樣的話最終會走到i==j這一步,這時就得跳過當前自身數值都會比N大的元素,直接採用下一個元素的值作爲sum,i和j的值也都做相應的更新)ij不回溯,最多2n步,所以複雜度爲O(n)

========================================================================

程序員面試題精選100題(27)-二元樹的深度[數據結構]  

題目:輸入一棵二元樹的根結點,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度爲樹的深度。

例如:輸入二元樹:

                                            10
                                          /     \
                                        6        14
                                      /        /   \
                                    4         12     16

輸出該樹的深度3。

分析:遞歸。

非遞歸:先序遍歷。參考http://blog.csdn.net/nanjunxiao/article/details/9088133

========================================================================

 

程序員面試題精選100題(28)-字符串的排列[算法]  

題目:輸入一個字符串,打印出該字符串中字符的所有排列。例如輸入字符串abc,則輸出由字符a、b、c所能排列出來的所有字符串abc、acb、bac、bca、cab和cba。

分析:遞歸,交換。參考http://blog.csdn.net/nanjunxiao/article/details/9081487

#include<iostream>

#include<stdio.h>

#include<assert.h>

usingnamespace std;

 

voidswap(char* a,char* b)

{

    char tmp = *a;

    *b = tmp;

    *a = *b;

}

 

voidPermutation(char* pStr, char* pBegin)

{

    assert(pStr && pBegin);

    if(*pBegin == '\0')

        printf("%s\n",pStr);

    else

    {

        for(char* pCh = pBegin; *pCh != '\0';pCh++)

        {

            swap(*pBegin,*pCh);

            Permutation(pStr, pBegin+1);

            swap(*pBegin,*pCh);

        }

    }

}

 

intmain(void)

{

    char str[] = "abcd";

    Permutation(str,str);

    return 0;

}

有重複元素情況:參考http://blog.csdn.net/nanjunxiao/article/details/9081487

擴展:

組合問題:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

 

intstate[5] = {0};

 

voidprint(char* str)

{

    int i;

    for(i=0; i<strlen(str); ++i)

    {

       if(state[i] )

           printf("%c",str[i]);

    }

    printf("\n");

}

 

voiddigui(char* str,int b,int e)

{

    if(b == e)

    {

       print(str);

       return ;

    }

    state[b] = 1;//yes

    digui(str,b+1,e);

    state[b] = 0;//no

    digui(str,b+1,e);

}

 

intmain()

{

    char *str = "abcef";

    digui(str,0,strlen(str));

    return 0;

}

 

擴展2:輸入一個含有8個數字的數組,判斷有沒有可能把這8個數字分別放到正方體的8個頂點上,使得正方體上三組相對的面上的4個頂點的和相等。

===========================================================================

程序員面試題精選100題(29)-調整數組順序使奇數位於偶數前面[算法]  

解法:前後指針向中間靠攏,類似於快排的partition

討論:

上面的代碼有三點值得提出來和大家討論:

1.函數isEven判斷一個數字是不是偶數並沒有用%運算符而是用&。理由是通常情況下位運算符比%要快一些;

2.這道題有很多變種。這裏要求是把奇數放在偶數的前面,如果把要求改成:把負數放在非負數的前面等,思路都是都一樣的。

3.在函數Reorder中,用函數指針func指向的函數來判斷一個數字是不是符合給定的條件,而不是用在代碼直接判斷(hardcode)。這樣的好處是把調整順序的算法和調整的標準分開了(即解耦,decouple)。當調整的標準改變時,Reorder的代碼不需要修改,只需要提供一個新的確定調整標準的函數即可,提高了代碼的可維護性。例如要求把負數放在非負數的前面,我們不需要修改Reorder的代碼,只需添加一個函數來判斷整數是不是非負數。這樣的思路在很多庫中都有廣泛的應用,比如在STL的很多算法函數中都有一個仿函數(functor)的參數(當然仿函數不是函數指針,但其思想是一樣的)。如果在面試中能夠想到這一層,無疑能給面試官留下很好的印象。

===========================================================================

程序員面試題精選100題(30)-賦值運算符重載函數[C/C++/C#]  

C++基礎,沒啥說的。。。

===========================================================================

程序員面試題精選100題(31)-從尾到頭輸出鏈表[數據結構]  

分析:1.之前的反轉鏈表,然後從新的頭到尾輸出。缺點:額外操作,破壞鏈表結構了。

2.放入棧中,彈棧輸出即可。

3.遞歸。

擴展:1.       從尾到頭輸出一個字符串;

2.       定義一個函數求字符串的長度,要求該函數體內不能聲明任何變量。

===========================================================================

程序員面試題精選100題(32)-不能被繼承的類[C/C++/C#]  

題目:用C++設計一個不能被繼承的類。

分析:這是Adobe公司2007年校園招聘的最新筆試題。這道題除了考察應聘者的C++基本功底外,還能考察反應能力,是一道很好的題目。

分析:http://blog.csdn.net/nanjunxiao/article/details/9112973

1.私有構造、析構函數可以實現。

2.更好的方法友元+虛繼承。

C++虛繼承的作用  

C++虛繼承可以防止多重繼承產生的二義性問題。

上面的試驗結果表面,在多重繼承的時候,如果父類中有同名的成員變量(類似這篇文章中談及的例子),爲了防止二義性,一般要採用虛繼承的方式,並且最右邊的基類中的那個成員變量會出現在派生類對象中

===========================================================================

程序員面試題精選100題(33)-在O(1)時間刪除鏈表結點[數據結構]  

題目:給定鏈表的頭指針和一個結點指針,在O(1)時間刪除該結點。

腦筋急轉彎。。。

(2)給定的要刪除的結點是鏈表的頭結點情況。

===========================================================================

程序員面試題精選100題(34)-數組中只出現一次的數字[算法]  

題目:一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)。

分析:這是一道很新穎的關於位運算的面試題。

限定空間複雜度爲O(1)了,不能使用hash_map了。

異或運算,最終是a^b,關鍵在怎麼把數組分成兩部分,兩部分分別異或就得出a,b了。

===========================================================================

程序員面試題精選100題(35)-兩鏈表的第一個公共結點[數據結構]  

題目:兩個單向鏈表,找出它們的第一個公共結點。

分析:長的先走l-s步,再一起走,

擴展:如果有環呢????

===========================================================================

程序員面試題精選100題(36)-在字符串中刪除特定的字符[算法]  

題目:輸入兩個字符串,從第一字符串中刪除第二個字符串中所有的字符。例如,輸入”They are students.”和”aeiou”,則刪除之後的第一個字符串變成”Thy r stdnts.”。

分析:快慢指針。查找使用hash,因爲是字符,可以申請256大小數組。

===========================================================================

序員面試題精選100題(37)-尋找醜數[算法]  

題目:我們把只包含因子

2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因爲它包含因子7。習慣上我們把1當做是第一個醜數。求按從小到大的順序的第1500個醜數。

分析:這是一道在網絡上廣爲流傳的面試題,據說google曾經採用過這道題。

很巧妙,第一次想不到,只會暴力法。。。智商拙計。。。。

 

===========================================================================

程序員面試題精選100題(38)-輸出1到最大的N位數[算法]  

題目:輸入數字n,按順序輸出從1最大的n位10進制數。比如輸入3,則輸出1、2、3一直到最大的3位數即999。

分析:1.直接,可能溢出

2.大整數遞增,短時間很難寫完寫正確。

3.沒想到的遞歸啊。。。。

===========================================================================

程序員面試題精選100題(39)-顛倒棧[數據結構]  

題目:用遞歸顛倒一個棧。例如輸入棧{1, 2, 3, 4, 5},1在棧頂。顛倒之後的棧爲{5, 4, 3, 2, 1},5處在棧頂。

題目要求遞歸。

1.      pop棧頂

2.      遞歸反轉剩下的,

3.      將棧頂添加到棧底。

這個第三步卡住了,沒想到效率高的算法,只想到從棧頂到棧底上一個元素依次後移一位,然後將棧頂放到棧底,但是棧不提供隨機訪問吶。看完答案恍然大悟,還是遞歸吶,尼瑪,題目也要求遞歸呀。我們需要考慮的另外一件事情是如何把一個元素e放到一個棧的底部,也就是如何實現AddToStackBottom。這件事情不難,只需要把棧裏原有的元素逐一pop出來。當棧爲空的時候,push元素e進棧,此時它就位於棧的底部了。然後再把棧裏原有的元素按照pop相反的順序逐一push進棧。

注意到我們在push元素e之前,我們已經把棧裏原有的所有元素都pop出來了,我們需要把它們保存起來,以便之後能把他們再push回去。我們當然可以開闢一個數組來做,但這沒有必要。由於我們可以用遞歸來做這件事情,而遞歸本身就是一個棧結構。我們可以用遞歸的棧來保存這些元素。

複雜度爲O(n^2),每個AddToStackBottom複雜度就爲O(n)

這題其實就是考察對遞歸的熟悉程度。其實完全可以先pop進數組,然後在逆序push進原棧即可,複雜度只有O(n)。

===========================================================================

程序員面試題精選100題(40)-撲克牌的順子[算法]  

題目:從撲克牌中隨機抽5張牌,判斷是不是一個順子,即這5張牌是不是連續的。2-10爲數字本身,A爲1,J爲11,Q爲12,K爲13,而大小王可以看成任意數字。

         分析:這題目很有意思,是一個典型的寓教於樂的題目。

這題不難,考察抽象能力。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章