java程序員面試筆試寶典之算法思路總結

1.        如何從鏈表中刪除重複元素(NO2_DeleteDup.java)

1)        遍歷鏈表,把遍歷到的值存儲到一個hashTable中,在遍歷過程中,若當前訪問的值在hashTable中,則刪除這個數據。

2)        雙重循環遍歷

2.        如何找出單鏈表中倒數第K個元素(NO3_FindEndK)

定義兩個指針p1、p2,p2比p1先行k-1步。當p2到達鏈表尾部時,p1爲所求。

3.        如何實現鏈表反轉(NO4_ReverseIteratively)

定義3個指針per,cur,next,改變指針的指向順序,即讓指針反轉。

next = cur.next;

 

cur.next = per;

per = cur;

cur = next;

4.        如何從尾到頭輸出單鏈表(NO5_PrintReversely)

每訪問一個節點,先遞歸輸出它後面的節點,在輸出該節點自身。

5.        如何尋找單鏈表的中間結點(NO6_SearchMid)

1)        定義兩個指針pFast,pSlow,從頭開始遍歷。

2)        pFast一次走兩步,pSlow一次走一步。

3)        當pFast到達鏈表尾部時,pSlow爲所求。

6.        如何檢查一個鏈表是否有環(NO7_IsLoop)

1)        定義兩個指針fast,slow;

2)        fast一次走2步,slow一次走一步,從頭開始遍歷

3)        沒走一次,比較fast和slow是否相等,若相等,則有環。若到結尾,都未相等,則無環。

7.        如何找到環的入口點(NO7_IsLoop)

1)        定義兩個指針pFast,pSlow,從頭開始遍歷。

2)        根據方法6,找到pFast,pSlow的相遇節點pFast。

3)        將pSlow指向頭結點,當pSlow與pFast再相遇時,二指針所指向的爲所求。

8.        如何在不知道頭指針的情況下刪除指定節點(NO8_DeleteNode)

1)        如果指定結點是尾結點,則無法刪除。因爲不能將前驅結點的next指針置爲空。

2)        若不是尾結點,則可以通過這個結點和後繼結點的值,然後再刪除後繼結點來完成。

9.        如何判斷兩個鏈表是否相交(NO9_IsIntersect)

若兩個鏈表相交,則兩個鏈表必然有相同的尾結點。

1)        遍歷鏈表h1,得到尾結點tail1。

2)        遍歷鏈表h2,得到尾結點tail2。

3)        若tail1==tail2,則相交,否則不想交

10.    如果兩個鏈表相交,如何找到它們相交的第一個結點(NO10_FirstMeetNode)

1)        分別計算兩個鏈表h1和h2 的長度len1和len2。

2)        對鏈表h1遍歷(len1-len2)個結點到結點p。

3)        此時同時遍歷兩個鏈表,直到遇到相同的結點爲止,這個結點爲所求。

11.    如何實現棧(NO11_MyStack)

可以採用數組與鏈表這兩種方法來實現棧

12.    如何用O(1)的時間複雜度求棧中最小元素(NO12_MyStack_MIN_O1)

實現兩個棧結構:一個棧elem用來存儲數據,另一個棧min用來存儲棧中最小元素。

1)        如果當前入棧元素比棧min的棧頂元素小,則把這個值壓入保存最小元素的棧中。

2)        在出棧時,如果當前入棧的元素恰好爲當前棧中的最小元素,棧min棧頂元素出棧,使得當前最小值變爲其入棧之前的那個最小值。

13.    如何用兩個棧模擬隊列操作(NO13_MyQueue)

有兩個棧,棧A和棧B,來模擬隊列Q

1)        入隊操作:棧A入棧。

2)        出隊操作:分兩種情況

a)        若棧B不爲空,則棧B出棧操作。

b)        若棧B爲空,棧A出棧並將其放入到棧B中,棧B出棧。

14.    如何用兩個隊列模擬棧的操作

兩個隊列,隊列A和隊列B,來模擬棧S

1)        入棧操作:隊列A入隊列

2)        出棧操作:

a)        隊列A中的元素出隊列,將其放入到隊列B中。

b)        隊列A中最後一個元素不入隊列B中,輸出該元素。

c)        隊列B中元素放入的隊列A中。

