字節跳動上海創新業務(2021屆實習崗)三輪技術面總結

  博主於2020.4月初投了字節跳動 上海創新業務 後端開發實習崗Java方向),並且在2020.5初拿到了客戶端的實習offer,下面分享一下此次技術面試的相關內容。

一、筆試(2020.4.12)

  按各位前輩的說法,字節跳動的內推一般是沒有筆試的,但是我還是有。。。最後發現原來我是直接在字節跳動官網投遞,內推是在字節跳動內推官網,我還是太年輕了。。。
  筆試我現在只記得一道題,總共有四道題,當時AC了三道。不過已經得了一個月,如果後面想起來了,再來補吧。

1、儘量使用優惠卷

題幹:
  給你一個優惠卷數組、準備購買商品的價格數組,並且規定每件商品只能使用金額不大於自身價格的優惠卷(否則商場還得給你找零😂),優惠卷可以重複使用,但是一件商品只能使用一張優惠卷。現在要求你計算使用優惠卷後最小的總價

輸入示例:
  每個測試用例的第一行優惠卷的數量第二行是各優惠卷金額第三行商品數量第四行是各件商品的價格

3
1 2 3
4
2 4 1 5

思路分析:
  水題一道,顯然每件商品應該尋找≤自身價格最大的金額的優惠卷。以我閱題無數道行來看,這道題的關鍵是優化查找,不能每件商品都去搜一遍優惠卷數組,時間複雜度爲O(m*n)(m、n分別爲優惠卷商品價格數組的長度)。
  我們首先對兩個數組進行升序排列快速排序堆排序歸併排序隨便擼一個,時間消耗O(nlogn + mlogm)。然後使用兩個指針,分別從優惠卷、商品價格數組頭部開始掃描。
在這裏插入圖片描述
  這要計算的理由比較簡單,假設我們計算price[i]用了某張最適合的優惠卷coupon[j],那麼計算price[i + 1]用的優惠卷的金額必然不會比coupon[j]小,因此只要後移ptr1指針往後找即可。所以時間複雜度在O(m+n)級別。
  那麼排序+計算總價格的時間複雜度在O(nlogn + mlogm + m + n)級別。這道題測試數據還是比較多的,我最開始寫的是希爾排序,時間複雜度與步長有關,一般認爲時間複雜度爲O(n^(1.3—2))級別,沒有通過,後面修改爲快排才AC。

2、其它不記得了。。。

二、第一輪面試(2020.4.21)

1、自我介紹下吧

姓甚名誰,籍貫啥的,就讀於武漢理工大學 計算機科學與計算學院 計算機專業 本科
大一學了C++、Java
大二學了數據結構、算法,下學期在LeetCode上刷了半年的算法題
大三學了操作系統、數據庫原理、計算機網絡等專業核心課程
同時自己自學了Java web開發技術,SSM、SpringBoot框架,做了一個電商項目
看過分析MySQL、Redis、JVM實現原理的相關書籍

2、數據庫中的事務瞭解麼?有啥特性?

ACID,原子性、一致性、隔離性、持久性
可以特別提下一致性、隔離性的理解

3、MySQL數據庫的隔離級別是什麼?有幾種?分別是什麼?爲什麼要隔離?

如果多事務併發執行,不隔離,會產生問題
①、髒寫。比如事務A將某條記錄的屬性修改爲a,接着事務B修改爲b,事務A再查看。
	發現自己修改的內容被其他事務修改覆蓋了。
②、髒讀。事務A讀到其它事務未提交的事務,比如事務B修改某條記錄的屬性爲a,
	事務A第一次查看是a,此時a是事務B未提交的內容
③、不可重複度。事務A讀到其它事務的修改,比如事務A第一次某條記錄屬性的值爲a,
	事務B將其修改爲b,然後提交了,此時事務A再去查看,發現變成b了,即不可重複度
④、幻讀。事務A讀到其它事務的數據插入、刪除,比如事務A第一次select * from table while a = 'xxx',
	假設數據庫沒有符合條件的記錄,然後事務B插入一條滿足a = 'xxx'條件的記錄並提交事務,
	事務A再次查看,發現突然又查到了。。。就像幻覺一下
注意:不可重複度側重數據修改,幻讀側重數據插入、刪除

四種隔離級別:
①讀未提交。解決了髒寫,存在髒讀、不可重複讀、幻讀問題,同一條記錄
	不能同時被多個事務修改,行鎖就行
