快手面經篇一,據說看了面試通過率提升50%

寫給正在找工作的你

都說金三銀四,對於找工作的人來說,因爲每年的三月或四月是不少互聯網公司的年終季,不少人都是拿到年終獎後不滿意,或者感覺職業發展受限,之後跑路。這樣不少部門因爲人員流動,就會有hc空缺出來。
這裏要說的是每年3、4月份確實是hc最多的季節,但同時是跳槽旺季,競爭大,你要想找到好的坑位,那就需要絕對的實力纔行。
相對來說,其實年底是個好時候,俗話說,鐵打的營盤流水的兵,互聯網的陣地上不少崗位是常年招人,常年缺人,當然hc並不富裕,但是年底的時候,看機會的人也少。畢竟不少人還是很在意“年終獎”的嘛。所以說,年底跳槽你可能會損失一部分年終獎,但換工作的競爭性相對來說也會少很多,競爭的人少了嘛,說不定你就可以憑“運氣的實力”脫穎而出呢?

快手面試

算法

面試官很親切,說Excel表用過吧,Excel表中的編號一般是這樣的,A…Z AA…AZ BA…BZ,分別對應數字0…25 26…51 52…77,類比做數字映射,給出一個字符串,求映射的結果。

分析 這個題目其實很基礎,可以理解爲是以26爲基準的進制轉換,一個for循環,除了末尾的字符直接加到結果上之外,其他的字符位-‘A’+1的結果乘以26*(該字符位置與末尾的差值)。做這種題目一定要先思考,自己手動實現一下。
如果想看具體代碼答案,可以掃碼關注【程序員之道】,後臺回覆“快手列轉換”。
在這裏插入圖片描述

第二個算法,就稍微有一點偏了,如何實現redis的分佈式鎖。

如果沒有接觸過高併發,或者沒有使用過redis作爲分佈式鎖,那這這個算法肯定是寫不出來的,而且像這種算法,一般來說可能也就是讓講講思路。具體實現確實有點難。
關於分佈式鎖,其實是有幾個坑的:

  1. 加鎖,必須設置過期時間(防止釋放鎖失敗,有過期時間,鎖可以自動釋放)。且加鎖和設置過期時間必須爲原子操作。否則,如果加鎖成功,但設置過期時間時客戶端崩潰,那設置過期時間就失敗了。
  2. 加鎖和釋放鎖必須是同一個客戶端。用唯一id來標誌。
  3. 釋放鎖時,判斷鎖是否屬於自己及釋放鎖必須是原子操作。

思考了這些,你能寫成正確的加鎖,解鎖方式嗎?具體的坑及正確的加解鎖方式,關注【程序員之道】,後臺回覆“redis分佈式鎖”。

