疫情已經好轉,待工在家很迷茫,看完快手4月,5月的Java崗面經的整理,準備上戰場。

所有內容整理自牛客網其他同學的面經,疫情已經好轉,希望可以給要去找工作的朋友一些好的建議,拿到心儀公司的公司。

一面:

基礎知識

1、java基本數據類型(8種)

1.基本數據類型有哪些,各佔多少位,浮點型表示能否精確的表示小數,int的範圍(這個當時腦袋可能抽了,順嘴說了2^-32到2^32 - 1,面試官可能知道我的意思,沒有指出)最大值爲什麼要減一,int的最小值在計算機中怎麼表示(我回答的是二進制表示,沒有思考直接說是32位全是1,回答錯了,實際是10000....0000) 這個知識點很久沒有看過了,所以回答的不是很好。

10.private那四個權限的限制
答:一個是標記的變量只能自己使用,一個是標記的變量可以讓父子都可以訪問,一個是可以接收同一個包的其他類的引用,一個是所有的其他包都可以引用。

4.反射的作用及機制

3.泛型,子類繼承父類的public可以寫成private嗎(竟然回答錯了,這地方拉跨了,基礎還得鞏固)(不可)

1.數組構造過程:

當時面試官就打在屏幕上:描述 int[] Array={1,3,5,7,9}的構造過程。我問您是指什麼,就告訴我說描述下怎麼創造出來的?但我還是沒聽懂?後來問各種同學才知道應該是想說數組內存的分配方法,就是棧裏開闢地址空間,將Array指向地址,然後堆裏分配連續內存這意思

9.Integer和int的初始化以及是否相等問題

還有一道題,是這樣的:Number[] a=new Integer[]{0},問,編譯是否通過?
答:我說的是,編譯不可以,賦值的時候,沒有指定大小。結果是,不會有錯誤。。。因爲後面賦值{0},就代表,這個數組的大小賦值爲了1,而且初值爲0。

接口裏面可以實現方法嗎?

java幾開始接口可以寫方法體的

5:重載與重寫

(面試官還寫了例子讓我判斷是不是重載)

instanceof

new一個對象 操作系統層面是怎麼分配內存的

2.說幾種創建對象的方式

一個進程是怎麼跑起來的

8.然後繼續考察Java的基礎。問了幾個位運算符號以及==和equals,float和double的一點細節(回答不出來了)

1.==和equals區別

1.==和equals區別

4.爲什麼要重寫equals方法

7.對java底層代碼的瞭解,如何判斷字符串相等

2.static修飾的成員變量運行時機

3.內部類和靜態內部類區別

7.說一下序列化,網絡傳輸使用什麼序列化

8.說一下泛型底層實現原理—類型擦除

14.面試官寫了類繼承代碼,問輸出順序。(靜態代碼塊、非靜態代碼塊、構造函數的加載順序)

8:攔截器與過濾器

2.介紹多態

5.String、StringBuilder、StringBuffer

3.final、finally、finalize的區別

2、final、finally、finalize的區別 (修飾符、異常處理、垃圾回收)對了這裏死磕了一陣finally的調用時間,開始胡說

1 jre和jdk的區別

3.error和exception的區別。舉例子
答:error是錯誤,而exception是異常。
error是jvm無法解決處理的錯誤,一旦發生,進程壞死,停止運行。常見的錯誤有:oom,NoClassDefFoundError,StackOverflowError。
而exception是異常。有兩個類別:運行期和非運行期:
其中運行期是程序負責搞定的,即,不要catch的,而非運行期是編譯器負責的,要顯式的catch。
運行期異常有:空指針,下標越界異常,數字格式異常
而非運行期有:ClassNotFoundException和IO操作異常。(這兩類是要顯示捕獲的,所以加載mysql驅動的時候,要catch。)

4.補充一個:ClassNotFoundException和NoClassDefFoundError的區別
答:
當應用程序運行的過程中嘗試使用類加載器去加載Class文件的時候,如果沒有在classpath中查找到指定的類,就會拋出ClassNotFoundException。
當JVM在加載一個類的時候,如果這個類在編譯時是可用的,但是在運行時找不到這個類的定義的時候,JVM就會拋出一個NoClassDefFoundError錯誤。比如當我們在new一個類的實例的時候,如果在運行是類找不到,則會拋出一個NoClassDefFoundError的錯誤。
(這個情況是我們的class文件被刪除了)
總結:當動態加載Class的時候找不到類會拋出異常,當編譯後找不到類的時候,會拋error

3.介紹handler

Throwable接口下的異常和錯誤,只問了層次結構

1.JAVA的終端命令有什麼,環境配置是什麼

2.MAVEN的終端命令有什麼

Lambda表達式

函數式編程

命名函數

集合

4說一說知道哪些集合

List常用的實現類

ArrayList與LinkedList區別

5 ArrayList和LinkedList

6插入元素時間複雜度

7新建一個ArrayList會分配內存嘛

8 ArrayList擴容的時機

9 ArrayList什麼時候縮容

10 LinkedList插入int

11誰實現int裝包的,是List嗎

12 ArrayList線程安全嗎,說說你知道的線程安全的List

13 Collections.同步方法和copyonwriteArrayList的異同點

ArrayList和LinkedList的區別

ArrayList擴容機制,上次看ArrayList源碼還是去年9月份,,,真的忘了,只記得1.5倍擴容和grow方法的流程,其他的模模糊糊。我回答到當擴容1.5倍之後還不能滿足大小,就直接將需要的大小設置爲要擴容的大小。面試官可能將計就計的問了我add方法一次添加一個元素爲什麼會不滿足條件呢,當時內心有點懵,所以也沒回答出來,面試官又問如果讓你去寫這個代碼,你覺得的該怎麼寫,只說思路就好。我就講了一下自己的想法,這才結束了這個話題,害,健忘的我。