②讀已提交(不可重複度)。解決了髒寫、髒讀,存在不可重複讀、幻讀問題,
	此級別獨到的都是提交了的事務B構成的數據集
③可重複度。解決了髒寫、髒讀、不可重複讀,存在幻讀問題
④串行化。解決了髒寫、髒讀、不可重複讀、幻讀,所有事務一個一個排好隊執行,沒有併發問題,可是太慢了

4、熟悉MySQL的存儲引擎嗎?

熟悉innodb,瞭解一點myism

結構上區別,innodb中的主鍵(若沒有主鍵,則使用表中的唯一字段,若唯一字段也沒有,
	自動生成一個唯一id字段標記每一條數據)使用了聚簇索引,索引即數據,數據即索引;
	myism中的使用非聚簇索引,可以沒有主鍵,數據單獨保存在一個文件,索引是索引,數據、是數據;
功能上主要區別:innodb支持事務,myism不支持事務

如果只有查詢,可用myism,有插入(特別是併發插入)一定要用innodb

5、什麼是聚簇索引,聯合索引?

MySQL中的索引分成主鍵索引、二級索引兩大類,也可劃分爲聚簇索引和非聚簇索引兩大類

主鍵索引(若沒有主鍵,則使用表中的唯一字段,若唯一字段也沒有,自動生成一個唯一id字段標記每一條數據),此索引是聚簇索引
二級索引根據非主鍵字段生成的索引

聚簇索引的特點是將所有數據複製到當前B+樹的葉子節點,

一般的二級索引是根據索引字段排序,葉子節點只有索引字段值、主鍵值,
查完二級索引需要根據得到的主鍵值去查主鍵索引(聚簇索引),即要查兩顆B+樹

若某個二級索引是聚簇索引,則其葉子節點包含所有字段信息,查找即可得到所有需要的數據,
此時再去查找主鍵索引(聚簇索引),即只要查一棵B+樹,但是聚簇索引需要浪費存儲空間,因爲要複製一遍數據

那麼聯合索引處於兩種極端之間,根據多個字段建立索引,葉子節點含有建立索引的多字段、主鍵值,
這時就會產生一個問題,查完聯合索引是否要去查主鍵索引?這時看你select的字段是啥,
如果聚合索引的索引字段包括了你要查的字段(索引覆蓋),此時不需要去查主鍵索引,
否則你仍然要根據聯合索引葉子節點的主鍵值查主鍵索引,因此當你查找sql使用聯合索引,儘量將
需要查找的字段設置爲聯合索引中的值(索引覆蓋),可以減少查主鍵索引

6、select * frow table where 字段a < A and 字段b > B,假設它使用了聯合索引<a, b>,大致查找過程什麼?

聯合索引對應的B+樹根據a、b升序排列,存儲引擎訪問聯合索引B+樹,篩選字段a < A的記錄
對應的主鍵值集合,篩選字段b > B的記錄對應的主鍵值集合,然後取交集。不過也可能直接遍歷
一一判斷是否同時符合字段a < A and 字段b > B兩個條件。

使用聯合索引,需要考慮是否會發生索引覆蓋,由於select * 所有字段,
一般的聯合索引得到主鍵值集合,再去查找主鍵索引得到所有字段

7、MySQL執行sql的主要流程?

MySQL是基於C/S模式開發的數據庫管理系統,客戶端把sql傳給服務器,服務器先要驗證身份,
服務器得到sql,先查服務器中的緩存,查到了直接返回,然後對sql進行詞法、語法、語義分析,
再接着進行sql優化,交給sql執行器,最終給到存儲引擎,存儲引擎查到數據返回給客戶端。

(數據庫這塊,中間被面試官打斷了兩次,說深度可以了可以了。。。可我硬是給扯完了😂😂😂)
8、Redis字符串是如何存放的?

Redis自定義了sds數據結構用於存放字符串,該結構主要有len,buf(C格式的字符數組)、
capacity是buf字符數組的長度。由於該結構使用屬性len來記錄字符串的長度,所以是二進制安全,
因爲即使字符串中含有'\0'字符(在C語言表示字符串結束),也不影響長度計算,當你獲取sds字符串
的長度時,直接訪問len屬性,並不需要計算長度。

9、TCP/IP協議瞭解麼?四層/七層模型是啥?