15.    選擇排序(NO14_SelectSort)

每一趟從未排序的隊列中選出最小的元素,與未排序隊列中的第一個位置交換,並將未排隊列的第一元素納入到已排隊列中。

16.    插入排序(NO15_InsertSort)

每趟把未排序隊列的第一個元素,插入到前面已排序隊列中。

17.    冒泡排序(NO16_BubbleSort)

從後往前,每趟把最小的元素放到前面。

18.    歸併排序(NO17_Merge)

歸併排序關鍵就2步:

1)        劃分半子表

a)        遞歸前一半

b)        遞歸後一半

2)        合併字表

a)        分別將開頭到中間和中間到結尾的元素放入到2個數組中(L和R)。

b)        每次從L和R中找出最小的放入到原數組中

19.    快排(NO18_QuitSort)

1)        分解。將a[i]放到正確的位置。將數組分成兩個非空子序列,分別是:a[i]之前和a[i]之後。

2)        分別遞歸求解兩個數組。

20.    希爾排序(NO19_ShellSort)

1)        選擇一個步長序列t1,t2,…,tk,滿足ti>tj(i<j),tk=1.

2)        按步長序列個數k,對待排序序列進行k趟排序。

3)        每趟排序,根據對應步長ti,將待排序列分割成ti個子序列,分別對各個子序列進行直接插入排序。

21.    堆排序(NO20_HeapSort)

1)        構建堆(不斷的調整堆)

a)        找到該父結點的兩個子節點。

b)        比較倆個子節點,找到最小的子節點。

c)        比較父結點和最小的子節點。若子節點小,則交換。

2)        交換堆頂元素與最後一個元素的位置,調整堆。每次調整堆使得最後一個元素在正確的位置。

22.    如何用移位操作實現乘法運算

把一個數向左移動n位,相當於把這個數乘以2的n次方。

23.    如何判斷一個數是否爲2的n次方(NO21_IsPower)

方法1:

1不斷的乘以2,即i左移1位。若i==n,則n是2的次方。若到了i>n時,則n不是2的次方。

方法2:

利用若n是2的次方,則n的二進制數只有一個1。即m=n&(n-1),m=0則是,否則不是。

24.    如何求二進制數中1的個數(NO22_CountOne)

利用沒執行一次n&(n-1)實際是將n所代表的二進制數中最後一個1去掉。

循環執行,直到n爲0爲止。

25.    如何尋找數組中的最小值與最大值(NO23_MaxMin)

維持兩個變量max和min,遍歷數組,用min標記最小值,用max標記最大值,每次取出一個元素,先與已找到的最小值比較,再與已找到的最大值比較。

26.    如何找出數組中第二大的數(NO24_SecondMax)

1)        定義兩個變量max和secmax。

2)        遍歷數組元素

a)        如果數組元素的值比最大數變量的值大,則secmax=max,max=a[i]。

b)        如果小於最大值,則與第二大值比較。若比第二大值大,則secmax=a[i];

27.    如何求最大子數組之和(NO25_MaxSubArray)

方法1:

1)        分別以a[0],a[1],…,a[n]開頭的最大子數組和。

2)        每次遍歷過程中,每加一個數後的和都要與maxSum比較,用maxSum標記最大子數組的和。

方法2:

         根據數組的最後一個元素a[n-1]與最大子數組的關係分爲以下3中情況:

1)        最大子數組包含a[n-1],即以a[n-1]結尾。

2)        a[n-1]單獨構成最大子數組。

3)        最大子數組不包含a[n-1],那麼求a[1,…,n-1]的最大子數組可以轉換爲求a[1,…,n-2]的最大子數組。

即遍歷數組,每一趟的最大子數組爲nAll=max{nEnd+a[i],a[i],nAll}

28.    如何確定最大子數組的位置(NO25_MaxSubArray)

1)        定義兩個變量,begin和end

2)        當nSum值小於0時,最大子數組重新計算。即nStart = i;

3)        當nSum值大於maxSum時,maxSum = nSum;begin=nStart;end=I;

29.    如何找到數組中重複元素最多的數(NO26_MostFrequentInArray)

1)        使用Map,將元素放入到Map中。重複一次value值+1;

2)        遍歷Map,找到value最大值,和對應的元素(key);

