python數據結構與算法刷題

說不清楚,只能看代碼理解的用紅色標出 


查找算法:查找較排序來說較簡單,不外乎順序查找和二分查找、哈希表查找和二叉排序樹查找。(很多面試官喜歡讓應聘者寫出二分查找(如test53)的代碼)【注意:二分查找傳入的必須是排好序的數組】

排序算法:面試官經常會要求應聘者比較插入排序、冒泡排序、歸併排序、快速排序等不同算法的優劣,作者強烈建議應聘者在準備面試時,一定要對各種排序算法的特點爛熟於心,能夠從額外的空間消耗、平均時間複雜度和最差時間複雜度等方面取標膠他們的優缺點。(很多面試官喜歡讓應聘者寫出快速排序、歸併排序(test51考察的就是歸併排序)的代碼) 

樹的遍歷:通常分爲兩種:深度優先和廣度優先。深度優先又細分爲三種:前序遍歷、中序遍歷和後序遍歷,對應的程序可以用遞歸實現,也可以用循環實現(循環實現的方法有點難)。一種有特殊順序的二叉樹稱爲二叉搜索樹。(很多面試官喜歡讓應聘者寫出紅黑樹、B+樹的代碼) 


面試題7:重建二叉樹

先考慮一般情況,用遞歸的方式創建二叉樹,再考慮特殊的,兩種情況:先/中序遍歷都是空;先/中序遍歷都只有一個節點;

創建好二叉樹後,進行特殊情況的測試,兩種特殊情況:①根節點爲空;②先序遍歷和中序遍歷序列不匹配;

最後用先序遍歷的方式打印一下二叉樹(在本代碼中遍歷二叉樹時,會出現空值,可在打印前加個條件語句判斷一下,具體原因在demo中有解釋)

思路:先根據前序遍歷找到根節點,然後再根據根結點的將中序遍歷且分爲左右兩顆子樹,再根據子樹的長度切分前序遍歷,從而切分出小的先序遍歷和中序遍歷,然後循環以遞歸的方法解題

面試題8:二叉樹的下一個節點

題目:給定一顆二叉樹和其中的一個節點,找出中序遍歷的下一個節點。其中已知該節點的左右子節點和該節點的父節點。

思路:
先在紙上畫一顆滿二叉樹

  1. 情況1:如果該節點有右子樹,則下一個節點就是右子樹的最左節點(用while尋找右子樹的最左節點);
  2. 情況2:如果該節點沒有右子樹,且其是左子樹下的,則下一個節點就是其父節點;或者其是右子樹下的,則下一個節點就要一直往上溯源,否則返回None

面試題9:用兩個棧實現隊列

題目:用兩個棧實現一個隊列。隊列的聲明如下,實現它的兩個函數appendTail和deleteHead, 分別完成在隊列尾部插入節點和在隊列頭部刪除節點。

思路:

  1. 首先清除一點:列表類似於棧,所以可以用列表創建兩個棧stack;
  2. 其次,在添加元素時都添加到stack1;在輸出時,判斷stack2是否爲空,爲空則把stack1的元素pop進stack2,若stack2不爲空,則直接pop stack2的元素;

這樣就通過兩個棧構造出了隊列。

面試題10:斐波那契數列
題目一:求斐波那契數列的第n項。寫一個函數,輸入n,求斐波那契數列(Fibonacci)的第n項。(結合第二部分的12,也是斐波那契數列但是多了一種臨時變量的解法)
【斐波那契數列:f_0=0, f_1=1, f_2=f_0+f_1=1, f_3=f_2+f_1=1+1=2, f_4=f_3+f_2=2+1=3, 以此類推】

題目二:青蛙跳臺階問題。一隻青蛙一次可以跳上1級臺階,也可以跳上2級臺階,求一隻青蛙跳上n級臺階總共有多少總跳法。

思路:
題目一:

  1. 首先想到的方法就是用遞歸的方式,從上至下的求解,而且遞歸的方式demo簡捷,但是遞歸的方式每次都會重新計算一遍,會增加徒勞的計算量;
  2. 進一步升級用循環的方式從下至上求解,前面的值可以保存下來供後面使用,算法複雜度爲O(n), 而且性能更優計算n=3000都沒問題,而遞歸n=30就開始卡了;

題目二:
這道題的關鍵在於怎麼把該問題轉換爲斐波那契數列的問題。
把n級臺階的跳法看作n的函數,記爲f(n), 若第一次跳1級,剩下f(n-1); 若第一次跳2級,剩下f(n-2), 所以n級臺階的跳法爲f(n)=f(n-1)+f(n-2)

相關題目:用一個2*1的矩形去覆蓋2*8的矩形,問有多少種覆蓋方法?(類似於unknow3矩形覆蓋這個題)

總結(僅供參考):可以轉換爲斐波那契數列的問題通常具有以下特徵:

  1. 涉及1或2(倍數也行);
  2. 最後問有多少種方法;
  3. 遇到滿足上述條件的,一定要用循環去解題,用遞歸性能嚴重不足。

面試題11:旋轉數組中的最小數字

旋轉數組中的最小數字。把一個數組最開始的若干元素搬到數組的末尾,則稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素,如[3,4,5,1,2]爲[1,2,3,4,5]的旋轉,該數組的最小元素爲1.

思路:

  1. 先考慮較爲一般的情況,[4,5,6,1,2,3],找兩個遊標,分別標在第一個、最後一個元素,再找一個遊標標在中間元素,根據旋轉數組的本身特點,中間元素與cur1、cur2比較,若大於等於cur1的元素,則將cur1重標在此位置;若小於等於cur2的元素,則將cur2重標在此位置,以此循環縮小範圍;
  2. 在進一步考慮特殊情況:①把0個元素搬到數組的末尾,這種只要確定cur1的元素小於cur2的元素且cur1的元素不等於mid的元素(爲保證該數組的數字不全相同), 則輸出cur1;②cur1、cur2、mid指向的元素都相等,此時只能使用順序查找的方法尋找最小元素【注意:在進入順序查找進行分析之前,先用set判斷一下該數組是否只有一類元素】

面試題12:矩陣中的路徑

矩陣中的路徑。設計一個函數用來判斷一個矩陣中是否存在一條包含某字符串所有字符的路徑。路徑可以從矩陣的任意一格開始,每一步都可以在矩陣中向左、右、上、下移動一格。如果一條路徑中包含了矩陣的某一格,那麼該路徑不能進入該格子。【提示:用的是回溯法,回溯法適合有多個步驟且每個步驟都有很多選項的問題,通過遍歷式的嘗試找到最優的可行方案】