TCP/IP是一個協議簇,包括http、tcp、ip、rip等衆多協議
四層是實際商業標準模型,分別是應用層、運輸層、網際層、網絡接口層,
七層是國際標準組織OSI提出的ISO參考模型,分別是應用層、會話層、表示層、運輸層、網絡層、數據鏈路層、物理層
在計算機網絡學習中,一般劃分爲是應用層、運輸層、網際層、數據鏈路層、物理層

劃分層次,主要是解耦、模塊化,各層只專注自己的功能實現,便宜開發、維護

10、TCP是可靠傳輸?如何實現的?

TCP是可靠傳輸,面向連接,UDP是不可靠傳輸,無連接。
TCP是可靠傳輸,主要是用於協議中設定了通信前要三次握手建立連接,通信完要四次揮手釋放鏈接,
以及協議中設定了流量控制、擁塞避免、自動重傳,滑動窗口算法

11、介紹一下TCP的滑動窗口

滑動窗口是一個發送端虛擬構建的一個控制發送流量的窗口,主要包括起始序號,窗口大小。
比如剛開始startIndex = 0,size = 300,表示發送端最多隻能發送100個字節,假設
發送端發送的一個包起始序號爲0,長度爲50,起始序號爲50,長度爲100的兩個包,如果
接收端接收到第一個包,則需要反饋發送端,確認序號ack=50,表示期待的下一個包的起始下標,
此時窗口更新爲startIndex = 50, size = 300

如果接收端接收不過來了,可以反饋發送端減小滑動窗口的大小,亦或是發送端發現超時未收到
回覆(可能是網絡擁塞),會自動縮小滑動窗口的大小

12、三次握手是什麼?爲什麼要進行三次?四次揮手是什麼?爲什麼要進行四次?

三次握手是TCP協議規定的通信雙方建立連接的過程,主要流程如下:
A發送SYN=1,seq=x給B,(喂,B你聽得到我說話嘛?)
B回答SYN=1,ACK=1,seq=y,ack=x+1給A,(喂,我聽得到,A你聽到我說話嘛?)
接着A發ACK=1,seq=x+1,ack=y+1給B(B,我也聽得到)

三次少一次都不行,A要確定B聽得到自己說話(發包),B也要確定A聽得到自己說話(發包)

四次揮手是TCP協議規定的通信雙方釋放連接的過程,主要流程如下:
A發送FIN=1,seq=x給B,(喂,B,我要關連接了)
B發送ACK=1,seq=y,ack=x+1(喂,A,我知道了)
(可能B還有數據要發送...發完數據後,告訴A,我也要釋放連接了)
B發送FIN=1,seq=y+k給A,(喂,A,我也要關連接了)
A發送ACK=1,seq=x+m(喂,A,下次再見~)

同樣四次揮手,一次都不能少,A發送的關連接請求FIN=1需要得到B的答覆,
此時只能說明A沒有數據要發了,但是B可能還有數據要發,所以發完數據後B也要
給A發送FIN=1關連接請求,並且得到A的回覆確認,雙方纔能真正關連接

13、瀏覽器輸入域名到看到頁面這段時間用了哪些協議?主要乾了什麼事?

第一步:域名解析爲IP地址。首先訪問瀏覽器的域名緩存,沒找到就去訪問計算中的域名緩存、host文件,
再沒找到就需要使用DNS協議(傳輸層用的UDP協議)訪問本地域名解析服務器,如果本地域名解析服務器也不知道,
則需要訪問根域名服務器、頂級域名服務器、二級域名服務器,直到找到域名對應的IP地址
(中間有包的轉發,會用到RIP等路由選擇協議,ARP協議,通過IP地址查MAC地址)

第二步:與服務器建立連接。(假設輸入域名使用http或https協議訪問),http/https協議是應用層協議,
它傳輸層用的是TCP協議,TCP協議在雙方通信前,需要進行三次握手,建立連接

第三步:瀏覽器、服務器傳輸頁面數據。

第四步:釋放鏈接,TCP協議需要進行四次揮手釋放連接。

14、寫下三個線程輪流打印A、B、C

這道題我直接說不會,因爲用Java寫那種沒有代碼提示、自動導包的編輯器裏寫代碼,實在是。。。
其實這種控制線程執行順序的題是比較簡單的,我們設置一個變量m,
m % 3 == 0時,線程1打印A
m % 3 == 1時,線程2打印B
m % 3 == 2時,線程3打印C
每次一個線程打印後m += 1
三個線程需要公用同一個鎖對象,每次判斷m前需要獲取鎖對象。