面試官在對話框裏列出了ArrayList很多API,讓我逐個分析他們的時間複雜度。

2.hashmap的複雜度 O(1),有鏈表還得算鏈表,大於8變紅黑樹

hahsmap的擴容。
答:就是新開一個2倍大小的空間,然後用頭插法插入到新的位置;而1.8版本的話,是會用位運算求出節點的位置。

萬年不變的集合開頭,hashmap底層數據結構,什麼時候轉化爲紅黑樹,put操作的流程,講定位下標的時候說到了擾動,又問擾動的過程和好處(講一半小哥哥網不穩定,掉線了,,,)

hashmap線程安全嗎?線程安全的方式有哪些?

concurrenthashmap怎麼樣去保證線程安全的

5.hashmap、hashtable、concurrenthashmap

講講hashmap

HashMap底層數據結構實現
紅黑樹能不能再變回鏈表
爲什麼在8個的時候轉化爲紅黑樹
HashMap是線程安全的嗎
如果一個在讀寫操作,另一個在擴弄,會不會有問題

5:併發包、ConcurrentHashMap等

5.HashMap底層數據結構,以及put方法和resize方法

6.說一下ConcurrentHashMap底層數據結構,以及如何保證線程安全的

講講java中的集合類,Comparable接口和Comparator接口

多線程

1.說一下JUC包下的同步工具

2.synchronized修飾方法和代碼塊區別

3.volatile如何怎麼保證有序性和可見性

1

2

3

4

5

6

7

8

9

10

11

12

1lock指令

volatile修飾的變量,執行寫操作的話,JVM會發送一條lock前綴指令給CPU,CPU在計算完之後會立即將這個值寫回主內存,同時因爲有MESI緩存一致性協議,所以各個CPU都會對總線進行嗅探,自己本地緩存中的數據是否被別人修改

 

如果發現別人修改了某個緩存的數據,那麼CPU就會將自己本地緩存的數據過期,然後這個CPU上執行的線程在讀取那個變量的時候,就會從主內存重新加載最新的數據。

 

lock前綴指令 + MESI緩存一致性協議

 

2)內存屏障:禁止重排序

 

底層就是插入了XX內存屏障,XX內存屏障,就可以保證指令不會重排

 

對於volatile修改變量的讀寫操作,都會加入內存屏障

1.多個線程同時對volatile類型的變量進行i++操作,可以保證結果嗎,爲什麼不能,說說volatile的原理,那我們在什麼時候使用volatile是正確的,剛纔的場景怎麼保證結果(synchronized),說說sync的原理,它和ReentrantLock有什麼不同

22怎麼保證線程安全

23說說volatile

24 volatile爲什麼不保證原子性

25 volatile和final的共同點

8.synchronized關鍵字9.volatile關鍵字

26 synchronized可重入嗎,怎麼實現的

27 synchronized怎麼實現線程安全的。

2.說一下synchronized,volatile。

4.說一下synchronized原理,使用方法。對象鎖和類鎖互斥嗎?不互斥

13.synchronized和reentrant鎖區別

11.synchronized和reentrant鎖

2.Java的加鎖的方式,讀寫鎖的實現,synchronized和reentrantlock的比較,CAS的實現

11.ReentrantLock加鎖操作後,在catch中捕獲的是什麼異常,爲什麼會發生這用異常

4.Java中的鎖,volatile的相關原理,應用場景等

4.以統計接口訪問量爲背景,寫了一段代碼,主要工作就是多線程訪問下方法內實現counter++,是否能達到效果?爲什麼不能?爲何不是原子操作,分成了哪些步驟?那通過什麼方法去完成這個任務,回答了atomiclong和加鎖

3.說一下AtomicInteger。

講講AtomicInteger的實現原理,Atomic開頭的類經常會有一個方法叫lazySet,講講它的作用

10.i++是不是一個原子操作,說幾種方法java如何保證對整型變量寫操作線程安全的方法

11.工廠模式

15.java interrupt(不瞭解,後來去查一下是線程的中斷機制)

9:創建線程的方式以及區別

線程有幾種狀態
創建線程的有幾種方式

4:java多線程的內存模型

8.進程和線程,進程和線程的通信方式,進程調度算法

3、多線程的理解

2.對死鎖,多線程的瞭解,具體實例

7.jvm多線程內存

3.線程的幾個狀態以及狀態之間轉換的方法

5.線程的幾種狀態,並指出在哪種狀態下可以中斷,中斷原理

10.項目中有沒有用到多線程,怎麼用的

線程池瞭解嗎?兩個提交方法一個是submit一個是execute,有什麼區別?

4.介紹threadLocal

9.線程池的原理

5.線程池的作用,sleep和wait。

5.線程池重要參數,處理任務流程

6:Excutors、 線程池的參數含義以及線程池的工作原理

7:什麼時候用到線程池的拒絕策略

說說線程池的工作流程,4種拒絕策略,4種隊列,其中一個線程掛掉了會怎麼樣

4.說一下線程池,以及線程池的幾個核心參數,如果提交一個cpu密集型的任務怎麼選取線程池

5.線程池簡單描述

14 copyonwriteArrayList,咋實現線程安全的。

15 copyonwriteArrayList的加鎖時機

16 copyonwriteArrayList寫的時候讀會讀到空數據嗎

17線程如何創建

18繼承Thread和實現Runnable接口的區別,這兩者的繼承關係

19線程池的參數有哪些,挑重要的解釋一下

20線程池怎麼保證線程一直運行的

21單線程線程池的應用場景

28鎖升級的過程

29說說自旋鎖咋實現的

30讀寫鎖咋實現的

31說說CLH

14.還有一道題是countdownlatch的,看代碼,判斷輸出是什麼。
答:我看了以後,發現沒有保證原子性,所以i++輸出的結果不會如預期。而後讓我將他改爲串行,我用了join,用了lock,用了sysc三個進行上鎖。實現了一個同步。同時,爲了保證可見性,還在共有變量上加上了一個volatile。