思路:採用回溯法進行解題,每到一個格子都有上下左右四步走法,用循環用第一行第一列的元素開始往下尋找,若該位置的元素等於要尋找的元素時進入遞歸以查看其上下左右是否能匹配下一個元素,否則返回上一級;其實就是找到首字母后纔會進入遞歸,進一步判斷其上下左右是否有符合的,否則重新返回到for循環,尋找下一個匹配成功的首字母。【稍微有點繞】

面試題13:機器人的運動範圍。

機器人的運動範圍。地上有一個m行n列的格子。一個機器人從座標(0,0)的位置開始移動,每次可以向左右上下移動一格,但不能進入行座標和列座標位數之和大於k的格子。如k=18時,機器人可以進入(35,37), 但不能進入(35,38)。問該機器人能到達多少個格子?

  1. 思路:
  2. 對比:矩陣中的路徑中使用了for循環先匹配首字母,匹配成功後在其上下左右匹配下一個字母,匹配成功後,再匹配下一個字母;否則表明該路徑不通,重新用for匹配首字母;    機器人的運動範圍中沒有使用for,因爲這個題不用先匹配首字母再匹配下一個,相當於首字母給出,需要不斷以上下左右的方式尋找滿足條件的下一個,直至到路的盡頭爲止,具體還得結合demo理解。
  3. 問題:movingCountCore()的遞歸沒有繞明白,check通過進入一個點後,開始上下左右測試,先上遞歸,上面如果通過check,在這一個點再上下左右遞歸,直到到達盡頭爲止【有點不撞南牆不回頭的意思,在一個滿足的點上,沒有找到盡頭是不會結束遞歸的】

面試題14:剪繩子。

剪繩子。給你一根長度爲n的繩子,請把繩子剪成m段(m、n都是整數,m、n>1, 【可知:m的取值範圍爲大於等於2,小於等於n】),每段繩子的長度記爲k[0]、k[1]、k[2]、...、k[m]。請問k[0]*k[1]*k[2]*...*k[m]的最大乘積是多少?例如當繩子的長度爲8時,可以剪長度爲爲2、3、3的三段,此時得到的最大乘積爲18。

  1. 思路:兩種方法。①用動態規劃的方法,自下而上的解題(也可以用遞歸的方式自上而下解題),關鍵在於li的定義及其存放的元素的定義(li裏的第i個元素指長度爲i時的最大乘積,其中0,1,2,3給出的是剪0刀時的最優解),循環中的i表示當前繩子的長度,j表示剪一刀下去,其中一段的長度,則i-j表示另一端的長度;②用貪婪算法進行解題。
  2. 難點:要能把一個具體的場景抽象成一個能用動態規劃或貪婪算法解決的模型,具體參考書中6.4節。

 貪婪算法解題時,爲什麼是3的k次方,如下圖所示:

面試題15:二進制中1的個數

二進制中1的個數。實現一個函數,輸入一個整數,輸出該數二進制中1的個數。如9的二進制爲1001,有2位是1,因此返回2。

  • 注:Python中沒法做,用書上的左移解題時,python中並不會說到64/32結束,會一直左移下去,那麼這個數就會一直變大;關鍵是負數不好處理,牛客網的題中標明負數用補碼錶示,也有網友給出了2**32+n(n<0時)(可以轉爲補碼),但是這是針對32位計算機的,64位的就是64,而且當這個數非常大時,加2**32還是負數,此時就不再適用了;我在寫出的demo爲負數還是統計原碼中1的個數,針對補碼時就不對了。

new method
================================================================================================
題目:實現一個函數,輸入一個整數,輸出該數二進制中1的個數。如9的二進制爲1001,有2位是1,因此返回2。(其中負數用補碼錶示)

思路:
python比較特殊,不管數有多大都不會溢出,所以在此只取前32位(n = 0xFFFFFFFF&n 一個F是4個1)
①將截取的32位數字轉換爲二進制,再轉換爲字符串統計1的個數;
②將數字左移統計;
③在while中n=n&(n-1),count+=1, 每次n&(n-1)都會減去二進制中的一個1

 面試題16:數值的整數乘方

數值的整數次方。求base值得整數次方,不得使用庫函數,同時不用考慮最大數的問題。

思路:

  1. ①要考慮全面。有正整數次方,也有0和負整數次方,正整數直接相乘即可,0直接返回1,負整數在正數的基礎上取倒數
  2. ②方法一,直接使用循環e個數相乘解題,但是時間複雜度較高
  3. ③方法二,用遞歸解題逐層遞歸自上而下,時間複雜度好像第一點, 當n爲偶數時,a^{n}=a^{n/2}a^{n/2}, 當n爲奇數時,a^{n}=a^{(n-1)/2}a^{(n-1)/2}a, 例如,若 exponent 爲 32,按照上面 power 函數的做法,for 循環中要進行31次乘法。若是換一種思路思考:base^{32}等於base^{16}的二次方,base^{16}又是base^{8}的二次方。以此類推,做32次方只需5次乘法,先求2次方,然後4次方, 然後8次方,再然後16次方,最終求得32次方。

面試題17:打印1到最大的n位數 

題目:輸入數字n,按順序打印出從1到最大的n位十進制數。如輸入3,,則打印出1,2,3,...,999

思路:關鍵在於怎麼設置循環結束的條件(在其他語言中要考慮大數,防止溢出,但是在python中不用考慮溢出的問題)

面試題18:刪除鏈表的節點

題目一:在O(1)時間內刪除列表節點,返回最終鏈表的頭節點。給定單向列表的頭指針和一個節點指針,定義一個函數在O(1)時間內刪除該節點。

思路:
因爲最終要返回的是鏈表的頭節點,所以需要藉助空間複製一個新的鏈表,但是新的鏈表比原鏈表的在頭節點處多一個元素,然後接下來的操作在新鏈表上進行,最終返回新鏈表的next。需要藉助兩個指針用來標記前後位置,如果前面的節點發現了目標節點,則後面的指針指向前面節點的下一個節點,從而實現刪除節點;要注意刪除節點不存在的情況

題目二:刪除鏈表中的重複節點。在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理後爲 1->2->5

思路:
因爲最終要返回的是鏈表的頭節點,所以需要藉助空間複製一個新的鏈表,但是新的鏈表比原鏈表的在頭節點處多一個元素,然後接下來的操作在新鏈表上進行,最終返回新鏈表的next。需要藉助兩個指針用來標記前後位置,先找到重複的節點的值,然後再去刪除從該節點起等於刪除節點值的節點

面試題20:表示數值的字符串 

題目:請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符"+100"、"5e2"、"-123"、"3.1416"及"-1E-16"都表示數值,但"12e"、"1a3.14"、"1.2.3"、"+-5"、"12e+5.4"都不是