三面的時候,又碰到這道題,躲肯定是躲不過去的。。。

15、瞭解設計模式麼?Java GUI用了哪些設計模式?

當時並沒有閱讀過相關書籍(正在補。。。),只知道觀察者模式、單例模式、適配器模式。
順帶把單例模式的懶漢式、餓漢式兩種實現方式說了一下。

他這裏問GUI,是由於我簡歷寫一個項目用了它,我當時只說了適配器模式(GUI中有很多事件適配器)。。。

16、單例模式你知道幾種實現方式?

單例模式的餓漢式,設置一個靜態屬性,並且new實例,將構造方法申明爲私有,由於類
一般加載一次,所以在jvm加載該類就創建了一個實例,以後直接訪問這個靜態變量即可
class MyClass{
    // 類加載的時候,直接生成一個實例
    public static MyClass single = new MyClass();
    //構造器私有
    private MyClass(){}
}

單例模式的懶漢式,編寫一個靜態方法,第一次調用的時候調用構造方法,後面再次調用直接返回
之前創建的實例,此種方法存在線程同步問題,需要使用synchronized關鍵修飾(靜態方法,將使用class鎖)
class MyClass{
    // 指向唯一生成的實例
    public static MyClass single = null;
    //構造器私有
    private MyClass(){}
    // synchronized修飾靜態方法,使用的是class鎖
    public static synchronized MyClass getInstance() {
        if (single == null) {
            // 第一次需要生成一個實例
            single = new MyClass();
        }
        return single;
    }
}

17、Java中的HashMap容器是怎麼實現?

通過維護一個table數組(hash桶數組),每次放入一個key-value,根據key計算得到一個
hash值,然後用餘數法,散列到table[hash % 數組長度]的位置