JVM

Java8的JVM結構

2講講java類加載

3類加載器

12.類加載機制(加載和初始化問的比較詳細)

類加載過程,雙親委派模型的優缺點

類加載過程

爲啥要雙親加載

jvm(

1.說一下幾種引用方式,並說出其作用,以及垃圾回收時機

2.一個static成員變量如何進行內存分配及賦值

)

說說Java的GC機制,講講G1

垃圾回收算法

詳細說一說CMS

每種垃圾回收算法的原理和適用,G1簡單說了下設計思想

4:jvm內存結構

13.java內存,堆和棧

JVM內存劃分
堆的話怎麼劃分
常量池放什麼
常見的GC算法

5.強應用和弱應用和軟引用的區別。
答:強引用,就是標記了引用,不會直接回收的;而弱引用是gc下一次回收會發現的。而軟引用我忘了,回答不知道。
回去好好查了一下後發現:
強引用,在內存不足的時候,寧可報錯:oom,也不會回收。而我們程序中有些對象其實沒有這麼重要,那些對象我們可以用引用級別標明。這樣內存不足的時候,標記了軟弱虛引用的對象會被回收。
而軟引用是:在gc後還內存不足的時候,纔會去回收,平時不會回收;
弱引用是:在GC的時候,不管內存空間足不足都會回收這個對象。
虛引用:直接回收了,就像沒有引用一樣gcroot找不到一樣。但是會有一個回調函數,比如打印一個日誌:我被回收了之類的。

數據結構

4.B樹和B+樹共同點、區別,優缺點

7.B樹和B+樹

38 B+樹和B樹的區別

39 B+樹數據太多了會怎麼樣

40 B+樹聚簇索引和非聚簇索引

41 B+樹存儲結構,在磁盤上(沒理解啥意思)

2.說一下樹,哈夫曼樹,二叉樹,搜索樹,平衡樹,紅黑樹。

什麼是平衡樹回答不滿意

3.Java中哪些類用到了上述的樹。

什麼叫穩定排序

堆排序是穩定排序嗎回答錯了

快排是嗎

2.桶排序時間複雜度,快速排序,堆排序時間複雜度

常見排序算法的時間複雜度(幹,我爲什麼要說桶排序,明明不記得了)

計算機網絡

TCP連接斷開的流程簡單描述

2.問了本科的時候一個關於通信軟件的項目,主要是問TCP/UDP,TCP三次握手

HTTP的四次揮手講一下?每個步驟進入的狀態一定要記住(回答的不好)

3.TCP保證有序傳輸的是什麼技術。校驗和,流量控制,擁塞控制,連接管理,確認應答,超時重發都答了。完美避開了序列和,就純屬蠢

5.網絡協議哪些層,用了哪些協議說一下。

6.TCP和UDP的區別。

8.tcp和udp的區別,各自的適用範圍是什麼,能否只用其中一種

9.httpp和tcp/udp有什麼區別,http和https的區別,怎麼樣保證安全,爲什麼將兩種加密方式結合起來,怎麼樣結合。

7.http和https的區別

8.http如何在一個TCP連接上進行多次請求響應的

10.上面說到http建立在tcp連接上,所以開始了http和tcp連接之間的各種關係,這塊複習的比較少,講的不太好,問到了長連接/短連接,哪個版本開始支持長連接。一個tcp連接是否可以併發,這個沒有複習到,所以一開始回答不能,後來面試官就問,如果現在一個網頁要加載很多張圖片,他們應該怎麼樣加載,根據平常上網經驗,明顯是多個圖片同時向下加載,所以隨即改口。可能面試官知道我不太明白這塊,也就結束了。

6、http協議各個版本的區別 (長連接短連接)

7、網絡模型的各個層以及作用

8、數據鏈路層的功能細節

1. 計算機網絡的7層結構:
答:物理層,鏈路層,網絡層,傳輸層,應用層(應用層,展示層,通信層)

2. tcp的三次握手,以及爲什麼要三次握手。
答:防止消息在網絡中延遲,導致建立無用的通道

11.http的狀態碼和每個狀態碼的含義
答:我說出了5類狀態碼的含義,但是,每一類狀態碼中,具體每個類別有那些碼,我還真不知道。這個問題,發現很多面試官喜歡問,要好好準備這個了。

12.網絡中傳輸層的作用
答:就是跨主機兩個進程之間通信,比如接用tcp之類的,端口端口之間搭建通道,就是傳輸層解決的。讓兩個進程可以實現通常。屏蔽了網絡,物理等底層。

操作系統

4、線程的調度是誰命令的 直接蒙掉

5、數據是怎麼保存到硬盤的 再次蒙掉

shutdown和shutdownnow的區別

shutdownnow是立刻就停止嗎?會先調換中斷,不會立刻停掉的

Linux

10.linux常用命令,以及對於文件的操作

數據庫:MySQL

MySql存儲引擎都有什麼

MyISAM的優點是什麼?查詢爲什麼這麼快

6.MyISAM和InnoDB的區別

37 MySQL用的是什麼引擎,索引是啥

Myisam與InnoDB的區別
如何理解事務,事務解決了什麼問題
ACID
事務的隔離級別

5.事務的隔離級別和事務併發的問題

7.事務的ACID特性,然後說了下事務隔離級別以及數據庫上的實現。刪除一條不存在的數據會加鎖嗎(emmm,沒試過)

髒讀,不可重複讀,幻讀

InnoDB解決幻讀了嗎
如果第一次Select出來只有一條,第二次出來是兩條,這是幻讀嗎

第一次查詢張三這個人系統沒有,嘗試插入張三,提示主鍵重複,是不是幻讀

聚集索引
聯合索引底層是什麼結構什麼樣子的
討論例子能不能命中索引