思路:
(反面解題,針對不合規的情況討論,剩下的就是合規的情況)表示數字的字符串遵循A[.[B]][e|EC]或.B[e|EC],其中A和C都是整數(可以有正負號,也可以沒有),而B只能是一個無符號整數找三個輔助變量分別表示正負號、小數點、E/e是否出現或出現的位置是否合適。遍歷整個字符串,每個字符進行判斷, 正負號只能出現在整數部分的前面或者是e/E的後面;小數點只能出現一次, 且在e/E的部分不能出現小數;e/E只能在數字的後面且其前面不能沒有數字,且只能出現一次

面試題21:調整數組順序使奇數位於偶數前

題目:輸入一個整數數組,實現一個函數調整該數組中數字的順序,使得所有奇數位於數組的前半部分,所有偶數位於後半部分。

思路:

  1. 從頭開始遍歷,遇到偶數就移到最後面。時間複雜度和空間複雜度都爲O(n),但是是穩定的,即移動後奇數相對於奇數、偶數相對偶數位置是不變的;
  2. 找兩個指針分別放在頭部cur1和尾部cur2,若cur1指的是偶數,cur2指的是奇數,則交換元素,時間複雜度爲O(log n ),但是是不穩定的
  3. 特殊用例:傳入的是空數組;傳入的列表只有一個元素;所有的偶數都在前半部分

變體:

  1. 改成負數都在非負數前面
  2. 能被3整除的數都在不能被3整除數的前面

面試題22:鏈表中倒數第k個節點 
面試題22:輸入一個(單向)鏈表,輸出該鏈表中倒數第k個節點。如鏈表爲[1,2,3,4,5], k=2時,輸出倒數第二個節點爲4

思路:

  1. 先遍歷一次列表獲得鏈表的長度n,再從頭遍歷到n-k+1個值,輸出即可,但是這樣時間複雜度高
  2. 找兩個指針cur1(第i個位置)、cur2(第i+k個位置),並另二者的間隔爲k,當cur2走到鏈表尾部時,cur1所指的就是倒數第k個值。【注意:輸入的鏈表爲空或者鏈表的長度小於k時,會直接報錯】
  3. 防爆措施:1、當輸入的k小於1時,返回None;2、鏈表爲空,返回None;3、鏈表長度小於k,返回None

面試題23:鏈表中環的入口節點

題目:給定一個鏈表,若其中包含環,請找出該鏈表的環的入口節點,否則輸出null

思路:

  1. 找一個set,記錄下環中的每一個節點,如果遇到None,則無環,如果再次遇到相同的節點,則表明有環,且該該節點爲環的入口節點;
  2. (先判斷是否有環,無環則return None,有環再去尋找環的入口)找兩個指針fastPointer、slowPointer,f每次走兩步,s每次只走一步,如果f遇到none表明無環,否則有環(注意當f==s時,說明,f在環裏面追上了s,表明有環);在判斷環的入口位置,經過數學公式證明,當兩個指針在環中第一次相遇後,此時找一個新的指針從頭開始一步一步移動,s也一步一步往前移,二者相遇的位置就是入口節點

證明過程如下(假設鏈表中有環):
假設s與f第一次相遇時,s已經走了l步,則f走了2l步;
假設入環前的步長爲a,s進環後與f相遇又走了b步,則l=a+b,相遇的位置距離環的入口爲c; 
則f所走的步長2l=a+n*(b+c)+b, 其中n表示f在環中所繞的圈數
有2*(a+b)=a+n*(b+c)+b, 化簡得a=c+(n-1)*(b+c),(其中b+c表示環的長度)

面試題24:反轉鏈表 

題目:定義一個函數,輸入鏈表的頭節點,反轉該鏈表並輸出反轉後鏈表的頭節點。(就是要求把一個單向鏈表有正序變爲倒序)

思路:

  1. 需要找三個指針指定位置左中右做標記,然後三個指針依次往下走
  2. 特殊測試:空鏈表、只有一個節點的鏈表

面試題25:合併兩個鏈表

題目:輸入兩個遞增排序的鏈表,合併這兩個鏈表並使新鏈表中的節點仍然是按遞增排序的。輸出合併後的鏈表

思路:
建立一個新的鏈表,找兩個遊標作爲標記, 再找一個指針指向新鏈表的前一個節點,每次兩個遊標進行比較從而判斷指針的下一個節點

面試題26:樹的子結構

題目:輸入兩顆二叉樹A和B,判斷B是不是A的子結構(注意:約定空樹不是任意樹的子結構)

思路:
主要是分爲三種情況處理:第一種,二者的根節點就相同;第二種,B是A的左子樹的一部分;第三種,B是A的右子樹的一部分;針對每一種情況再判斷B是否是A的子結構(如何判斷:先判斷根節點是否相等,如果相等,再分別去判斷左、右兩邊是否相等,整體相等才能返回True,否則只能返回false)

面試題27:二叉樹的鏡像

題目:請完成一個函數,輸入一個二叉樹,該函數輸出它的鏡像

思路:
採用遞歸的方式,每次對調根節點下的左右子節點

面試題28:對稱的二叉樹

題目:請實現一個函數,用來判斷一顆二叉樹是不是對稱的。如果一顆二叉樹和它的鏡像一樣,那麼它就是對稱的,否則不是

思路:
採用遞歸的方法,判斷左子樹的左邊是否與右子樹的右邊相等,左子樹的右邊是否與右子樹的左邊相等

面試題30:包含min函數的棧

題目:定義棧的數據結構,在棧的原有功能上添加一個能夠得到棧的最小元素的min函數,要求:在該棧中,調用min、push及pop的時間複雜度都是O(1)

思路:

  1. 棧的特點是先進後出,後進先出。棧的功能主要有:push(進棧)、pop(出棧)、top(棧頂元素);
  2. 遍歷棧去尋找元素,時間複雜度爲O(n),題中要求是O(1),所以考慮用空間換時間,創建一個存放最小值的列表,在每次進棧時都比較,對應放入最小值,從而棧有多長(假設爲n),則最小元素的列表也爲n 

面試題31:棧的彈出與壓入 

題目:輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否爲該棧的彈出順序。假設壓入棧的所有數字都不相等。例如1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。

思路:
每壓入一個元素,都會考慮彈出或不彈出的情況,不彈出則繼續壓入;彈出則彈出,下一個元素接着考慮是否彈出,不彈出則壓入,由此得到第二個序列,即第二個序列是出棧方式中的一種可能結果

面試題32:從上到下打印二叉樹

題目:從上往下打印出每個二叉樹的節點,同一層的節點按照從左到右的順序打印

思路:
將樹的每一個左右節點都按照左右的順序放入隊列中,然後再按照先進先出的順序打印出該節點的值,再將它的左右子節點放入隊列中

面試題33:二叉搜索樹的後序遍歷序列