基礎

  • mysql索引怎麼建立,查詢語句select * from T where a=“a” and b=“b” and c=“c”,與select * from T where a=“a” and c=“c” and b="b"執行有什麼區別嗎?建議索引遵循什麼原則?
    要點:
    (1)儘量減少like,但不是絕對不可用,”xxxx%” 是可以用到索引的
    (2)表的主鍵、外鍵必須有索引
    (3   誰的區分度更高(同值的最少),誰建索引,區分度的公式是count(distinct(字段))/count(*)
    (4)單表數據太少,不適合建索引
    (5)where,order by ,group by 等過濾時,後面的字段最好加上索引
    (6)如果既有單字段索引,又有這幾個字段上的聯合索引,一般可以刪除聯合索引;
    (7)聯合索引的建立需要進行仔細分析;儘量考慮用單字段索引代替:
    (8)聯合索引: mysql 從左到右的使用索引中的字段,一個查詢可以只使用索引中的一部份,但只能是最左側部分。例如索引是key index(a,b,c). 可以支持 a|a,b|a,b,c 3種組合進行查找,但不支持 b,c 進行查找.當最左側字段是常量引用時,索引就十分有效。
    (9)前綴索引: 有時候需要索引很長的字符列,這會讓索引變得大且慢。通常可以索引開始的部分字符,這樣可以大大節約索引空間,從而提高索引效率。其缺點是不能用於ORDER BY和GROUP BY操作,也不能用於覆蓋索引 Covering index(即當索引本身包含查詢所需全部數據時,不再訪問數據文件本身)。
   (10)NULL會導致索引形同虛設

=和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式。

  • redis裏有哪些數據結構,都用過什麼?redis裏Sorted Set怎麼用,需要傳什麼參數?
    要點:
    redis的數據結構:String,Hash、List、Set、Sorted Set,用過哪些就說哪些就行了,沒用過的,估計你根據名詞也能大概猜出是什麼。
    面試官問Sorted Set大概是你聽到你說了Sorted Set,所以問一下你命令,看你是不是真的知道啊,不知道的話,這下沒法矇混過關了吧。有序集合,設置每個key的時候需要傳入一個score參數。具體命令zadd key score value。還有一些其他的命令google學習一下吧!

  • java volatile幹什麼用的。public int incrment() { count++},兩個線程同時訪問是否有問題,count如果用volatile修飾呢?
    要點:
    volatile主要是保證多線程訪問時的可見性。我們知道計算機爲了提高訪問內存的速度,引入了工作內存和主內存的概率,多線程訪問數據時,訪問的是工作內存的數據,各個線程之間的工作內存是分別隔離的。這就可能導致同一個變量,由於工作內存的存在,在不同線程“看到的值”是不一樣的。但volatile關鍵字,強制了各線程讀取變量時必須從主內存讀取,同時對變量的修改也直接刷新到主內存,這樣就保證了同一變量修改的同時可以立刻被其他線程“看到”。這裏面使用了“內存屏障”的技術。
    對於count++,操作系統執行時,並不是一個原子操作,分爲三步:1)將count變量load到內存。2)執行count+1。3)將結果存入內存。非原子性操作,任何一個步驟執行的時候,都可能被其他線程打斷,所以多線程執行時會有問題。
    使用volatile修飾也是不可以的,因爲始終不是原子操作,也只是保證可見性而已,原子性的問題無法解決。

  • jvm裏內存分配什麼樣的,分別用來幹什麼?
    要點:
    JVM內存分配幾乎是每個java開發人員的面試必考點,單純這部分的內容都夠寫幾個篇章的了。這裏只是簡單的介紹一下。
    JVM內存分爲年輕代和老年代,其中年輕代又分爲S0、S1、Eden區,JVM採用分代垃圾回收算法,因爲這樣才能更充分的利用年輕代和老年代的對象特點,最大化的提高垃圾回收效率。

  • 類對象定義後分配在年輕代。

  • 大對象或大數組直接分配在老年代。

    常見的垃圾回收算法有複製算法、標記清除、標記整理,然後又引出不同的垃圾回收器,垃圾回收器的迭代是不斷髮現問題並優化的過程,新生代收集器使用的收集器:Serial、PraNew、Parallel Scavenge;老年代收集器使用的收集器:Serial Old、Parallel Old、CMS。然後結合自己的理解再說一下!

  • jvm的棧是做什麼,爲什麼有堆又有棧,只使用堆可以嗎?
    要點:
    JVM的棧是線程私有的,一些基本變量都是存儲在棧中的,Java棧中存放的是一個個的棧幀,每個棧幀對應一個被調用的方法,在棧幀中包括局部變量表(Local Variables)、操作數棧(Operand Stack)、指向當前方法所屬的類的運行時常量池(運行時常量池的概念在方法區部分會談到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些額外的附加信息。當線程執行一個方法時,就會隨之創建一個對應的棧幀,並將建立的棧幀壓棧。當方法執行完畢之後,便會將棧幀出棧。
    爲什麼有了堆之後還要有棧?棧的存在可以說是爲了解決遞歸調用的問題。如果只有堆內存,那就不會有遞歸調用了。

  • 分佈式自增id怎麼實現,如果用redis實現,怎麼保證與數據庫的一致性?
    分佈式自增id一般使用MySQL的自增id、redis的incr函數,還有比較經典的雪花算法。
    MySQL自增id受數據庫訪問速度的限制,在分佈式使用時qps不大。
    使用redis產生自增id,就要防止redis崩潰的可能性,一般在MySQL或hbase中記錄當前最大的value值。或者如果你設計的是一個聊天室,那肯定是有持久化存儲當前聊天室的最大seqId,如果redis集羣出現崩潰,從持久化存儲的地方取出最大seqId然後自增即可。

  • ArrayList,LinkedList有什麼區別,分別什麼時候使用?
    ArrayList的底層實現是數組,數組的擴容是不斷通過複製來完成的,所以存儲的數據容量不斷髮生變化時,ArrayList的性能是比較差的。使用ArrayList時一般都是預知數據的最大容量。如果能直接使用數組,那使用數組當然是最好的了。
    LinkedList的底層實現是鏈表,發生數據擴容時,性能較好,但同容量情況下佔用的空間比ArrayList要大。對於數據頻繁擴容的情況,推薦使用LinkedList。

面試的內容還有很多,限於篇幅問題,在下一篇介紹。
程序員的小夥伴們,覺得自己孤單麼,那就加入公衆號[程序員之道],一起交流溝通,走出我們的程序員之道!
掃碼加入吧!

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