寫SQL的注意事項

寫個sql:課程名中包含‘計算機’的課程 且 成績小於60分學生的 學號、姓名

1

2

SELECT stu.id, stu.name FROM stu, stu_score WHERE stu_score.coursename = '計算機'

AND stu_score.score <60 AND stu.id = stu_score.stuid

數據庫中JOIN是怎麼實現的,IN呢

4.mysql索引

4.mysql的索引,分頁查找,如果要查找很靠後的頁面如何,比如100萬之後查10條怎麼優化()

6.數據庫索引、非聚簇索引和聚簇索引

講下MySQL的聚簇索引

聚簇索引哪個引擎在用?只有InnoDB嗎?

InnoDB索引採取什麼數據結構

說說聚集索引和非聚集索引,mysql的4種事務隔離級別,InnoDB在Repeatable_Read下爲什麼不會幻讀,索引爲什麼用B+樹,B+樹和B樹的區別

7.數據庫索引底層數據結構是什麼樣的

6.next_lock,快照讀和當前讀,MVCC

6.數據庫問題,表結構是t ,sql語句是select * from t where a= , b= , c= 問這個語句執行的效率,我當時直接說會很慢,可以建立聯合索引,然後就開始了最左匹配原則的各種情況。最後一個問題是如果查詢條件固定,聯合索引的順序怎麼樣安排比較好,之前沒考慮過,只能當場思考,回答的是區分度較高的排在前面,讓搜索的範圍儘早縮小。可能解釋不太明白,面試官出了具體的場景問我,才作罷。

動態SQL

order by在數據庫innodb的實現過程沒答出來

limit會對前面的數據進行IO嗎

數據量大limit的解決方案

數據庫一定會走索引嗎回答了最左匹配原則和索引沒及時更新數據位置,沒答到他想要的點,他想問的是where語句中出現了!=,會走索引嗎

K>某個值,索引會失效嗎?MySQL會判斷一下全盤掃描的成本和走索引的成本

Elasticsearch 是一個分佈式、可擴展、實時的搜索與數據分析引擎

es有哪兩種交互方式?

es底層數據結構(不知道)lucene

Redis

32 redis你咋用的

33 redis的淘汰策略

4.redis會嗎,不咋懂

34定期刪除咋實現的

35 redis中lru咋實現的

36 redis內存滿了會怎麼樣

3.redis的底層數據結構

7.redis的使用,分佈式鎖,各種數據結構以及相應的應用。redis的讀併發量和寫併發量

4.redis怎麼用,用來存儲什麼的

Spring

spring的ioc和aop
答:簡單解釋了一下,動態代理和代理的兩個類別;還有就是反射機制實現了ioc加載bean。而aop是動態代理實現了擴招功能。

6.Spring IOC

8.spring bean

8.spring的AOP應用,原理是啥

2:Spring IOC

說說Spring IoC機制,以及實現原理

講講你熟悉的Java設計模式,知道裝飾者模式嗎,IoC機制符合了Java設計模式的什麼原則

6.項目中如何用到IOC思想的

3: Spring AOP

說說Spring AOP

5.說一下spring中IOC和AOP,還問了這個兩個的英文全稱是啥(差點沒說出來)

3.靜態代理和動態代理的區別

6.Spring的IOC和好處,AOP,問了動態代理的實現,兩種動態代理的。還問了具體怎麼寫一個切面類,還要不要加Component(又回答錯了)。

7.面試官:項目怎麼部署的。我:單機項目,springboot內嵌的tomcat。面試官: 那你訪問頁面的時候怎麼找到你的方法?我:一開始沒聽明白,後來理解了,是url訪問的流程加springmvc的過程,emmm不好意思,中間忘記說tomcat幹啥活了

SpringMVC的從接受請求到響應請求的一個流程

映射信息存放在什麼地方

filter和interceptor的區別

Inteceptor有辦法能得到HttpServletRequest的信息嗎?

Cookie可以得到,那RequestBody能到嗎?RequestBody只能被讀取一次

Spring注入有哪幾種方式,有什麼區別嗎?

比如說Autowired注入的話,經過哪些流程(沒答出來)

注入的過程發生在什麼時期我答的是初始化容器的時候

又問了一下是發生在編譯期還是運行期

IOC實現機制

IOC的好處?對業務開發的好處在什麼地方?我回答的是解耦

就比如注入的時候,我會依賴一個接口的注入或者基類注入,這種的話,怎麼找到它的實例呢?

同一個工程下不同包下定義了兩個同樣的類,會出現問題嗎?

AOP講一下

有哪幾種實現方式

AOP和AspectJ區別

MyBatis緩存機制

消息隊列

kafka瞭解麼,說說你對他的理解

3.消息隊列怎麼用的,什麼作用

zookeeper(我答的不好)

Zookeeper可以幹嘛,咋實現的,我不會

安卓

6.A活動啓動B活動過程中兩活動生命週期函數的調用順序。如果中間A活動調用finish()呢

要手寫的

單例模式

9、單例模式

10.手寫單例模式 1.寫一個單例模式,

4.線程安全的單例模式:雙重檢查寫法

4.用volatile+synchronized寫一個單例模式,用雙重校驗鎖方法,說出兩個if判斷語句的作用

寫個單例保證線程安全(雖然寫出了,但被問住了,告訴我代碼不能死記硬背)

爲什麼還要再判斷一次是否爲空

怎樣保證這個單例在序列化和反序列中還是這個單例枚舉

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

class Singleton{

    public static volatile Singleton uniqueInstance;

    public static Singleton getUniqueInstance(){

        if(uniqueInstance==null){

            synchronized(Singleton.class){

                if(uniqueInstance==null){

                    uniqueInstance=new Singleton();

                }

            }

        }

        return uniqueInstance;

    }