題目:輸入一個整數數組,判斷該數組是不是某二叉搜索樹的後序遍歷的結果。如果是則返回True,否則輸出False。假設輸入數組的任意兩個數字都互不相同
(名詞解釋:二叉搜索樹————左子樹的值必然小於根節點,右子樹的值必然大於根節點的值;或者是一顆空樹)

思路
二叉搜索樹的後序遍歷,如5 7 6 9 11 10 8,8是根節點,根據二叉樹的性質判斷出5 7 6 是左子樹的(都小於8),9 11 10是右子樹的(都大於8),再遞歸進行判斷,如果應該是右子樹的部分出現小於根結點的(如小於8),則輸出False

面試題34:二叉樹中和爲某一值的路徑

題目:輸入一顆二叉樹和一個整數,打印出二叉樹中節點值的和爲輸入整數的所有路徑。從樹的根節點往下一直到葉節點所經過的結點形成一條路徑
(注意:第一,路徑指的是從根節點到葉子節點的一條完整的路徑)

思路:
根據廣度優先的方法,依次去尋找路徑和爲輸入整數的路徑(看代碼吧,不太明白)

面試題36:二叉搜索樹與雙向鏈表

題目:輸入一顆二叉搜索樹,將該二叉搜索樹轉換爲一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向

思路:
參考網址:https://blog.csdn.net/u010005281/article/details/79657259作者講的很詳細。
借用兩個輔助變量分別標記雙向鏈表的頭節點和尾節點,按照中序遍歷的思路,用遞歸進行解題。尾部節點得每次移動到尾部,從而每次都是尾部標識。

面試題37:序列化二叉樹

題目:請實現兩個函數,分別用來序列化和反序列化二叉樹

思路:
序列化的過程就是對樹進行前序遍歷,但是要注意找一個記號(如'#')標記葉子結點;
反序列化的過程將序列轉換爲樹結構。先將字符串且分爲列表格式,再根據所做的葉子結點的標記採用遞歸的方法,找出左右子節點從而還原爲一棵樹

面試題38:字符串的排列

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

思路:
看不懂,死記吧

面試題39:出現次數超過一半的數字

題目:數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如一個輸入長度爲9的數組{1,2,3,2,2,2,5,4,2}, 由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2(注意:這個題主要考察的是時間複雜度和空間複雜度

思路:

  1. 創建一個字典,記錄下每一個數字出現的次數,並判斷其出現次數是否超過數組長度的一半(時間複雜度和空間複雜度都爲O(n))
  2. 每次抵消兩個前後兩個不相同的數字,從而得到最後一個剩下的一個數字;再判別該數字的出現次數是否超過數組的一半(時間複雜度爲O(n), 空間複雜度爲O(1)))

面試題40:最小的k個數

題目:輸入n個數,找出其中最小的k個數。例如,輸入4 5 1 6 2 7 3 8這8個數字,則最小的4個數字是1 2 3 4
(這個題主要是考察時間複雜度;知識點:最大最小堆)

提示:找k個最小的數,需要用到最大堆;找k個最小的數,需要用到最小堆;最大最小堆必須是一個完全二叉樹;堆插入一個值的時間複雜度爲O(lgn), 刪除一個
值得時間複雜度爲O(lgn), 創建一個堆的時間複雜度爲O(n); 完全二叉樹找到其父節點的索引的公式爲(index-1)//2,index爲當前值的索引,注這裏的索引順序是
按照廣度優先排序的,反過來也可以找到其子節點,左子節點索引爲index*2+1, 右子節點索引爲index*2+2, 

思路:

  1. 可以使用各種排序算法,先對數組進行排序,然後再選出最小的k個數(但是如果數據達到億級別時,直接排序可能內存放不下)
  2. 借鑑最大最小堆的思路進行解題,要找k個最小的數,首先需要建立一個含有k個數的最大堆,然後再依次遍歷去修改已經建立好的最大堆。最大堆並不需要建立真實的一棵樹,而是根據最大堆是完全二叉樹的一些性質,將數放在列表裏面即可(這種方法的時間複雜度爲O(nlogk))

面試題41:數據流中的中位數

題目:
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值,如果數據流中讀出偶數個數值,那麼中位數就是所有數值排序後中間兩個數字的平均值。我們使用insert()方法讀取數據流,使用getMedia()方法獲取當前讀取數據流的中位數

思路:
將數組裏的數交替放入最大堆最小堆中,這樣中位數只能是最大堆的堆頂或者最大最小堆堆頂元素的均值。首先編寫最大堆最小堆的創建及修改的函數(共4個),交替的往最大最小堆添加數字(添加數字的過程是重點),從而保證最大最小堆裏的元素個數要麼相等,要麼相差一個,從而實現了實時獲取數據流的中位數。

面試題42:連續數組的最大和

題目:輸入一個整型數組,數組裏有正數也有負數。數組中一個或連續的多個整數組成一個子數組,求所有子數組和的最大值。例如,{6,-3,-2,7,-15,1,2,2}, 連續子向量的最大和爲8(從第0個開始到第三個爲止)。要求時間複雜度爲O(n)【題目的意思是找出連續的數字中那幾個加起來是最大的,只需要找到子數組和最大的那個和就行,不需要找出子數組】

思路:
找兩個輔助變量,一個記錄最大和,另一個記錄加到第i個數之前的和,通過遍歷數組,從而找到連續子數組的最大和

面試題43:統計1~n整數中1出現的次數

題目:輸入一個正整數n,求從1到n這n個整數的十進制表示中1出現的次數。例如輸入12,從1到12這些整數中包含1的數字有1,10,11和12,1一共出現了5次
(這道題主要是考察時間複雜度)

思路:

  1. (暴力方法)每個數遍歷並去判斷其是否含有1
  2. 從個位、十位、百位到最高位,依次判斷該位數字爲1時可能出現的情況,再將其相加就得到了最終結果,難以口述清楚,還是看代碼吧

面試題44:數字序列中的某一位數

題目:數字以012345678910111213141516……的格式序列化到一個字符序列中,在這個序列中,第五位(從0開始計數)是5,第十三位是1,第十九位是4等。寫一個函數,求任意n位對應的數字。

思路:

  1. ①枚舉法,從第0位開始遍歷。一直找到第k位
  2. ②從1開始,個位數(只有一位的數字)有九個,佔位9個;兩位數有90個,佔位90*2個;三位數有900個,佔位900*3個;以此類推,如果要找的第k位大於佔位的累加和,則再增加一個位數,看目標數字是否在是這個位數,如果是則查找這個數,不是則再增加一個位數

面試題45:把數組排成最小的數

題目:輸入一個正整數數組,把數組裏面所有數字拼接起來排成一個數,打印能拼接出的所有數字中最小的一個。例如,輸入數組{3,32,321},則打印出這3個數字能排成的最小數字321323(321 32 3)