30.    如何求數組中兩兩相加等於20的組合種數

1)        對數組排序

2)        while(begin<end);如果begin+end<sum,則begin++。如果begin+end>sum,則end–;

如果begin+end=sum,則輸出並且begin++,end–。

31.    如何把一個數組循環右移k位

原數組根據k分成兩個數組,後k個元素爲一個數組,剩餘元素是一個數組。

1)        數組1逆序

2)        數組2逆序

3)        整個數組逆序

32.    如何找出數組中第K個最小的數(NO29_GetKMin)

採用快排的思想來實現

1)        選取一個數,快排放到正確的位置

2)        若它的位置是k-1,則爲所求。

3)        若它的位置<k-1,遞歸右半部分

4)        若它的位置>k-1,遞歸左半部分

33.    如何找出數組中只出現一次的數字(NO30_FindNoDouble)

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

利用任何一個數字異或自己都等於0的特點。從頭到尾異或數組中的每一個數字,那麼最終的結果剛好是隻出現1次的數字。

34.    如果題目改爲數組A中,一個整型數組裏除了一個數字之外,其他數字都出現了3次,那麼如何找出這個數字。(NO30_FindNoDouble)

1)        計算數組中所有數組對應的二進制數各個位置上出現1的次數。

2)        若某位上的結果不能被整除,則肯定目標數字在這一位上。

35.    如何找出數組中唯一重複的元素(NO31_FindDouble)

問題描述:數組a[N],1~N-1這N-1個數存放在a[N]中,其中某個數重複出現1次。要求每個數組元素只能訪問一次,並且不用輔助存儲空間。

1)        方法1:(a[N]全部數的和)-(1~N-1的和)=重複元素

2)        方法2:(a[N]全部數異或)異或(1~N-1異或)= 重複元素

36.    取值爲[1,n-1]含n個元素的整數數組,至少存在一個重複數,在O(n)時間內找出其中任意一個重複數。(NO31_FindDouble)

取反法:遍歷數組,如果遍歷數組中元素i,那麼把a[i]的值取反,如果i在數組中出現2次,那麼a[i]會經過兩次操作,a[i]的值跟原始的值相等。否則相反。

37.    如何用遞歸方法求一個整數數組的最大元素

遞歸求解“數組第一個元素”與“數組中其他元素所組成的子數組的最大值”的最大值

max(a[begin],findMax(a,begin+1))

38.    如何求數對只差的最大值

問題描述:數組中的一個數字減去它右邊子數組中的一個數字可以得到一個差值,求所有可能的差值中最大值。

二分法:把數組2部分,左數組和右數組(遞歸求解)

1)        求左數組最大差值

2)        求右數組最大差值

3)        求左數組最大值-右數組最小值

4)        設置最大值和最小值

5)        比較3個值,求最大值

39.    如何求絕對值最小的數(NO34_MinAbsoluteValue)

問題描述:有一個升序排列的數組,數組中可能有正數、負數或0,求數組中元素的絕對值最小的數。

1)        取數組的中間值a[mid]。

2)        若a[mid]=0,即爲所求。

3)        若a[mid]>0,若a[mid-1]<0,則比較2者絕對值,小的爲所求。否則遞歸左邊。

4)        若a[mid]<0,若a[mid+1]>0,則比較2者絕對值,小的爲所求。否則遞歸右邊。

40.    如何求數組中兩個元素的最小距離(NO35_MinDist)

問題描述:給定一個數組,數組中含有重複元素,給出兩個數n1和n2,求這兩個數字在數組中所出現位置的最小距離。

1)        定義兩個變量n1_index和n2_index

2)        每遇到一次n1或n2時,標記相應的index,比較求得最小的minDist。

41.    如何求指定數字在數組中第一次出現的位置(NO36_FindIndex)

問題描述:給定數組a={3,4,5,6,7,8,9,8},這個數組中鄰居元素之差爲1,給定數字9,它在數組中第一次出現的位置的下標爲8。

1)        從數組第一個元素開始,把當前位置的值與t比較。若相等則返回。

2)        若不想等,則從i+|t-a[i]|開始查找。

42.    如何對數組的兩個子有序段進行合併(NO37_VoidSort)