    public static void main(String args[]){

        for(int i=0;i<50;i++){

            new Thread(new Runnable(){

                public void run(){

                    System.out.println(Thread.currentThread().getName()+":"+Singleton.getUniqueInstance().hashCode());

                }

            }).start();

        }

    }

}

寫一個單例模式

答:一個類的構造函數私有化,然後在類中定義一個私有靜態變量,通過一個靜態函數get獲得私有變量實例即可實現單例。如果想要懶加載,可以用上雙重檢驗鎖在get函數中。

生產者消費者線程同步

4.寫一下阻塞隊列。

我用ArrayBlockingQueue實現的生產者消費者模型

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

public class ArrayBlockingQueueDemo {

    private ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue(3, true);

 

    public static void main(String[] args) {

        ArrayBlockingQueueDemo test = new ArrayBlockingQueueDemo();

        Consumer c1 = test.new Consumer();//內部非靜態類實例化方式

        Producer p1 = test.new Producer();

        ExecutorService service = Executors.newCachedThreadPool();

        service.execute(p1);

        service.execute(c1);

        //new Thread(p1).start();

        //new Thread(c1).start();

    }

 

    class Consumer extends Thread {

        @Override

        public void run() {

            try {

                while (true) {

                    System.out.println("消費" + blockingQueue.take());

                    if (blockingQueue.size() == 0) {

                        System.out.println("隊列爲空,阻塞");

                    }

                }

            } catch (InterruptedException e1) {

                System.out.println("消費者等待時被打斷");

                e1.printStackTrace();

            }

        }

    }

 

    class Producer extends Thread {

        private int element = 0;

 

        @Override

        public void run() {

            try {

                while (element < 20) {

                    System.out.println("生產" + element);

                    blockingQueue.put(element++);

                }

                if (blockingQueue.size() == 20) {

                    System.out.println("隊列滿,阻塞");

                }

            } catch (InterruptedException e) {

                System.out.println("生產者等空閒時被打斷");

                e.printStackTrace();

            }

            System.out.println("終止生產");

        }

    }

}

9.手寫一個生產者消費者模式,用的ReentrantLock,爲什麼判斷當前count是否滿足生產或者消費時用while

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

public class ProducerAndConsumer {

    private int number = 0;

    private final int MAX = 10;

    private final int MIN = 0;

    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

 

    public static void main(String args[]) {

        ProducerAndConsumer test = new ProducerAndConsumer();

        Consumer c1 = test.new Consumer();

        Producer p1 = test.new Producer();

        ExecutorService service = Executors.newCachedThreadPool();

        for (int i = 0; i < 10; i++) {

            service.execute(p1);

        }

        for (int i = 0; i < 5; i++) {

            service.execute(c1);

        }

    }

 

    class Producer extends Thread {

        public void run() {

            try {

                lock.lock();

                while (number >= MAX) {//不用if是因爲可能有錯誤喚醒的線程,while可以進行多次判斷

                    System.err.println("產品已滿");

                    condition.await();

                }

                number++;

                System.out.println("生產了一個產品,現在有:" + number + "個產品");

                condition.signalAll();

            } catch (InterruptedException e) {

                e.printStackTrace();

            } finally {

                lock.unlock();

            }

        }

    }

 

    class Consumer extends Thread {

        public void run() {

            try {

                lock.lock();

                while (number <= MIN) {

                    condition.await();

                }

                number--;

                System.out.println("消費了一個,現在有" + number);

                condition.signalAll();

            } catch (InterruptedException e) {

                e.printStackTrace();

            } finally {

                lock.unlock();

            }

        }

    }

}

LRU

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

//https://blog.csdn.net/u013568373/article/details/90607083

import java.util.LinkedHashMap;

 

public class LRUCache extends LinkedHashMap {

 

    //首先設定最大緩存空間 MAX_ENTRIES 爲 3;

    private static final int MAX_ENTRIES = 3;

 

    //之後使用LinkedHashMap的構造函數將 accessOrder設置爲 true,開啓 LRU順序;

    public LRUCache() {

        super(MAX_ENTRIES, 0.75f, true);

    }

 

    //最後覆蓋removeEldestEntry()方法實現,在節點多於 MAX_ENTRIES 就會將最近最少使用的數據移除。

    //因爲這個函數默認返回false,不重寫的話緩存爆了的時候無法刪除最近最久未使用的節點

    @Override

    protected boolean removeEldestEntry(java.util.Map.Entry eldest) {

        //在容量超過最大允許節點數的時候返回true,使得在afterNodeInsertion函數中能執行removeNode()

        return size() > MAX_ENTRIES;

    }

 

    public static void main(String[] args) {

        LRUCache cache = new LRUCache();

        cache.put(1, 1);

        cache.put(2, 2);

        cache.put(3, 3);

        cache.get(1);

        cache.put(4, 4);

        System.out.println(cache.keySet());

    }

}

1.手寫Rxjava實現網絡請求後數據展示到ui(這是安卓的)

算法題

輸入處理

1

2

3

4

5

6

7

8

#include//萬能頭文件

//數組中的輸入

vectornum;

int n;

while(cin>>n){

    num.push_back(n);

}

//鏈表中輸入

字符串

3.判斷字符串最少添加多少個字符,才能變成迴文串(當時沒寫出來,然後面試官問了下思路,然後說我思路是對的)

連續子串

算法題連續子數組的最大值

對於給定的數組,給出數組組合最大的數字(這個做出來了)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

class Solution {

public:

    int maxSubArray(vector& nums) {

        int res=nums[0],s=0;//設定初始狀態爲nums[0]

        for(auto x:nums){

            if(s<0)s=0;

            s+=x;

            res=max(res,s);

        }

        return res;

    }

};

class Solution {

public:

    int maxSubArray(vector& nums) {

        int res=nums[0];//設定初始狀態爲nums[0]

        for(int i=1;i<nums.size();i++){

            nums[i]+=max(nums[i-1],0);//狀態轉移方程爲dp[i]=max(dp[i-1],0)

            res=max(res,nums[i]);

        }

        return res;

    }

};

4.編程題(找字符串裏連續相同的最長串長度)

求一個字符串中最長的連續出現的字符,輸出該字符及其出現次數。字符串中無空白字符(空格、回車和tab),如果這樣的字符不止一個,則輸出出現最早的字符。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

#include

using namespace std;

char ch[256];

int main(){

    cin>>ch;

    int len=strlen(ch);

    char maxchar;

    int num=1,maxn=0;

    for(int i=0;i<len;i++){

        if(ch[i]==ch[i+1])num++;

        else{

            if(num>maxn){

                maxn=num;

                maxchar=ch[i];

            }

            num=1;

        }

    }

    cout<<maxchar<<" "<<maxn;

}

4.口述一道算法題,A字符串裏是否存在一個連續子串B 3.30

lcc03

 

滑動窗口實現:無重複字符的最長字串

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include

using namespace std;

int function1(string s){

        int left=0,res=0,n=s.size();

        unordered_map m;

        for(int i=0;i<n;i++){

            left=max(left,m[s[i]]);

            m[s[i]]=i+1;

            res=max(res,i-left+1);

        }

        return res;

    }

int main(){

    string n;

    cin>>n;

    cout<<function1(n);

}

假設有一個非常大的文件,全英文的,統計一下所有單詞出現的頻率,我回答的是mapreduce來查頻率,他說單機情況下,用map,有改進嗎?沒答出來--考慮字典樹、前綴樹的數據結構,會節省很多的內存空間

快排

2.手撕快排

1.編程題,快速排序(當時腦子不知道在想啥,沒做出來,很尷尬,不過面試官一直引導我,後來寫出來了還是有點問題,面試官一時也沒發現哪裏錯了,就直接跳過了)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

public class QuickSort {

    private  void quickSortC(int[] a, int l, int r) {

        if (l >= r) {

            return;

        }

        int p = partition(a, l, r);

        quickSortC(a, l, p - 1);

        quickSortC(a, p + 1, r);

    }

    //空間浪費比較多的分區函數可以將小於分界點存一段,大於分界點存一段,再合併

    public  int partition(int[] a, int l, int r) {

        int pivot = a[r];

        int i = l;

        for (int j = l; j < r; j++) {

            if (a[j] < pivot) {

                swap(a, i, j);

                i = i + 1;

            }

        }

        swap(a, i, r);

        return i;

    }

    public static void swap(int[] a,int l,int r){

        int temp=a[l];

        a[l]=a[r];

        a[r]=temp;

    }

    public static void main(String[] args) {

        int a[]={9,8,6,1,2,5,3,7,10,4};

        QuickSort quickSort=new QuickSort();

        for(int a1:a){

            System.out.print(a1+" ");

        }

        System.out.println();

        quickSort.quickSortC(a,0,9);

        for(int a1:a){

            System.out.print(a1+" ");

        }

    }

}

位運算

lc136 其餘每個元素出現2次

算法題1:出現奇數次的數字:給定一個非空整數數組,取值範圍[0,100],除了某個元素出現1次以外,其餘每個元素均出現次數爲2次。找出那個出現次數爲1次的元素。

1

2

3

4

5

6

7

8

//136 https://leetcode.wang/leetcode-136-Single-Number.html

public int singleNumber(int[] nums) {

    int ans = 0;

    for (int i = 0; i < nums.length; i++) {

        ans ^= nums[i];

    }

    return ans;

}

lc137 其餘每個元素出現三次

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

//https://leetcode.wang/leetcode-137-Single-NumberII.html?q=

public int singleNumber(int[] nums) {

    int ans = 0;

    //考慮每一位

    for (int i = 0; i < 32; i++) {

        int count = 0;//別忘了寫這個

        //考慮每一個數

        for (int j = 0; j < nums.length; j++) {

            //當前位是否是 1,無符號右移(右移不論正負都是高位補0)

            if ((nums[j] >>> i & 1) == 1) {

                count++;

            }

        }

        //1 的個數是否是 3 的倍數

        if (count % 3 != 0) {

            ans = ans | (1 << i);

        }

    }

    return ans;

}

2:):一個全英文題,意思是給定整數N 求1~N中 出現1的次數

lc189 旋轉數組

k次將最後1個元素移到最前

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

//https://leetcode-cn.com/problems/rotate-array/

class Solution {

    public void rotate(int[] nums, int k) {

        int previous,temp;

        int len =nums.length;

        for(int i=0;i<k;i++){

            previous=nums[len-1];

            for(int j=0;j<len;j++){

                temp=nums[j];

                nums[j]=previous;

                previous=temp;

            }

        }

    }

}

93微軟100道:

給定一個數組 求某個位置上的元素 滿足左邊的全小於它,右邊的全大於它

1

2

3

4

5

/*https://blog.csdn.net/xijiaoda_liuhao/article/details/8168875?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase*/

//https://blog.csdn.net/weixin_37553155/article/details/78806038?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2

//https://blog.csdn.net/robbyo/article/details/8575339?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-5

//https://blog.csdn.net/u012605629/article/details/40482851?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-1

//https://blog.csdn.net/u012605629/article/details/40482851?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase

14.算法題:調整數組順序讓奇數位於偶數前面,只能在原數組上操作

9.將數組的奇數放在左邊偶數放在右邊。然後修改一下判斷奇數偶數的方法(改成了位運算,然後又問了&和==的優先級)

lc21 調整數組順序使奇數位於偶數前面

解法1 快慢指針

1

2

3

4

5

6

7

8

9

10

11

12

13

14

class Solution {

public:

    vector exchange(vector& nums) {

        int fast=0,slow=0;

        while(fast<nums.size()){

            if(nums[fast]&1){

                swap(nums[slow],nums[fast]);

                slow++;

            }

            fast++;

        }

        return nums;

    }

};

