據(jù)開發(fā)筆試題B卷解析與備戰(zhàn)攻略)
又到秋招季總有學(xué)弟學(xué)妹跑來問我大數(shù)據(jù)開發(fā)方向的筆試題到底怎么準(zhǔn)備我的建議向來是同一個——先找一套完整的大廠真題從頭到尾認真做一遍比漫無目的地刷幾個月短視頻里的“面試技巧”有用得多。如果你問哪套題最適合用來摸底我通常會推薦愛奇藝2019秋招大數(shù)據(jù)開發(fā)方向筆試題B。原因很簡單這套題覆蓋面夠廣Java基礎(chǔ)、并發(fā)、大數(shù)據(jù)組件、Linux命令、SQL、手寫代碼全都有難度梯度也算合理特別適合當(dāng)成一張“能力體檢表”來用。我當(dāng)年把這套題的回憶版翻來覆去做了三遍后來去其他公司面試時發(fā)現(xiàn)很多考點是相通的。今天就把我對這套題的分析、做題過程中查漏補缺的知識點以及從這套題里反推出來的秋招備戰(zhàn)思路一次性整理出來。不需要你基礎(chǔ)多好只要你有一定 Java 和 Hadoop 生態(tài)的使用經(jīng)驗這篇文章就能幫你把零散的知識串成一條線。1. 這套筆試題為什么值得反復(fù)拆解1.1 從崗位JD反推考察重點想弄明白一套筆試題為什么這么出最直接的方法是看崗位 JD。大數(shù)據(jù)開發(fā)這個崗位在愛奇藝這類視頻平臺日常面對的絕不僅僅是“寫幾個 MapReduce”那么簡單。視頻網(wǎng)站每天產(chǎn)生海量用戶行為日志點擊、播放、暫停、拖拽、搜索、評論、付費這些日志經(jīng)過采集、清洗、ETL、數(shù)倉建模、指標(biāo)計算最終支撐推薦、廣告、會員運營等業(yè)務(wù)方做決策。所以這個崗位要求的能力是復(fù)合的既要懂 Java 這種主力開發(fā)語言又要熟悉 Hadoop、Spark、Flink、Kafka 這套大數(shù)據(jù)生態(tài)組件還要能寫復(fù)雜的 SQL 和 Shell 腳本偶爾甚至要自己調(diào) JVM 參數(shù)、排查線上 OOM。愛奇藝這套筆試B的考點布局基本上就是按照這個能力模型來的。很多同學(xué)拿到試卷第一反應(yīng)是“怎么考這么多 Java 基礎(chǔ)”覺得大數(shù)據(jù)開發(fā)不應(yīng)該只考框架嗎這個認知在面試里很吃虧。大數(shù)據(jù)框架本身就跑在 JVM 上Hadoop、Spark、Flink、Kafka 的源碼全是 Java/Scala 寫的你如果連 HashMap 的結(jié)構(gòu)、并發(fā)編程的基本機制都說不清楚面試官很難相信你能讀懂框架源碼、能定位線上問題。所以 Java 基礎(chǔ)部分不是湊題數(shù)是篩人。1.2 題型分布與答題節(jié)奏從各個渠道流傳的回憶版來看B 卷大致分為四類單選題、多選題、簡答題、編程題。單選多選主要覆蓋 Java 基礎(chǔ)、并發(fā)、JVM、Linux 命令、SQL 語法、大數(shù)據(jù)組件原理簡答題一般會有一兩道讓你描述 MapReduce 流程、Spark 任務(wù)執(zhí)行流程或者數(shù)據(jù)傾斜解決方案的題編程題則是傳統(tǒng)的數(shù)據(jù)結(jié)構(gòu)與算法題偶爾會結(jié)合大數(shù)據(jù)場景。這里有一個很關(guān)鍵的答題節(jié)奏問題選擇題不能戀戰(zhàn)。每道選擇題的分值并不高但如果在兩道爭議題上死磕十分鐘后面編程題的時間就會被壓縮。我記得當(dāng)時給自己定的規(guī)則是單道選擇題最多兩分鐘拿不準(zhǔn)的先標(biāo)記等編程題寫完再回頭蒙。整套題里真正的拉分項永遠是編程題和簡答題不要在基礎(chǔ)題上丟了西瓜撿芝麻。1.3 B 卷背后的“套卷機制”標(biāo)題里的B不是隨便標(biāo)的。大廠筆試通常會在同一時間安排多套試卷題目一樣但順序打亂或者抽選不同子題集目的就是防止前后排考生對答案。這也是為什么你在網(wǎng)上看到同樣的“2019秋招大數(shù)據(jù)開發(fā)筆試題”有人說是 A 卷、有人說是 B 卷題目卻大同小異。準(zhǔn)備的時候不用糾結(jié)自己考的是哪一套考點就那么多把核心知識點全部過一遍任何卷子都能應(yīng)付。2. Java與并發(fā)看起來是選擇題實則是淘汰主戰(zhàn)場2.1 為什么大數(shù)據(jù)開發(fā)要死磕 Java 基礎(chǔ)大數(shù)據(jù)開發(fā)的日常工作中Java 不是“偶爾用一下”的語言而是主力語言。你用 Spark 寫分析任務(wù)雖然可以用 Scala 或者 PySpark但閱讀源碼、調(diào)優(yōu)、排查問題最終都會落到 Java/JVM 層面。愛奇藝這套筆試題里Java 相關(guān)題目占比相當(dāng)高而且考察得非常細。這不是為難人而是想篩掉那些只背框架 API、不懂底層原理的簡歷選手。我之前幫部門做過校招面試發(fā)現(xiàn)一個明顯的規(guī)律Java 基礎(chǔ)扎實的人大數(shù)據(jù)框架學(xué)得也快因為 Spark 的 RDD、DataFrame 也好Flink 的 Watermark、Checkpoint 也罷本質(zhì)上都是 Java 并發(fā)、集合、網(wǎng)絡(luò)編程的封裝。你明白 HashMap 的擴容原理就更容易理解 Spark 的 shuffle 為什么會產(chǎn)生大量小文件你明白 JVM 內(nèi)存模型就更容易理解為什么大數(shù)據(jù)任務(wù)要設(shè)置 executor memory 參數(shù)。2.2 HashMap、ConcurrentHashMap 與并發(fā)安全的底層邏輯集合框架是 Java 基礎(chǔ)題里的“必考點”愛奇藝這套題也不例外。比較有代表性的考察方式是這樣的問題JDK 7 和 JDK 8 中 HashMap 的實現(xiàn)有哪些差異為什么 HashMap 在并發(fā)場景下不安全這個題幾乎每年都出現(xiàn)但能答全的人不多。正確的答題框架應(yīng)該是JDK 7 的 HashMap 底層是數(shù)組加鏈表插入元素時采用頭插法擴容時多線程并發(fā) put 可能形成環(huán)形鏈表一旦 get 的時候發(fā)生死循環(huán)CPU 直接飆滿。JDK 8 改成了數(shù)組加鏈表加紅黑樹鏈表長度超過 8 且數(shù)組長度超過 64 時樹化插入改用尾插法從機制上避免了死循環(huán)問題但并發(fā)場景下仍然可能出現(xiàn)數(shù)據(jù)覆蓋、size 計數(shù)不準(zhǔn)確等問題。所以并發(fā)場景要用 ConcurrentHashMap。如果再追問 ConcurrentHashMap 的原理JDK 7 是分段鎖把整個 Map 分成 16 個 Segment每個 Segment 是一把鎖JDK 8 放棄分段鎖改用 CAS 加 synchronized 鎖住桶的首節(jié)點鎖粒度更細并發(fā)度更高。這種層層遞進的答法比背幾句“線程安全基于 CAS”的面試話術(shù)要顯得有底氣得多。2.3 JVM 與 GC 的考察方式JVM 相關(guān)題目在 B 卷里也占據(jù)一席之地常見考法有內(nèi)存區(qū)域劃分、GC 算法、OOM 場景分析。這類題看起來很“后端”但大數(shù)據(jù)開發(fā)同樣躲不開因為跑 Spark/Flink 任務(wù)時OOM 是出現(xiàn)頻率最高的線上事故之一。我推薦用“畫圖加舉例”的方式復(fù)習(xí)把堆內(nèi)存、虛擬機棧、本地方法棧、方法區(qū)、程序計數(shù)器的職責(zé)先講清楚然后結(jié)合一個具體場景——比如一個 Spark Executor 頻繁 Full GC你會怎么排查一般思路是先用jstat看 GC 頻率再用jmap導(dǎo)出堆內(nèi)存快照用 MAT 分析哪個對象占內(nèi)存最大。如果你能在筆試簡答題里寫出這個排查鏈路面試官對你的印象會明顯不一樣。GC 算法方面CMS 和 G1 的區(qū)別是高頻考點。CMS 基于標(biāo)記清除并發(fā)收集但會產(chǎn)生內(nèi)存碎片G1 把堆劃分成 Region基于 Region 做局部回收可以預(yù)測停頓時間。JDK 9 之后 G1 成為默認垃圾回收器JDK 17 以后 ZGC 開始普及這些演進脈絡(luò)也可以順帶了解。2.4 數(shù)組與指針從 Java 數(shù)組到 C 指針的延伸搜這套題的同學(xué)經(jīng)常會連著搜“數(shù)組和指針筆試題”說明這類題在筆試里出現(xiàn)頻率很高。Java 里沒有指針的概念但數(shù)組本身就是一種引用類型所以考題會圍繞數(shù)組的拷貝、引用傳遞、內(nèi)存分配展開。比如問題int[] a {1,2,3}; int[] b a; b[0] 100;此時a[0]是多少答案是 100。因為b a賦值的是引用兩個變量指向同一塊堆內(nèi)存修改 b 的元素等于修改 a 的元素。這是 Java 基礎(chǔ)題里最經(jīng)典的坑也是很多非科班同學(xué)容易忽略的點。C 語言的指針與數(shù)組又是另一套完全不同的玩法數(shù)組名是常量指針a[i]本質(zhì)上是*(a i)的語法糖。雖然大數(shù)據(jù)開發(fā)崗位基本不會讓你寫 C但筆試偶爾會出這類題來考察計算機基礎(chǔ)是否扎實。應(yīng)對方式很簡單把指針加減、指針數(shù)組和數(shù)組指針、函數(shù)指針這幾個概念過一遍即可不需要深入。2.5 Java 基礎(chǔ)部分的備戰(zhàn)方式針對這套題折射出來的 Java 考點我的建議是不要只看面經(jīng)要自己動手做實驗。比如 HashMap 的樹化條件你就寫一段代碼往 HashMap 里插入哈希值相同的 key觀察鏈表什么時候變成紅黑樹再比如 volatile 的可見性你寫一個多線程程序驗證一下不加 volatile 時死循環(huán)的現(xiàn)象。這些實驗做完之后你會發(fā)現(xiàn)很多題不再需要“背答案”而是憑理解就能推導(dǎo)出來。3. 大數(shù)據(jù)組件原理MapReduce、Spark 與 Kafka 的考察重心3.1 視頻平臺的真實數(shù)據(jù)鏈路愛奇藝這類視頻平臺的數(shù)據(jù)鏈路很有代表性。以一次用戶播放行為為例客戶端上報播放日志到 KafkaFlink/Spark Streaming 消費 Kafka 數(shù)據(jù)進行實時清洗與此同時離線任務(wù)把日志落盤到 HDFS通過 Hive/Spark SQL 做 ETL按天構(gòu)建數(shù)倉分層最終產(chǎn)出播放量、完播率、觀看時長等核心指標(biāo)。理解了這條鏈路你就明白為什么筆試題會同時考察 Kafka、Flink、Spark、Hive 這些組件。它們不是孤立的知識點而是同一套數(shù)據(jù)流轉(zhuǎn)過程中的不同環(huán)節(jié)??荚嚨臅r候別只顧著背每個組件單獨的特性能講清楚一條數(shù)據(jù)從產(chǎn)生到最終形成報表的完整流轉(zhuǎn)過程才是面試官真正想看到的。3.2 MapReduce 與 Shuffle必考的流程題MapReduce 的 Shuffle 過程幾乎是大數(shù)據(jù)筆試的“釘子戶”。愛奇藝這套題簡答題部分很可能會有這么一道描述一個 MapReduce 任務(wù)從提交到完成的完整流程。答題不能只寫“Map 階段輸出中間結(jié)果Reduce 階段匯總”那樣太單薄。完整的回答應(yīng)該包含這幾個階段InputFormat 對輸入數(shù)據(jù)進行切分生成 InputSplitRecordReader 將數(shù)據(jù)解析成 key-value 對Mapper 處理數(shù)據(jù)后map 輸出先寫入環(huán)形緩沖區(qū)默認大小 100MB達到 80% 閾值時觸發(fā)溢寫溢寫前會做分區(qū)和排序默認按 key 的哈希值分區(qū)溢寫會產(chǎn)生多個小文件之后執(zhí)行歸并排序合并成一個大文件同時做 Combiner 局部聚合Reduce 端通過 pull 方式拉取屬于自己的分區(qū)數(shù)據(jù)做一次完整的 shuffle然后再進行分組排序最終調(diào)用 Reduce 函數(shù)。一個容易踩坑的細節(jié)是很多同學(xué)分不清“分區(qū)”和“分組”的區(qū)別。分區(qū)是決定某個 key 進入哪個 Reduce 分區(qū)分組是決定哪些 key 值被認為是同一個 key從而調(diào)用一次 Reduce 方法。在 Hive 中g(shù)roup by作用于分組而 MapReduce 的分區(qū)數(shù)決定 Reduce 個數(shù)兩者不是說一回事。3.3 Spark 核心RDD 依賴、Stage 劃分與數(shù)據(jù)傾斜Spark 的考察重點集中在 RDD 依賴關(guān)系、Stage 劃分、Spark SQL 和調(diào)優(yōu)方向。寬依賴和窄依賴的區(qū)別是必考題。窄依賴是指父 RDD 的每個分區(qū)最多被子 RDD 的一個分區(qū)使用典型操作有 map、filter、union寬依賴是指父 RDD 的每個分區(qū)可能被子 RDD 的多個分區(qū)使用典型操作有 groupByKey、reduceByKey、join。窄依賴的算子不需要 shuffle可以在同一個 Stage 內(nèi)完成寬依賴需要 shuffle是 Stage 劃分的邊界。為什么這個知識點如此重要因為數(shù)據(jù)傾斜通常就發(fā)生在寬依賴的算子上。比如用 groupByKey 做 WordCount某個單詞出現(xiàn)次數(shù)特別多對應(yīng)的 Reduce 任務(wù)就會長時間運行甚至 OOM。解決方案主要是加隨機前綴進行二次聚合、兩階段聚合、調(diào)整并行度、開啟spark.sql.adaptive.enabled讓 Spark 自動做傾斜 join 優(yōu)化。筆試題如果出“Spark 任務(wù)運行緩慢你怎么排查”答題思路應(yīng)該是先看 Spark UI識別出哪個 Stage 耗時最長再點進去看是某個 Task 卡住還是所有 Task 都慢如果是單個 Task 慢基本可以斷定是數(shù)據(jù)傾斜再用sample算子抽樣檢查 key 分布最后根據(jù)傾斜情況選擇加隨機前綴或者調(diào)并行度。3.4 Flink 和 Kafka如果考到會這么出題雖然 2019 年的時候 Flink 還沒有如今這么普及但愛奇藝的實時計算場景早就存在了所以這套題里出現(xiàn) Flink 相關(guān)題目也不意外。Flink 常見的考點是事件時間與處理時間的區(qū)別、Watermark 的作用、狀態(tài)后端、Checkpoint 機制。Kafka 的考點相對更基礎(chǔ)分區(qū)與副本機制、ISR 與 ACK 參數(shù)acks0/1/all、消費者組與分區(qū)分配策略、消息不丟失的保證。有一個很經(jīng)典的連環(huán)題“Kafka 如何保證消息不丟失”答題要從生產(chǎn)者、Broker、消費者三個層面分別說明生產(chǎn)者設(shè)置acksall并開啟重試Broker 設(shè)置min.insync.replicas2消費者處理完成之后再提交 offset。能分三層答基本能拿滿分。3.5 數(shù)倉分層與建模類簡答題大數(shù)據(jù)開發(fā)筆試里最常見的一類簡答題是談?wù)勀銈償?shù)倉是怎么分層的各層的作用是什么一般回答是 ODS、DWD、DWS、ADS 四層模型。ODS 層是源數(shù)據(jù)直接落地保持與業(yè)務(wù)庫一致不做任何加工DWD 層做清洗、規(guī)范化、維度退化統(tǒng)一命名規(guī)范DWS 層按主題匯總比如按用戶、商品、流量主題加工成寬表ADS 層是面向報表和應(yīng)用的數(shù)據(jù)直接對接業(yè)務(wù)方。這道題考察的不只是概念還有你對業(yè)務(wù)的理解。能結(jié)合視頻平臺舉出具體例子最好比如“播放記錄表屬于 ODS 層清洗后的播放明細表在 DWD 層按用戶維度匯總的觀看統(tǒng)計表在 DWS 層最終每日報表在 ADS 層”。筆試的時候如果能寫出這種層級加例子而不是只背四層定義是一個不小的加分項。4. Linux與SQL筆試中的“隱形大戶”4.1 Linux 命令題總是被低估很多同學(xué)備戰(zhàn)大數(shù)據(jù)筆試時會把精力放在算法題和框架原理上對 Linux 命令不屑一顧覺得“反正工作之后再學(xué)也不遲”。但大數(shù)據(jù)開發(fā)這個崗位日常工作的主戰(zhàn)場就是 Linux 服務(wù)器你不會用top、free、df、ps連排查問題都無從下手。所以筆試里出 Linux 題是非常合理的而且考察的點往往貼合實際場景。常見的出題方式不是問“l(fā)s命令的-l參數(shù)是什么意思”而是給你一個實戰(zhàn)場景服務(wù)器 CPU 飆升你怎么找出是哪個進程干的標(biāo)準(zhǔn)答案是先用top查看進程 CPU 占用率再用top -Hp [pid]查看具體線程配合jstack導(dǎo)出線程快照找到出問題的代碼位置。另一個高頻場景磁盤空間不足怎么快速找到大文件df -h看整體使用率du -sh *層層排查目錄再用find / -type f -size 1G直接列出大于 1GB 的文件。這些命令在大數(shù)據(jù)運維里天天都要用筆試考它們就是考察日常積累。4.2 grep、awk、sed 三件套的實戰(zhàn)用法文本處理三件套是 Linux 命令題的重頭戲。比如日志文件access.log的每一行是“IP 地址 訪問時間 請求路徑 狀態(tài)碼”問你如何統(tǒng)計訪問次數(shù)最多的前 10 個 IP。awk {print $1} access.log | sort | uniq -c | sort -rn | head -10這條命令的每一步都值得拆開講awk {print $1}是取第一列sort是排序讓相同的 IP 排在一起uniq -c統(tǒng)計去重后每項的出現(xiàn)次數(shù)sort -rn按數(shù)字逆序排序head -10取前十條。還有一類??碱}是 sed 的原地替換把文件里所有http替換成https并且修改原文件。sed -i s#http://#https://#g config.txt這里沒用常見的/作為分隔符而是用了#主要原因是 URL 里本身包含/直接用/做分隔符需要轉(zhuǎn)義寫成#可以少踩很多坑。這種細節(jié)就是筆試選擇題里的加分點。4.3 SQL 窗口函數(shù)分組 TopN 是最高頻考點大數(shù)據(jù)開發(fā)筆試的 SQL 題基本繞不開窗口函數(shù)。它的典型場景是求每個部門工資最高的員工、求每個用戶最近一筆訂單、求連續(xù)登錄 N 天的用戶。窗口函數(shù)的核心語法就一條row_number() over (partition by 分組字段 order by 排序字段 desc) as rk以“求每個用戶的最近 3 筆訂單”為例select user_id, order_id, order_time from ( select user_id, order_id, order_time, row_number() over(partition by user_id order by order_time desc) as rk from orders ) t where rk 3;這里特別需要提醒一個新手常犯的錯誤子查詢里的rk字段不能在同一個查詢的 where 條件里直接引用比如where row_number() over(...) 3會直接報錯因為窗口函數(shù)是最后執(zhí)行的。必須包一層子查詢在外面過濾。這個坑在筆試里出現(xiàn)頻率特別高因為它考察的是執(zhí)行順序的理解而不是語法背誦。4.4 連續(xù)登錄問題的兩種解法“求連續(xù)登錄 3 天以上的用戶”是另一道高頻 SQL 題它有很多變形比如連續(xù)簽到、連續(xù)購買。核心解法是用date_sub做日期差值。select user_id from ( select user_id, login_date, row_number() over(partition by user_id order by login_date) as rn from user_login group by user_id, login_date ) t group by user_id, date_sub(login_date, rn) having count(1) 3;思路是這樣的先把同一個用戶每天的連續(xù)登錄日期減去行號如果日期是連續(xù)的那么差值會保持不變?nèi)绻虚g斷了差值就會變。所以group by user_id, 差值之后count 大于等于 3 的組就是連續(xù)登錄至少 3 天的用戶。這里有個細節(jié)login_date可能同一天有多條記錄比如用戶一天登錄了兩次直接算行號會把同一天的重復(fù)記錄也算進去導(dǎo)致誤判。所以要先group by user_id, login_date去重再做窗口計算。這個去重的步驟是很多參考答案里沒寫出來的但實際筆試時很容易中招。5. 編程題是拉分項從 TopN 到滑動窗口的破題路徑5.1 編程題到底在考什么筆試的編程題不會讓你寫一個完整的 MapReduce也不會讓你手寫 Spark 算子。它的核心考察點還是數(shù)據(jù)結(jié)構(gòu)和算法只是偶爾會套一層“大數(shù)據(jù)場景”的外衣。愛奇藝這套題的編程部分基本集中在數(shù)組、字符串、鏈表、堆、滑動窗口這些經(jīng)典題型上。刷題的時候不要盲目追求題量先把每一類題型的套路吃透。比如“連續(xù)子數(shù)組最大和”是動態(tài)規(guī)劃基礎(chǔ)題“兩數(shù)之和”是哈希表的典型應(yīng)用“TopK”是堆的經(jīng)典場景“最長無重復(fù)子串”是滑動窗口的標(biāo)準(zhǔn)模板。這四類題掌握之后筆試遇到新題至少不會完全懵。5.2 海量日志 TopK堆是最優(yōu)解結(jié)合大數(shù)據(jù)場景的編程題最常見的是“在一個很大的文件里找出出現(xiàn)次數(shù)最多的 TopK 個單詞”。純算法題版的問法是“求一個無序數(shù)組里的前 K 大元素”。public int[] topK(int[] nums, int k) { PriorityQueueInteger heap new PriorityQueue(k); for (int num : nums) { if (heap.size() k) { heap.offer(num); } else if (num heap.peek()) { heap.poll(); heap.offer(num); } } int[] res new int[k]; for (int i 0; i k; i) { res[i] heap.poll(); } return res; }這里用了一個大小固定為 K 的最小堆遍歷數(shù)組時只要當(dāng)前元素比堆頂大就替換堆頂這樣堆里始終維護著當(dāng)前最大的 K 個數(shù)時間復(fù)雜度 O(n log k)。面試如果追問“數(shù)據(jù)量特別大怎么辦”可以補充說明文件過大無法一次性加載到內(nèi)存時先做哈希分片把大文件拆成多個小文件分別統(tǒng)計每個小文件的 TopK最后再歸并。這道題還有一個高頻變種求第 K 大的元素。用快速選擇算法平均時間復(fù)雜度 O(n)代碼思路是在快排的 partition 基礎(chǔ)上只遞歸處理包含第 K 大的一側(cè)不做全量排序。如果筆試時間充裕寫快選比寫一堆更優(yōu)雅。5.3 連續(xù)子數(shù)組最大和動態(tài)規(guī)劃入門模板“最大子數(shù)組和”是 LeetCode 第 53 題也是筆試編程題里出現(xiàn)頻率很高的一道因為它短小精悍能快速看出候選人的動態(tài)規(guī)劃基本功。public int maxSubArray(int[] nums) { int cur nums[0]; int max nums[0]; for (int i 1; i nums.length; i) { cur Math.max(nums[i], cur nums[i]); max Math.max(max, cur); } return max; }核心邏輯就一行cur Math.max(nums[i], cur nums[i])。翻譯成人話就是“當(dāng)前最大子序列和”要么從當(dāng)前元素重新開始要么帶著前面的累加值繼續(xù)加取兩者較大值。cur維護的是以當(dāng)前元素結(jié)尾的子數(shù)組最大和max維護的是全局最大和。這道題寫出來很容易但想要在筆試里拿滿分還需要在注釋或者旁邊寫明“時間 O(n)空間 O(1)”這能體現(xiàn)你的算法復(fù)雜度意識。5.4 輸入輸出格式筆試翻車的高發(fā)區(qū)域代碼寫對了但是 0 分這類悲劇每年都在發(fā)生。原因絕大多數(shù)不是算法問題而是輸入輸出格式?jīng)]處理好。??途W(wǎng)這類平臺和 LeetCode 不同LeetCode 已經(jīng)幫你把函數(shù)簽名定義好了你只需要填函數(shù)體??途W(wǎng)需要你寫完整的public class Main自己用Scanner讀取輸入再按指定格式輸出。很多同學(xué)平時只刷 LeetCode不熟悉這種“自己處理輸入輸出”的方式筆試時一緊張Scanner 的循環(huán)讀法都寫錯了。我建議在秋招開始前去??途W(wǎng)上把近三年的真題模擬題都做幾道專門練習(xí)完整的代碼結(jié)構(gòu)。記住一個通用模板import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc new Scanner(System.in); int n sc.nextInt(); int[] arr new int[n]; for (int i 0; i n; i) { arr[i] sc.nextInt(); } // 處理邏輯 System.out.println(result); } }還有一個容易被忽略的點有些題目要求輸出結(jié)果保留兩位小數(shù)比如System.out.printf(%.2f, result)有些要求多個結(jié)果之間用空格分隔最后一個后面不能有空格。這些細節(jié)在筆試環(huán)境里一旦出錯會直接判定答案錯誤比算法沒寫出來還可惜。6. 從這套筆試反推秋招備戰(zhàn)我的幾點實踐復(fù)盤6.1 原理與刷題的時間配比我見過太多人備戰(zhàn)大數(shù)據(jù)開發(fā)筆試要么只刷算法題要么只看框架面經(jīng)這倆都是極端。愛奇藝這套題給我的最大啟發(fā)是它同時考察原理深度和代碼熟練度兩邊的權(quán)重其實差不多。比較合理的安排是五五開一半時間用來深入理解 Hadoop、Spark、Kafka 的核心機制另一半時間用來刷算法題和 SQL 題。原理部分不要停留在“會用”層面要能用自己的話講清楚 MapReduce 的 Shuffle 過程、Spark 寬窄依賴、Kafka 的 ISR 機制。SQL 部分不要只看題解一定要親手在本地或者在線環(huán)境跑一遍。我自己復(fù)習(xí)時有一個笨但有效的方法把每個核心知識點抄在一張 A4 紙上只寫關(guān)鍵詞和流程箭頭不看資料對著這張紙口述講一遍。講不出來的地方就是知識盲區(qū)回頭再去看那塊的源碼或博客。這個方法堅持兩周效果比反復(fù)讀書好得多。6.2 筆試現(xiàn)場的答題順序與時間切分真正坐在筆試考場里心態(tài)和平時刷題完全不一樣。我總結(jié)了一套當(dāng)時用著很順的答題順序先花一分鐘掃一遍全部題標(biāo)記出編程題的大致難度然后按順序做選擇題遇到卡殼的直接跳過選擇題做完后先做會寫的編程題再做簡答題最后回頭處理跳過的選擇題和自己不熟悉的編程題。時間切分上我一般會把整個筆試時間的 50% 留給編程題30% 留給選擇填空20% 留給簡答。因為編程題是按通過用例給分的寫出來大部分用例可能就能拿到 60% 到 80% 的分數(shù)這比在選擇題上糾結(jié)半天的性價比高得多。6.3 復(fù)盤比刷題更重要做完一套題對照答案估分只是第一步更重要的是把錯題涉及的每一個知識點都深挖一遍。我會為每道錯題建立一個類似“問題是什么、涉及的知識點、根本原因、同類題型的解題模板”的卡片然后每周集中回顧一次。比如我在做 HashMap 相關(guān)題時錯過一次“JDK 7 頭插法和 JDK 8 尾插法的原因”這個點復(fù)盤的時候我就專門去看 JDK 8 的源碼把putVal方法整個讀了一遍又畫了擴容前后鏈表結(jié)構(gòu)的示意圖。從那以后凡是遇到 HashMap 并發(fā)問題我基本不會再丟分。這種“以題帶點、以點帶面”的復(fù)盤方式比再刷十套新題更有效果。6.4 最后分享一點心態(tài)上的體會準(zhǔn)備秋招筆試的過程確實枯燥尤其是當(dāng)你發(fā)現(xiàn)同一道題做了三遍還是會錯的時候很容易自我懷疑。但大數(shù)據(jù)開發(fā)這個方向本來考查的就是知識廣度和深度并重一時半會兒記不全太正常了。我自己的體會是把每一次筆試都當(dāng)成一次免費的學(xué)習(xí)機會題沒做完不要緊關(guān)鍵是從中提煉出哪些知識點還沒掌握、哪些代碼模板還不夠熟練下一次進場多拿幾分就足夠了。