問題描述:數組a[0,mid-1]和a[mid,n-1]是各自有序的,對數組a[0,n-1]的兩個子有序段進行合併,得到a[0,n-1]整體有序。要求空間複雜度爲O(1)

基本思想是使a[0,mid-1]中的所有數都小於a[mid],再加上2數組各自有序,則a[0,n-1]爲所求。

1)        遍歷a[0,mid-1]數組,每一個元素都與a[mid]比較。

2)        若a[i]<a[mid],則繼續。若a[i]>a[mid],則

a)        交換a[i]與a[mid]。

b)        找到a[mid]在a[mid,n-1]中的位置。

43.    如何計算兩個有序整型數組的交集(NO38_FindMix)

1)        建立一個容器,該容器用來存放相交元素

2)        遍歷2個數組,分別比較兩個數組,移動值小的數組指針。若相等放入到容器中。

44.    如何判斷一個數組中數值是否是連續相鄰(NO39_IsContinuous)

問題描述:

1)        5個數值允許是亂序的,例如{8,7,5,0,6}

2)        0可以通配任意數值

3)        0可以出現多次

4)        全0算連續,只有一個非0算連續

思路:連續最主要的特點就是相鄰值相差1,只要涉及到連續這就是一個隱含條件

1)        遍歷數組,找到數組中最大值max和最小值min。

2)        若max-min<n-1,則表示連續。否則,不連續。

45.    如何求解數組中反序對的個數(NO40_ReverseCount)

問題描述:給定一個數組a,如果a[i]>a[j](i<j),那麼a[i]與a[j]被稱爲一個反序對,例如{1,5,3,2,6},共有(5,3)、(5,2)和(3,2)三個反序對。

分治思想:利用歸併排序的方法,在歸併排序中加一個計數器記錄逆序個數。

當L[]>R[]時,計數器reverseCount+=mid-(i-1)

46.    如何求解最小三元組距離(NO41_MinDist)

問題描述:即在3個升序數組中分別找一個數a[i]、b[j]、c[k]使得

Distance = max{|a[i]-b[j]|,|a[i]-c[k]|,|b[j]-c[k]|}值最小。

基本思想:假設取出來的3個數爲a,b,c,且a<=b<=c。那麼c-a爲所求。

1)        從3個數組中取出第一個元素

2)        求curdist,軟後minDist比較,求得最小的值。

3)        3個數中最小的數對應的數組,移動該數組的下標。

4)        直到其中一個數組遍歷完畢爲止。

47.    如何實現字符串的反轉(NO42_SwapWord)

問題描述:把一個句子的單詞進行反轉,例如“how are you”,翻轉後爲“you are how”。

1)        整個字符串反轉“uoy era woh”

2)        每個單詞反轉“you are how”

48.    如何判斷兩個字符串是否由相等的字符組成(NO43_Compare)

問題描述:有相同的字符組成是指組成兩個字符串的字母以及各個字母的個數是一樣的,僅順序不同而已。

1)        將2個字符串轉化爲2個byte數組。

2)        對兩個byte數組排序

3)        將2個byte數組轉化爲字符串

4)        比較兩個字符串

49.    如何刪除字符串中重複的字符(NO44_RemoveDup)

問題描述:刪除字符串中重複的字符

1)        申請一個大小爲256的int型數組,用來記錄每個字符出現的次數,初值爲0。

2)        字符的編號作爲數組的下標,在遍歷字符數組時,如果這個字符出現次數爲0,那麼把它置爲1.如果這個字符出現次數爲1,把這個字符串置爲’\0’。

3)        遍歷字符串,去掉’\0’。

50.    如何統計一行字符中有多少個單詞(NO45_WordCount)

1)        判斷是一個單詞的標準是:空+非空=>一個單詞,計數器+1;

2)        用word標記連續出現的空。Word=0,表示前一個字符是空;若word=1,意味着前一個字符非空。

51.    如何按要求打印數組的排列情況(NO46_FirstSearch)

問題描述:針對1、2、2、3、4、5這6個數字,寫一個函數,打印出所有不同的排列,要求“4”不能在第3位,“3”與“5”不能相連。

1)        用1、2、2、3、4、5這6個數作爲6各節點,構造一個無向連通圖。除了“3”與“5”不連通外,其他都連通。