思路:
(有點類似於面試題38————字符串的排列,n個數字共有n!種排列,但是如果使用這種方法的話,還是很慢)
參考網址:https://blog.csdn.net/u010005281/article/details/80085476
使用了快排的思路,但是不太理解,和書上講的那一長串有點不一樣

面試題46:把數字翻譯爲字符串 

題目:給定一個數字,我們按照如下規則把它翻譯爲字符串:"0"翻譯爲"a","1"翻譯爲"b","2"翻譯爲"c",……,"25"翻譯爲"z"。一個數字可能有多個翻譯。例如,"12258"有五種不同的翻譯,分別是"bccfz"、"bwfi"、"bczi"、"mcfi"、"mzi"。寫一個函數,計算一個數字有多少種不同的翻譯。

思路:
採用遞歸的思路, 從後往前或從前往後,依次判斷一位與兩位(兩位數必須小於26纔行),有點類似於斐波那契數列遞歸的方法f(n)=f(n-1)+f(n-2)

6    
5               25 
2       12      1  11
1 11    1       1
1

面試題47:禮物的最大價值

題目:在一個m*n的棋盤的每一格都放一個禮物,每個禮物都有一定的價值(價值大於0).你可以從棋盤的左上角開始拿格子裏的禮物,並每次向右或者向下
移動一格,直到到達棋盤的右下角。給定一個棋盤及其上面的禮物,請計算你最多拿到多少價值的禮物

思路:
動態規劃。(看不明白,還是看代碼死記)
參考網址:https://www.jianshu.com/p/71bc21981090

面試題48:最長不含重複字符的子字符串

題目:請從字符串中找出一個最長的不包含重複字符的子字符串,計算該最長子字符串的長度,假設字符串中只包含"a"~"z"的字符。例如,在字符串'arabcacfr'中,最長的不含重複字符的子字符串爲acfr,長度爲4

思路:

  1. 先找出所有的子字符串,再去判斷子字符串是否重複,去掉重複的,再找到最長的子字符串,時間效率爲O(n^3)
  2. 遍歷整個字符串,記錄下當前無重複的最長子字符串,如果發現字符串i已經在記錄的最長子字符串中,那麼記錄從字符串i第一次出現的下一個位置開始重新開始
  3. 動態規劃。(動態規劃的解法沒大看懂)

面試題49:醜數

題目:把因子只包含2、3、5的稱爲醜數(ugly number)。求按從小到大第N個醜數,例如6、8都是醜數,但是14不是,因爲它的因子包含7,習慣上把1當做
第一個醜數(注意:主要考慮時間複雜度)

思路:

  1. (暴力方法)從1一直判斷下去,知道找到第N個醜數(判斷醜數的方法:先無限整除2,再無限整除3,最後再無限整除5,如果最終得到1則就是醜數,否則不是)【時間複雜度太高,而且N越大越慢】
  2. 找3個指針,分別表示*2、*3、*5,都從1開始,判斷大小找到小的數存放起來,並且對應的指針往前移一位,如1  *2、*3、*5,對應的最小的數爲2,則將2添加到列表裏,並將*2的指針往前移動一位,依次類推,知道找到第N個醜數爲止

面試題50:第一個只出現一次的字符

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

思路:

  1. 拿第i個字符分別與其後面的字符串比較,如果其後面沒有出現相同的,則輸出,否則繼續比較下一個字符。時間複雜度爲O(n)
  2. 用一個字典來統計出現的次數,用一個列表記錄字典中的鍵先後的出現次數,最後通過列表記錄下的鍵,尋找字典中值爲1的鍵

題目二:字符流中第一個只出現一次的字符。寫一個函數,找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g";當從該字符流中讀出前6個字符"google"時,第一個只出現一次的字符是"l"

思路:
可以根據題目一的思路改一下即可,每輸入一個數據流字符串,都判斷一下當前第一個出現的子字符串,爲了避免每次重複計算,可以將字典和列表定義在類下的init中

面試題51:數組中的逆序對

題目:在數組中的兩個數字如果前面一個數字大於後面一個數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。例如,{7,5,6,4}中,一共有(7,5), (7,6), (7,4), (5,4), (6,4) 5個逆序對(注:輸入的數組中沒有相同的數字)

思路:

  1. 每遍歷一個數字,都拿去與其後面的數字進行比較,但是這樣的時間複雜度爲O(n^2);
  2. 按照歸併排序的思路,先將數組折半分,直到分出單個元素,然後在合併的過程中統計發生調序的次數,此時的時間複雜度爲O(nlogn),空間複雜度爲O(n),是典型的空間換時間

面試題53:在排序數組中查找數字

題目一:數字在排序數組中出現的次數。統計一個數字在排序數組中出現的次數。例如,輸入排序數組{1,2,3,3,3,3,4,5}和數字3,由於3出現了4次,所以輸出4

思路:

  1. 直接從頭遍歷,但是這種方法的時間複雜度爲O(n)
  2. 根據二分查找的思路,先找到數字k首次出現的位置,再分別從前半段後半段找出k第一次和最後一次出現的位置(索引),從而統計出k出現的次數,這種方法的時間複雜度爲O(logn)。編寫兩個函數分別尋找k首次出現和左後依次出現的索引位置,尋找k首次出現的位置,需要用到遞歸,爲了能夠保證找到位置,所以每次需要傳入原數組,用兩個輔助變量firstIndex, lastIndex來表示每次的變動,這樣就能準確找到首次出現的索引位置

題目二:0~n-1中缺失的數字。一個長度爲n-1的遞增排序數組中的所有數字都是唯一的,並且每個數字範圍都在0~n-1之內。在範圍0~n-1內的n個數字中,有且只有一個數字不再該數組中,請找出這個數字。

思路:

  1. 從頭遍歷,找到缺失值,時間複雜度爲O(n)
  2. 採用二分查找的方法,時間複雜度可以爲O(logn)

面試題54:二叉搜索樹的第k大結點 

題目:給定一顆二叉搜索樹,請找出其中第k個最小結點值(書上的意思還是找出第k個最小值)。例如(5,3,7,2,4,6,8)中,按結點數值大小順序第三小結點的值爲4(補充:二叉搜索樹:左子樹都小於父節點,右子樹都大於父節點)

思路:
等價於中序遍歷找第k個值,先對給定的二叉搜索樹進行中序遍歷,將序列放於列表中,再去尋找是否有第k個元素

面試題55:二叉樹的深度

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

思路:
參考網址:https://blog.csdn.net/dailu11/article/details/80609416?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
自己做不會,但是一看別人的(哦,好像是那麼回事;對遞歸理解還是不到位)

題目二:平衡二叉樹。輸入一顆二叉樹的根節點,判斷該樹是不是平衡二叉樹。如果某二叉樹中任意節點的左右子樹深度相差不超過1,那麼它就是一顆平衡二叉樹