解法2 左右雙指針法

1 左右指針分別指向隊首和對尾。
2 如果當前對首是偶數,隊尾是奇數,則交換左右指針的數據。
3 接着查找下一個對首不是偶數和隊尾不是奇數的左右索引位置。
4 需要注意數組越界。

遞歸

跳臺階算法,劍指的原題.只不過不用遞歸,用的是一個棧加循環實現。

lc10 跳臺階

16.算法題:青蛙變態跳臺階,我寫了遞歸,面試官就說可以了,非遞歸沒讓寫

小青蛙跳臺階,一次可以跳1,2,3....n階臺階,對於第N階臺階有多少種跳法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

//https://www.nowcoder.com/questionTerminal/22243d016f6b47f2a6928b4313c85387

int jumpFloor(int n){

    int result=0;

    if(n==1||n==0){

        result=1;

    }else{

        result=2*jumFloor(n-1);

    }

    return result;

}

//leetcode10 https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof/

//青蛙跳臺階問題

//斐波那契類型,可以跳一格或兩格

int jumpFloor2(int n){

    int dp[n+2];

    if(n<2){

        dp[n]=1;

    }

    dp[0]=1;dp[1]=1;

    for(int i=2;i<=n;i++){

        dp[i]=dp[i-1]+dp[i-2];

    }

    return dp[n];

}

鏈表

算法題3:求長度爲n的數組, 取值範圍爲[0~100], 求第k 小的數

lc22一個鏈表的倒數第k個節點

1.找到一個鏈表的倒數第k個節點5.5日

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//leetcode22 鏈表中倒數第k個節點

//https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/

class Solution {

public:

    ListNode* getKthFromEnd(ListNode* head, int k) {

        auto first=head;

        auto second=head;

        for(int i=0;i<k;i++){

            first=first->next;

        }

        while(first!=NULL){

            first=first->next;

            second=second->next;

        }

        return second;

    }

};

lc206 lc92 單鏈表的逆序

15.算法題:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

struct ListNode {

     int val;

     ListNode *next;

     ListNode(int x) : val(x), next(NULL) {}

};

//leetcode206 https://leetcode-cn.com/problems/reverse-linked-list/

class Solution {

public:

    ListNode* reverseList(ListNode* head) {

        if(head==NULL)return NULL;

        auto a=head,b=head->next;

        while(b){

            auto c=b->next;

            b->next=a;

            a=b;

            b=c;

        }

        head->next=NULL;

        return a;

    }

};

//leetcode92 https://leetcode-cn.com/problems/reverse-linked-list-ii/

class Solution {

public:

    ListNode* reverseBetween(ListNode* head, int m, int n) {

        if(m==n)return head;

        auto dummy=new ListNode(-1);

        dummy->next=head;

        auto a=dummy,d=dummy;

        for(int i=0;inext;

        for(int i=0;inext;

        auto b=a->next,c=d->next;

        for(auto p=b,q=b->next;q!=c;){

            auto o=q->next;

            q->next=p;

            p=q;q=o;

        }

        a->next=d;

        b->next=c;

        return dummy->next;

    }

};

6.算法題2:鏈表1->2->3->4->5->6轉換成 2->1->4->3->6->5。

一個鏈表有沒有環怎麼判斷5.5

合併單鏈表

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

#include

#include

//using  namespace std;

typedef struct Node{

    int data;

    struct Node *next;

}Node;

Node *CreateH();

Node *CreateH1();

void show(Node *Head);

int main(){

    Node *Head,*Head1;

    Head=CreateH();

    show(Head);

    Head1=CreateH1();

    show(Head1);

    return 0;

}

 

Node *CreateH(){

    int x;

    Node *Head;

    Head = (Node *)malloc(sizeof(Node));

    Head->next=NULL;

    Node *r;

    r=Head;

    while(scanf("%d",&x)!=EOF){

        Node *p = (Node *)malloc(sizeof(Node));

        p->data=x;

        r->next=p;

        r=p;

    }

    r->next=NULL;

    return Head;

}

Node *CreateH1(){

    int x;

    Node *Head;

    Node *p;

    Head = (Node *)malloc(sizeof(Node));

    Head->next=NULL;

    while(scanf("%d",&x)!=EOF){

        p = (Node *)malloc(sizeof(Node));

        p->data=x;

        p->next=Head->next;

        Head->next=p;

    }

    return Head;

}

void show(Node *Head){

    Node *p;

    p=Head->next;

    while(p!=NULL){

        printf("%d \n",p->data);

        p=p->next;

    }

}

二分

lc162 在一個先增大後減小的數組中找到最大值

1

2

3

4

5

6

7

8

9

10

11

12

13

//leetcode162尋找峯值  https://leetcode-cn.com/problems/find-peak-element/

class Solution {

public:

    int findPeakElement(vector& nums) {

        int l=0,r=nums.size()-1;

        while(l<r){

            int mid=l+r>>1;

            if(nums[mid]>nums[mid+1])r=mid;

            else l=mid+1;

        }

        return l;

    }

};

lc33 旋轉數組中找到target

5.算法題1:旋轉數組中找到target,

算法題:對一個不遞減數組進行一次旋轉操作的結果,查找數組中的數

就是對類似於[4,5,6,1,2,3]這樣的數組,進行查找(二分)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

//https://www.nowcoder.com/questionTerminal/051934d3b2384b0fbfba3c544a0f75b1   牛客網題目

//leetcode33 https://leetcode-cn.com/problems/search-in-rotated-sorted-array/

#include

using namespace std;

int main(){

    int len,target;

    cin>>len>>target;

    vectornum;

    int n;

    while(cin>>n){

        num.push_back(n);

    }

    int l=0,r=len-1;

    while(l<r){

        int mid=(l+r)>>1;

        if(num[mid]<=num.back())r=mid;

        else l=mid+1;

    }

    if(target<=num.back())r=len-1;

    else l=0,r--;

    while(l<r){

        int mid=(l+r)>>1;

        if(num[mid]>=target)r=mid;

        else l=mid+1;

    }

    if(num[l]==target)cout<<"Yes";

    else cout<<"No";

}

7.算法題1:將數組中的數字,拼接起來,求能夠組成的最大的數。(思維僵化。。。想到了按位比較,後來我查了下,只需要寫個字符串排序,傳給sort方法即可。

快手的括號匹配

8.算法題2: 統計字符串中,匹配的括號對數,失配的左括號,右括號數目。用棧就行

3.手撕一道算法題,判斷括號的對數3.30

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

String charAt length//記得加()      HashSet contains  add

//1.left記錄左括號數目,res記錄匹配括號對數,right記錄右括號數目

//2.遇到左括號left++

//3.遇到右括號:當left不爲0,表示匹配,res++,left--;當left爲0表示不匹配,right++

public static void main(String[] args){

    Scanner scan=new Scanner(System.in);

    String s=scan.next();

    HashSet cals=new HashSet();//要記得new HashSet後的()

    int left=0,right=0,res=0;

    cals.add('(');

    cals.add(')');

    for(int i=0;i<s.length();i++){

        if(cals.contains(s.charAt(i))){

            if(s.charAt(i)=='('){

                left++;

            }else if(s.charAt(i)==")"){

                if(left=0)right++;

                else if(left>0){

                    res++;

                    left--;

                }

            }

        }

    }

   System.out.println(res+" "+left+" "+right);

}

lc22括號匹配

1

2

//https://blog.csdn.net/zrh_CSDN/article/details/80694202

//https://www.nowcoder.com/discuss/38862?type=post&order=create&pos=&page=1&channel=&source_id=1_post

1):兩個棧實現隊列

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

import java.util.Stack;

//用兩個棧實現隊列

public class Stack2 {

    private Stack s1=new Stack();

    private Stacks2=new Stack();

 

    public Integer push(int p){

        return s1.push(p);

    }

 

    public Integer pop(){

        if(s1.isEmpty()&&s2.isEmpty())return 0;

        if(!s2.isEmpty()){

            return s2.pop();

        }

        int size=s1.size();

        for(int i=0;i<size;i++){

            s2.push(s1.pop());

        }

        return s2.pop();

    }

    public static void main(String[] args) {

        Stack2 stack2=new Stack2();

        for(int i=0;i<5;i++){

            System.out.println(stack2.push(i));

        }

        for(int i=0;i<5;i++){

            System.out.println(stack2.pop());

        }

    }

}

1.用數組寫一個stack,看重邏輯和代碼質量

(有個坑,自己寫了一個類,運行不了,把代碼放到牛客網的Main裏就好了)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

public class ArrayStack {

    private int n;//棧長

    private int count;//數組長

    private String[] item;

 

    public ArrayStack(int capacity){

        item=new String[capacity];

        this.n=capacity;

        this.count=0;

    }

 

    public boolean push(String item1){

        if(count==n)return false;

        item[count]=item1;

        count++;

        return true;

    }

 

    public String pop(){

        if(count==0)return null;

        String res=item[count-1];

        count--;

        return res;

    }

    public static void main(String[] args) {

        ArrayStack stack=new ArrayStack(5);

        String[] s={"a","b","c","d","e"};

        for(int i=0;i<5;i++){

            System.out.println(stack.push(s[i]));

        }

        for(int i=0;i<5;i++){

            System.out.println(stack.pop());

        }

    }

}

1):求二叉樹的深度

5.二叉排序樹轉換成有序的雙向鏈表。我寫了一個非遞歸的中序遍歷,在打印二叉樹節點值的位置改成構建雙向鏈表節點,並連接指針5.9

算法題:一棵樹的右視圖,小哥哥說在框裏寫,,,我還沒問能不能用ide呢,,, 5.5

隊列

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

// 用數組實現的隊列

public class ArrayQueue {

  // 數組:items,數組大小:n

  private String[] items;

  private int n = 0;

  // head表示隊頭下標,tail表示隊尾下標

  private int head = 0;

  private int tail = 0;

 

  // 申請一個大小爲capacity的數組

  public ArrayQueue(int capacity) {

    items = new String[capacity];

    n = capacity;

  }

 

  // 入隊

  public boolean enqueue(String item) {

    // 如果tail == n 表示隊列已經滿了

    if (tail == n) return false;

    items[tail] = item;

    ++tail;

    return true;

  }

  // 出隊

  public String dequeue() {

    // 如果head == tail 表示隊列爲空

    if (head == tail) return null;

    // 爲了讓其他語言的同學看的更加明確,把--操作放到單獨一行來寫了

    String ret = items[head];

    ++head;

    return ret;

  }

  //主方法

  public static void main(String[] args) {

        ArrayQueue queue=new ArrayQueue(5);

        String[] s={"a","b","c","d","e"};

        for(int i=0;i<5;i++){

            System.out.println(queue.enqueue(s[i]));

        }

        for(int i=0;i<5;i++){

            System.out.println(queue.dequeue());

        }

    }

}

6:算法 4.26

算法題:表達式求值,“10+83-32-5”(雙端隊列)4.12日

寫個題:判斷數組中是否存在兩個不同的索引 i 和 j,使得 nums [i] = nums [j],並且 i 和 j 的差的絕對值最大爲 k。4.11

那就寫個題吧:計算x,y兩個數的和,需要花費(c∗x+c∗y)(cx+cy)(c∗x+c∗y)秒,怎麼合理安排計算的順序,可以使得花費的時間最短。 4.11

希望大家可以拿到心儀公司的offer,偷偷告訴你si xin 有驚喜喲

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