2)        分別對這6個結點出發對圖做深度優先遍歷。若第三個數不是“4”,則把這個數字放到集合Set中。

3)        遍歷Set集合,打印所有結果。

52.    如何輸出字符串的所有組合(NO47_HowCombin

問題描述:假設字符串中的所有字符都不重複,如何輸出字符串的所有組合

思路:用長度爲n的01字符串表示輸出結果中包含某個字符。例如:001表示不含a,b,只含c。

1)        把第一位的1變爲0;

2)        把第一個0變爲1;

3)        把變化後的應該顯示的字符放到cache中

4)        輸出結果

53.    如何實現二叉排序樹(NO48_BinaryTree)

1)        創建一個結點

2)        比較data與當前結點data的大小

a)        若data>curNode.data,curNode = curNode.right

b)        否則,curNode = curNode.left;

3)        直到當前結點爲空時,parent.left = newNode或parent.right =newNode;

54.    如何實現層序遍歷二叉樹(NO48_BinaryTree)

主要思路:藉助一個隊列實現

1)        把根節點放入到隊列中

2)        從隊列中取出一個元素,輸出data,然後將孩子結點放入隊列中。

3)        直到隊列爲空。

55.    已知先序遍歷和中序遍歷,如何求後序遍歷(NO48_BinaryTree)

1)        先序序列第一個爲根結點

2)        以根結點在中序中定位

3)        左子樹=中序中左部份構建左子樹

4)        右子樹=中序中右部份構建右子樹

5)        head.left = 左子樹

6)        head.right = 右子樹

56.    如何求二叉樹中結點的最大距離(NO48_BinaryTree)

問題描述:結點距離是指這兩個結點之間邊的個數。寫一個程序求一棵二叉樹中相距最遠的兩個結點之間的距離。

         結點內容加兩個變量:leftMaxDis和rightMaxDis;

1)        初始化根節點

2)        遞歸左子樹

3)        遞歸右子樹

4)        求左子樹中距離根節點的最大距離

5)        求右子樹中距離根節點的最大距離

6)        獲取最大距離max = root.leftMaxDis+root.rightMaxDis

57.    如何消除嵌套的括號(NO49_ChangeStr)

問題分析:給定一個如下字符串(1,(2,3),(4,(5,6),7))

1)        判斷表達式中只有數字、逗號和括號這幾種字符,如果有其他字符出現則是非法的。

2)        判斷括號是否匹配,若碰到“(”,則把括號的計數器+1;

3)        如果碰到“)”,此時在判斷計數器是否大於1。若是,則把計數器-1,否則非法表達式。

58.    如何不使用比較運算符就可求出兩個數的最大值和最小值

1)        Max(a,b) = (a+b+Math.abs(a-b))/2;

2)        Min(a,b) =(a+b-Math.abs(a-b))/2;

 

 

 

 

 

 

 

 

 

59.    給定一個整數N,那麼N的階乘N!末尾有多少個0?(NO50_CountZero)

思路:,那麼N!末尾有M個0。對N!進行質因數分解,,由10=2*5,故M=min(X,Y)。由能被2整除的數出現的頻率比能被5整除的頻率大,故M=Z。

即計算1~N的因式分解中5的指數,然後求和。

總結:N!中含質因數5的個數爲所求

60.    求N!的二進制表示中最低位1的位置(NO51_LowestOne)

N!中含質因數2的個數+1爲所求。

61.    一個ID的發帖數超過總貼數的一半,如何找出這個ID

思路:若“水王”的ID出現半數以上,則在ID數組中每次刪除2個不同的ID,那麼當遍歷一次後最後剩下的變爲所求。

62.    寫一個函數f(N),返回1到N之間出現1的個數,比如f(12)=5;

設N=abcde。從低位到高位計算每一位出現1的個數,累計的和爲所求。

這樣講N分爲3部分:低位lower、當前位cur、高位high。當前位出現1的個數與當前位的值有關。

Cur=0時:出現1的個數=high*當前位數

Cur=1時:出現1的個數=high*當前位數+lower+1

Cur>1時:出現1的個數=(high+1)*當前位數

其中:lower=n-(n/factor)*factor

           Cur=(n/factor)%10

           Hight=n/(factor*10)

63.    滿足條件“f(N)=N”的最大的N是多少。

 

 

 

点赞