hash衝突問題,存在多個key計算hash散列到同一個table[index](hash桶),此時使用
鏈表將key-value串起來,並且在JDK 1.8的時候,引入了紅黑樹來解決鏈表過長降低效率的問題。
(不好意思,前面分析過JDK 1.8 HashMap容器的源碼,還寫了博客https://hestyle.blog.csdn.net/article/details/105723602

18、ConcurrentHashMap有什麼特點?實現原理?

ConcurrentHashMap支持多線程併發讀寫,在JDK 1.8之前的版本存在段,
多線程讀寫時分段進行上鎖,與hashtable鎖整個容器的相比,大大提高了併發讀寫效率。
在JDK 1.8的時候,移除了段,將鎖的粒度縮小爲table[index]即hash桶,
並且儘可能減少synchronized同步代碼塊中的代碼,進一步提高了併發讀寫效率

(不好意思,前面分析過JDK 1.8 ConcurrentHashMap容器的源碼,還寫了博客
https://hestyle.blog.csdn.net/article/details/105723602

19、JVM中爲啥要分代回收?有哪幾種內存回收算法?

因爲根據實際運行狀態發現,大部分對象用到的時間很斷,多有少部分對象會經常使用,
因此我們需要將那些用幾次就不用的對象回收,(二八原則貌似啥地方都可以套。。。)

內存回收算法主要有標記-清除算法,複製算法、標記-整理算法
標記-清除算法,直接標記需要回收的對象,然後清除,會產生大量的碎片,(回收的小空間不是連續的)
複製算法,將空間分成兩部分,每次只用其中一塊,回收時,將存活的對象複製另外一塊。(減少了可使用空間)
標記-整理算法,標記需要回收的對象,然後將存活的對象複製另一端。(耗時稍長一點)

在這裏插入圖片描述
20、給你一個單鏈表,翻轉[m, n]區間的節點,程序實現一下吧

這道題顯然是一道水題,不過在這一面是第一次手撕代碼,有點緊張,思路有沒有分析,
上來就寫代碼,寫了10幾分鐘還是沒調試成功。。。

比如輸入鏈表1->10->5->20->30->8->90,要求翻轉2-4這一段,
翻轉後的鏈表1->30->5->10->30->8->90

需要分成三段[1, m) [m, n],(n, len]
我當時確實是分三段,寫複雜的地方在於構造新鏈表的時候一個個的調整指針,並且設置一大堆臨時變量。。。
其實[1, m)(n, len]兩段是串接好的,不需要要修改,只要把[m. n]中間段翻轉即可
蠢哭。。。

三、第二輪面試(2020.4.24)

1、前面面試感受如何?

總的來說就是理論部分答得還行,但是手撕代碼部分準備不充分,有點自亂陣腳。

2、學過哪些課程?數據結構、數據庫原理、計算機網絡學過嗎?
3、學過數據庫原理相關的課程吧?第三範式是啥?

第一範式(1NF):表結構,並且表中所有字段都是不可拆分。
第二範式(2NF):滿足1NF,表中任意非主屬性對碼(候選碼)是完全函數依賴。
第三範式(3NF):滿足2NF,表中任意非主屬性對碼(候選碼)不存在傳遞依賴
BC範式(BCNF):滿足3NF,表中任意主屬性對碼(候選碼)不存在傳遞依賴
(其實這裏我不記得,不過面試官引導我從第一範式開始,最終還是答出來了🤦‍♂️捂臉)

可以看出四個範式約束是越來越嚴格,一個表中的字段與碼的關係越來越緊。
如果設計數據庫時不考慮任何範式,也就是表中的字段任意放置,可能會造成插入刪除、刪除異常、更新異常、數據冗餘。
比如某張表(學號(主鍵),姓名,學生學院名,院系主任,課程號,課程名,分數,課程所屬院系名)
顯然
①、數據冗餘。學生每一條選課信息都要與學生所屬院系、課程所屬院系等信息綁定
②、插入異常。如果需要插入某個院系暫時沒有學生,我要插入一個院系、院系主任,這顯然存在插入異常,
	因爲該記錄學號(主鍵)沒有值,但是主鍵不能爲null
③、刪除異常。假設我要刪除某個院系的所有學生,但是保留院系名稱、院系主任,
	在這張表顯然是做不到的,因爲刪除所有學生,則院系信息必然也刪除了
④、更新異常。如果我要更新某個學生所屬院系,由於一個學生肯定不止一條選課記錄,
	所以我們需要修改多條記錄,但顯然只是想改一條記錄。
因此我們需要根據範式約束,將表垂直拆分爲學生信息表、院系表、院系課程表、學生選課表

但是範式約束越強的話,就要分更多的表,本來有些只需要訪問一張表的操作,現在
需要訪問多張表,降低了效率,所以需要根據自己的業務需求進行平衡。

4、某個用戶表,如何查出去重後的名字?如何查出出現多次的名字?

# MySQL中有一個去重關鍵字distinct,只要修飾name字段即可插入去重的名字
SELECT DISTINCT(name) 
FROM table_name

# 根據名字分組,使用having分組條件約束出現大於1的名字
SELECT name 
FROM table_name
GROUP BY name
HAVING COUNT(name) > 1

5、接觸過Linux嗎?用過哪些命令?

文件相關cd、mp、mv、tar、vim相關
ps、kill等
只會常見的命令🤦‍♂️

6、如何查看磁盤使用率?內存使用率?

Ubuntu上有一個top密令,會列出當前系統的內存、磁盤、進程等動態信息

7、一個單核CPU能否進行多進程任務?

可以在宏觀上做到併發,但是微觀上其實還是串行

也就是通過操作系統進行多進程的調度,將時間劃片,分給需要執行的進程,
這樣在宏觀上看起來是多個進程在同時執行,但是隻能稱爲併發,真正的並行需要多核或者多CPU

8、給你一個數組(元素不重複、無負數),如何找出最長的連續序列,請程序實現

最開始的思路是先排序,再掃描升序序列,這樣連續的升序序列很容易計算。
不過時間複雜度在O(nlogn + n)級別

不過面試官提示內存不限制,優化程序,降低時間複雜度。我們可以從排序方式下手,
nlogn級別已經是較高效的了,但是還漏了計數排序,將元素值與數組下標關聯,從而
將排序時間複雜度將爲O(n),但是需要額外的空間(與數組元素最大值有關)

計數排序就不說了,寫下最長的連續序列查找,nums[i] = 0表示i不再給定數組中
int maxLength = 0, startNum = 0;
for (int i = 0; i < length; ++i) {
	// 找到下一個在數組的元素
	while (i < length && nums[i] != 1) {
		++i;
	}
	// 計算以i爲起始的連續序列長度
	int begin = i;
	while (i < length && nums[i] == 1) {
		++i;
	}
	// 更新最長的連續序列長度
	if (i - begin > maxLength) {
		maxLength = i - begin;
		startNum = begin;
	}
}

四、第三輪面試(2020.4.29)

1、自我介紹
2、Java進行線程同步的方式

synchronized與ReentrantLock
synchronized是關鍵字,可修飾方式、代碼塊
分爲同步代碼塊(手動指定鎖對象)、同步非靜態方法(默認爲this對象鎖)、同步靜態方法(默認爲class對象鎖)
ReentrantLock是Lock實現類,需要手動獲取、釋放鎖資源。

3、寫下兩個線程輪流打印1、2、3、4…程序

一面沒答,三面還是碰上了。。。
其實也不難,要用一個鎖,一個計數變量,兩個線程死循環獲取這個鎖資源,滿足條件則打印計數變量
獲取鎖資源後,再判斷計數變量的奇偶性,如果是線程1獲得鎖,並且計數變量是偶數,則線程1打印計數變量,然後釋放鎖
如果是線程2獲得鎖,並且計數變量是奇數,則線程1打印計數變量,然後釋放鎖
其它情況獲取鎖資源的資源直接釋放鎖,
最後再加個while死循環即可

4、Redis有幾種對象類型?

字符串(sds)
列表(zipList或linkedList)
hash(zipList或hashtable)
集合(intset獲取hashtable)
有序集合(zipList或skipList+hashtable)

5、有序集合底層數據結構什麼?

有序集合有兩種數據結構,
一種是zipList,當集合中元素較少,直接開闢一個連續的內存存放
另外一種是skipList+hashtable,跳躍表保持元素遞增,Hashtable用於O(1)級別查找元素

6、Redis持久化是如何進行的?有幾種方式?區別是什麼?

一共有兩種持久化方式,
RDB,將當前數據庫的數據(狀態)完整寫入到一個文件中,恢復時直接讀入內存即可
AOF,將數據庫執行過的命令記錄在文件中,恢復時直接將操作重新執行一遍。由於可能存在
	操作膨脹的狀況(比如返回插入、刪除),所以對操作需要進行壓縮(直接壓縮爲一條插入)
RDB存儲數據,恢復直接讀取到內存,效率較高,AOF記錄數據庫執行過的命令,恢復時,
數據庫需要重新執行一遍所有操作,效率較低。

7、Redis淘汰緩存的策略?

一共有三種淘汰策略
第一種,使用定時器,到時自動銷燬(非常耗資源,加入數據庫有1萬個key-value,就來1萬個定時器?)
第二種,默認不做過期處理,當查詢數據的時候判斷是否過期,過期就報錯,否則返回數據
第三種,使用一個專門的線程檢查各個key-value是否過期,過期就刪除,並且在查詢的時候
	再判斷是否過期,過期就報錯,否則返回數據(前兩種方式的結合)

8、LRU知道麼?如何實現?查找、插入、刪除時間複雜度是多少?

LRU是Least Recently Used的縮寫,即最近最少使用
實現可用一個雙鏈表,每次插入元素放入頭部,訪問元素也將其移動到頭部,每次淘汰都是淘汰
尾部的節點。因此插入、刪除時間複雜度爲O(1),查找時間複雜度爲O(n)

其實同時可以用一個hashmap,將查找時間複雜度降爲O(1)

與之對應的還有一個LFU,即最少使用頻率淘汰,之前刷題刷到過
https://blog.csdn.net/qq_41855420/article/details/88909721

9、手撕快排

快排就不用多講吧,但是手撕代碼的那個在線編輯界面,不能單步調試。。。

快排的思路是每次只歸位一個元素,並且將比它小的元素,比它大的元素區分開。
假設要排序的段爲nums[left, right],我們把nums[left]歸位,比nums[left]小的
放在nums[left]前面,比如nums[left]大的放在它後面,假設歸位後nums[left]下標爲mid
則歸位後順序如下 nums[left ... mid - 1,mid, mid + 1 .. right]
注意這裏的nums[mid]是未調整前的nums[left]
然後遞歸處理nums[left, mid - 1],[mid + 1, right]

五、總結

1、算法、數據結構是重中之重
2、專業核心課程數據庫原理、計算機網絡、操作系統也很重要
3、手撕代碼很重要,不過思路更重要,先想好思路再寫代碼
4、即使程序不能正常執行、沒有單步調試的環境,也要採取簡單的調試方式,比如某段打印標記、打印某個變量的值。這其實是在考你在遇到bug的時候,如何解決問題
5、要自己掌握主動權,儘量往你熟悉的點引

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