思路:
根據二叉樹深度的思路,判斷其左右子樹的最大深度並進行比較,如果大於1,直接返回False,否則再進一步判斷其子樹是否滿足, 這種方法每個節點只需要遍歷一次即可

面試題56:數組中只出現一次的數字

題目:一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間複雜度是O(n), 空間複雜度是O(1)(這個題目比較難,難以口述清除,要結合代碼進行理解)

思路
使用異或這個位運算進行解題(首先異或運算也具有交換律)。
因爲數組中除了兩個只出現依次的數字外,其他的數字都是出現了兩次,使用異或運算可以使出現兩次的數字的異或結果爲0(如(1,1,2,2,3,4,4,5,5,6), 整體進行異或後,結果爲5==101),從而找出兩個只出現一次數字的異或結果x,再找到x的二進制碼中1首次出現的位置,並截取其右半段爲y(如5的右半段爲1,再如異或結果爲20==10100,截取的右半段爲100);再用截取的右半段y與數組中的每個數字進行與操作,可以將數組分爲兩段,並且每段中有一個只出現一次的數字,再分別對每段進行異或操作,從而找到了兩個只出現一次的數字

面試題57:和爲s的數字

題目一:和爲s的兩個數字,輸入一個遞增排序的數組和一個數字s,在數組中查找兩個數,使得他們的和正好是s。如果有多對數字和胃s,輸出任意一對即可。

思路:
找兩個指針,一個指向頭,一個指向尾,從而去找s,這樣的時間複雜度爲O(1)

題目二:和爲s的連續正數序列。輸入一個正數s,打印出所有和爲s的連續正數序列(至少含有兩個數)。例如,輸入15,由於1+2+3+4+5=4+5+6=7+8=15,所以打印出3個連續序列1~5、4~6和7~8

思路:
找兩個指針,指向1和2,如果cur1到cur2的和小於targetSum,那麼cur2加1;如果大於targetSum,則cur1加1;等於,則記錄下來,cur2加1,循環判斷直到沒有爲止(終止條件:cur1的值小於(1+targetSum)/2時一直滿足條件)

 面試題58:翻轉字符串

題目一:翻轉單詞順序。輸入一個英文句子,翻轉句子中單詞的順序,但單詞內字符的順序不變。爲簡單起見,標點符號和普通字母一樣處理。例如,輸入字符串"I am a student.",則輸出"student. a am I"

思路:
先切分開,翻轉後再用空格鏈接回去

題目二:左旋轉字符串。字符串的左旋轉操作是把字符串前面的若干個字符轉移到字符串的尾部。例如,輸入字符串'abcdefg'和數字2,該函數將返回左旋轉兩位得到的結果'cdefgab'

思路:將前面的n個字符串移動到後面即可

面試題59:滑動窗口的最大值

題目一:滑動窗口的最大值。給定一個數組和滑動窗口,請找出所有滑動窗口的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那麼一個存在6個滑動窗口,它們的最大值分別爲{4,4,6,6,6,5}

思路:

  1. 每次選取k個數裏面最大的,但是這樣的時間複雜度大,爲O(n^2)
  2. 雙向隊列,時間複雜度爲O(n)。遍歷整個數組,先刪除超出窗口數的索引;再刪除小於numbers[i]的數的索引;從第k-1個索引開始添加

題目二:隊列的最大值。請定義一個隊列並實現函數max得到隊列裏的最大值。要求函數max、push_back、pop_front的時間複雜度都是O(1)

思路:(沒整明白題目是什麼意思)

面試題60:n個骰子的點數之和

題目:把n個骰子扔在地上,所有骰子朝上一面的點數之和爲s。輸入n,打印出s的所有可能的值出現的概率

思路:
動態規劃問題。f(n, s) = f(n-1, s-1) + f(n-1, s-2) + f(n-1, s-3) + f(n-1, s-4) + f(n-1, s-5) + f(n-1, s-6)。初始條件,f(1,1)=f(1,2)
=f(1,3)=f(1,5)=f(1,6)=1
參考網址:https://www.bbsmax.com/A/1O5EVXAWd7/

面試題61:撲克牌中的順子

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

思路:
大小王可以看成是任意數字,假設爲0。先對數組進行排序,然後統計0的個數,再統計連續數字出現間隔的個數,如果0的個數大於等於出現間隔的個數,則可以認爲是連續的;否則,認爲是不連續的

面試題62:圓圈中最後剩下的數字

題目:0,1,...,n-1這n個數字排成一個圓圈,從數字0開始每次從這個圓圈裏刪除第m個數字,求出這個圓圈裏剩下的最後一個數字。如0,1,2,3,4這五個數字組成一個圓圈,從0開始每次刪除第三個數字,則刪除的前四個數字依次是2、0、4、1,因此最後剩下的數字是3

思路:

  1. 依次遍歷,從而找到剩下的最後一個數字,但是其時間複雜度爲O(n^2)
  2. 找規律,但是沒搞明白,這種方法的時間複雜度爲O(n),空間複雜度爲O(1)【死記】

面試題63:股票的最大利潤

題目:假設把某股票的價格按照時間先後順序存儲在數組裏,請問買賣該股票一次可能獲得的最大利潤是多少?例如,一隻股票在某些時間節點的價格爲{9,11,8,5,7,12,16,14}。如果我們能在價格爲5的時候買入並在價格爲16時賣出,則能收穫的最大利潤是11

思路:
(實際上是找數組的最大差值)

面試題64:求1+2+……+n

題目:求1+2+……+n,要求不能用乘除法、for、while、if、else等關鍵字及條件判斷語句

思路:
發散性思維,在實際中不太可能出現。

面試題65:不用加減乘除做加法 

題目:寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號(這個題只能死記,技巧性太強

思路:
進行位運算,進行按位與、異或運算
將十進制數轉換爲二進制,

第一步,先進行兩者間先進行按位與運算,如果結果爲0,那麼二者再進行的異或結果轉換爲十進制就是最終結果;
第二步,如果按位與結果不爲0,說明有地方需要進一位,對其右補一位0並記爲x(左移1位),原來的兩者間進行異或操作得到y;第三步,將x與y重複前面的步驟

面試題66:構建乘積數組

題目:給定一個數組A[0,1,...,n-1],請構建一個數組B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法

思路:

  1. 最暴力的方法,每個B[i]都從頭計算,時間複雜度爲O(n)
  2. B[i]的計算拆分爲兩部分,記C[i]=A[0]*A[1]*...*A[i-1],D[i]=A[i+1]*...*A[n-1],其中C[i]可以自上而下的計算,D[i]可以自下而上的計算,而C[i]=C[i-1]*A[i-1], D[i]=D[i+1]*A[i+1], 時間複雜度爲O(n)

unknown1:按之字形順序打印二叉樹

題目:請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右到左的順序打印,第三層按照從左到右的順序打印,依次類推

思路:
①(行不通)按照廣度優先的思路執行不通,因爲很難區分清楚打印到第幾層,從而沒辦法及時調整方向(從左到右還是從右到左)
②找兩個棧,將奇數層的結點從右到左append進去,將偶數層的結點從左到右append進去,最後再從尾部pop出來

unknow2:把二叉樹打印成多行

題目:從上到下打印二叉樹,同一層結點從左到右輸出,每一層輸出一行

思路:
與上一個按之字形打印二叉樹的題目高度相似,只是把上一個題用的棧換爲隊列

unknow3:矩形覆蓋

題目:用2*1的小矩形橫着或豎着覆蓋更大的矩形,請問用n個2*1的小矩形無重疊的覆蓋一個2*n的大矩形,總共有多少種方法

思路:
原理就是斐波那契數列,如果第一塊是豎着放的,那麼剩下的就相當於n-1的情況,如果第一塊是橫着放的,那麼第二塊的方法就確定了,就相當於是n-2的情況



水平線以上的是劍指offer的題,水平線以下也是算法題(但不是劍指offer上的)

1、洗牌問題

洗牌問題。用Array編寫洗牌問題?如何測試?(一個好的洗牌是每一張牌出現在一個地方的概率是相同的)
解題方法:

  1. 直接調用python的自帶包random.shuffle();【注意:random.shuffle()沒有返回值】
  2. 用概率的方法來解題使得一張牌出現在任意一個地方的概率都是\frac{1}{n},具體思路如下:
  • 先考慮第一個位置:隨機從n張牌中抽取一張放在第一個位置,在該過程中每張牌被抽中的概率是1/n;
  • 再開率第二個位置:從剩下的n-1張牌抽取一張放在第二個位置,在該過程中每張牌被抽中的概率是1/(n-1),但是第一次沒被抽中,概率爲(n-1)/n,兩個一乘爲1/(n-1) * (n-1)/n = 1/n;
  • 接下來考慮第三個位置1/(n-2) * (n-2)/(n-1) * (n-1)/n = 1/n;
  • 以此類推,可以得出每張牌出現在一個位置的概率是1/n(圖中就是詳細的過程)

2、計算質數的個數

題目:計算質數。給一個數n,返回它裏面的所有質數的個數;如17,它的質數個數爲7(包含17),則返回7。

思路:

  1. 1~n中的每一個數,都用其除以\sqrt{n}以內的數,比如17,從1遍歷到17,對於17個數中的每一個數都去除以是\sqrt{n}以內的數,如5就去除以\sqrt{5}以內的整數,來判斷5是不是質數。缺點:時間複雜度較高,每一個數都需要遍歷一次。
  2. 用空間換取時間,先找一個長度爲n的bool數組,裏面全設置爲true,從2開始,判斷2,是2的倍數(倍數大於1)則全部賦值爲false;然後再判斷3;因爲4被劃掉了,所以下一個考慮5;接下來再考慮7,一直到bool數組的後面全部轉換爲false爲止

注意: 

  • 倍數從2開始,因爲1倍數就是它自己;
  • bool數組的true可以換成1,false換爲0,這樣可以減少時間複雜度;因爲用ture/false的話,最後需要遍歷取統計true的個數,如果換爲1的話,直接sum求和即可;

3、“證明巴德赫猜想”

題目:證明巴德赫猜想。任意大於2的偶數都可以寫成兩個質數(素數)之和,如16=3+13。(這道題換句話表達:將任意一個大於2的偶數表示爲兩個質數之和)
思路:

  1. 首先,根據上一道題,計算n以內的所有素數個數,可以得到這個偶數範圍內的所有素數,而且是排好序的;
  2. 其次,有兩種方法解題:①用兩個for循環,將兩個素數加起來,判斷其是否等於輸入的這個偶數;②找兩個指針,分別指向第一步得到的有序素數列表的頭尾記爲i、j,如果i、j所指向的數之和大於這個偶數,那麼j往左移一位再次判斷;如果i、j所指向的數之和小於這個偶數,那麼i往右移一位;如果等於這個偶數,則返回所指的兩個質數。

注意:

  • 第一種方法的時間複雜度爲O(n^2);第二種方法的時間複雜度爲O(n)

4、掃雷遊戲

題目:掃雷遊戲。程序接收三個參數M,N,p,然後生成一個M*N的矩陣每一個cell都有p的概率是地雷,生成矩陣後,然後再計算每一個cell周圍地雷的數量。

思路:

  • 難度2星。因爲邊界的判斷是個問題,在邊上的格子只有5個鄰居,在角上的格子只有三個鄰居,只有在內部的纔有八個鄰居,可以直接寫程序,但是這樣有些太麻煩。所以應用了一個小技巧(技巧),在邊界加上一層框,即行數和列數各增加2行/列,且和真正棋盤上的元素都不一樣,用以區分。
  1. 首先,先創建一個棋盤;
  2. 然後再依次挨個遍歷;

5、矩陣0變換

題目:矩陣0變換。給定一個m*n的矩陣,如果有一個元素爲0,則把該元素對應的行和列全部轉換爲0

思路:

  • 【誤區:遇到0直接就立馬將其所在行與列都轉變爲0,結果會導致整個矩陣都變爲0】
  1. 先定義兩個列表來記錄有0的行和列,通過遍歷每一行去找0,如果遇到0則記錄下其行號和列號,
  2. 然後再去將對應的行和列轉爲0

6、九宮圖和驗證9*9的數獨

題目1:九宮圖(與數獨規則不一樣)。每一行每一列以及對角線的元素加起來和相等(注:九宮圖的行數與列數必然爲奇數)

思路:

  1. 首先要了解一個算法,每次把1放在最後一行的中間位置,然後另其右下方的數爲2,超出邊界,則對應找對角線上的位置,再在右下角填3,依次類推,如果發現下一個位置是1,則把下一個數填在這一對角線結束的上方的那個格子裏,再與之前的循環操作類似,直至把最後一個數填進格爲止【注:知道了這個解題方法後,關鍵是怎麼用程序寫出來】

注意:

  • 首先,要搞清楚遊戲規則;
  • 其次,(技巧)要處理好越界問題,當下一個元素的位置超出邊界時,通過取餘讓其重新回到邊界內;
  • 最後,寫出程序的時間複雜度爲O(n)
  • 遊戲規則如下圖解:

 題目2:數獨。在9*9的格子裏,每一行每一列以及每一個切分好的3*3的格子裏,1~9都僅出現一次。給一個填好的數獨,驗證其是否正確。
思路:

  1. 用for循環,然後再判斷行列以及3*3的單元裏面元素是否爲1~9,用set(這個題我已經繞懵圈了)。反正就是看代碼吧

7、旋轉數組:將一個數組旋轉90度

題目:旋轉數組。給定一個n*n的數組,將其順時針旋轉90度。

思路:

  1. 創建一個n*n的數組,將對應的元素存入新數組中,但是有O(n^2)的空間複雜度;
  2. 先轉置再左右翻轉,優點:沒有佔用新空間;【注意:根據這種方法可以求出旋轉90度、180度(先上下翻轉再左右翻轉)、270度(就是逆時針旋轉90度)等】

參考網址:https://blog.csdn.net/shahuzi/article/details/97825167

8、反轉字符串

題目:反轉字符串
思路(這個題目還是很簡單的):

  1. 直接str[::-1];
  2. 自己手寫一個,也很簡單,從第0個位置遍歷到第n/2個位置[注意:string是一個不可變的數據類型]

9、最長連續子串

題目:最長連續子串。給定一個只包含0和1的數組,找出只包含1的最長子串。
思路:

  1. (自己的解法,不僅找到了最長子數組,也找到了它的位置)用while從頭到尾遍歷一遍,把一個包含1的子數組用元組記下其頭索引和長度
  2. 只判斷出最長子數組是多長,代碼相對比我的簡潔很多 

 10、最大數

題目:最大數。給定一個數組,數組裏有且只有一個最大數,判斷這個數是否是其他數的兩倍或更大,如果存在這個數,則返回其index,否則返回-1
注意:

  • 沒有必要先找到最大的數,再去和每一個數進行比較,會增加時間複雜度;
  • 第二,如果直接用sort排序,再讓第一大和第二大的數比較,代碼夠簡潔,但是排序的時間複雜度爲O(nlogn)

思路:

  1. (核心)遍歷一次數組,找出最大和第二大的數,及第一大的數的索引,再去比較滿足返回最大數的索引,不滿足返回-1

11、消失的數字

 題目:找到數組中消失(沒有出現)的數。給定一個長度爲n的數組,裏面數字的範圍爲[1,n],有的數字出現了多次,有的一次也沒有出現,找到沒有出現的數字。要求:不能佔用其他的空間,時間複雜度不鞥超過O(n)
思路:

  1. 既然要求不能佔用新的空間,那就只能修改原來數組,從而標記[1,n]中那個數沒有出現,出現的則將這個數對應的索引上的數字記爲負數,那麼最後哪個索引位置的數字爲正就說明該索引(即該數字)沒有出現

12、斐波那契數列

注意:

  • 在遞歸裏面仍然會把整個函數執行一遍,自下而上

思路(3種方法):

  1. 普通的遞歸方式,時間複雜度爲O(2^n),n=40時,直接執行不了;
  2. 用for循環,每次把上一次的結果放入列表中,下一次計算時直接用列表中尋找上一次的結果;
  3. 找兩個臨時變量存儲上兩次的值用於計算下一次的結果,這樣可用for,也可以用遞歸; 

13、打印對稱的尺子

題目:打印對稱的尺子。如n=1時,輸出1;n=2時,輸出1   1 2 1;n=3時,輸出1   1 2 1    1 2 1 3 1 2 1;n=4時,輸出1   1 2 1   1 2 1 3 1 2 1   1 2 1 3 1 4 1 3 1 2 1;……
思路:

  1. 用for,找個空列表存入前半段數,後半段列表的前n-1個順序反轉一下即可, 這種還是有點慢,每一層還需要重新計算
  2. 用遞歸的方式:f(n) = f(n-1) + 'n' + f(n-1) 

14、數學表達式

題目:數學表達式。給定a和b兩個數,a<=b,把b以a乘2或者加1的最快的方式表示出來。(只能在a的基礎上乘2或者加1)
思路:主要分析b>2a以及b%2=0是否成立, 當b<2a時,只能通過加1達到b,當b爲奇數時通過加減1使b變爲偶數 

15、找出一個集合的所有子集

題目:(重要)找出一個集合的所有子集。打印出來即可。(leetcode上的:https://leetcode-cn.com/problems/subsets/)
思路:

  1. 有n個數字的集合共有2^n個子集。(技巧)第一個爲空集,選出集合的第一個元素放在已有的子集中,再選出第二個元素分別放入已有的子集中,依次遍歷,就找到了所有的子集。如原集合爲{3,2},第一個子集爲空集,接下來取出第一個元素3,放入所有已有子集中,形成新的子集,{} + 3 => {3},現在所有的子集爲{}、{3},再取出2放入所有已有的子集中形成新的子集,形成了{2}、{3,2},一共就有了4子集(這種解法是利用了python的特性)
  2. 回溯法(非常重要,死記)。感覺有點繞,不太理解。

變體:該集合中有重複的元素(可以直接用set去重)。 

回溯法的理解圖

16、尋找旋轉有序數組的最小值

這個題和劍指offer上的那一道一樣,本文上面也有,這次的解題代碼

變體,題目二:在旋轉的有序數組中尋找某個值。【有難度】
思路:

  • 這個題目是有難度的,需要分類討論的情況比較多,本人也是在不斷試錯的情況下解出來的,但明顯沒有答案優秀 

17、搜索插入位置

題目:給定有序數組和一個目標值,如果在數組中找到此目標值則返回與目標值相等的值的index,如果沒有找到,則返回目標值按順序應該被插入的位置。(注:假設該數組中不存在重複數)

思路:有點類似於插入排序。
實際上就是找到第一個大於等於item的數的位置,沒有找到則放在最後的位置上

18、搜索一個重複數字的區間

題目:搜索一個區間。給定一個排好序的有重複數字的array,找到一個給定目標值的起始位置和結束位置。如果都沒有,返回(-2,-2)

思路:
就是先找到第一次出現的位置,再找到第二次出現的位置。【用的是18中的經典二分搜索的方法】
這種解法的時間複雜度爲log(n)+log(n),用for從頭到尾遍歷的時間複雜度爲O(n)

19、在有空字符串隔開的有序array中查找元素

題目:在有空字符串隔開的有序array中查找元素。給定一個有序的字符串序列,這個序列中的字符串用空字符串隔開,請寫出找到給定字符串位置的方法。如[' ', ' ', 1, ' ', ' ',' ', 2, ' ',3]
思路:

  • 沒有什麼好的辦法,第一種辦法直接直接遍歷;
  • 第二種方法二分搜索,先從左右兩端找到非空字符串的位置,然後如果運氣好,碰到中間爲非空比較大小,縮小範圍;如果中間恰好是個非空字符串,則往前(或往後)找到非空字符,比較,再縮小範圍。【個人覺得不是專門搞算法的,這個題沒必要在那點時間複雜度上較勁】 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章