成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

從一道前端面試題談起

darkbaby123 / 1824人閱讀

摘要:但是題目非要弄成鏈表的形式,說(shuō)實(shí)在的,我真沒(méi)有見(jiàn)過(guò)前端什么地方還需要用鏈表這種結(jié)構(gòu)的除了面試的時(shí)候,所以說(shuō)這種題目對(duì)于實(shí)際工作是沒(méi)什么用處的,但是腦筋急轉(zhuǎn)彎的智商題既然這樣出了,我們就來(lái)看看怎么解決它吧。

今天在知乎上看到一個(gè)回答《為什么前端工程師那么難招?》,作者提到說(shuō)有很多前端工程師甚至連單鏈表翻轉(zhuǎn)都寫(xiě)不出來(lái)。說(shuō)實(shí)話(huà),來(lái)面試的孩子們本來(lái)就緊張,你要冷不丁問(wèn)一句單鏈表翻轉(zhuǎn)怎么寫(xiě),估計(jì)很多人都會(huì)蒙掉。

于是我在leetcode 上找了一下這道題,看看我能不能寫(xiě)得出來(lái)。

題目的要求很簡(jiǎn)單:

反轉(zhuǎn)一個(gè)單鏈表。

示例:
輸入: 1->2->3->4->5->NULL
輸出: 5->4->3->2->1->NULL

最后的解決就是這樣的一行代碼:

const reverseList = (head, q = null) => head !== null ? reverseList(head.next, { val: head.val, next: q }) : q;

答案并不重要,有意思的是整個(gè)的解題思路。

前端工程師需要了解算法嗎?

在解題之前,我們先來(lái)聊聊算法。嚴(yán)格來(lái)說(shuō),單鏈表翻轉(zhuǎn)這種問(wèn)題只是對(duì)于鏈表這種數(shù)據(jù)結(jié)構(gòu)的一種操控而已,根本談不上是什么算法。當(dāng)然,寬泛地來(lái)說(shuō),只要涉及到循環(huán)和遞歸的都把它歸入到算法也可以。在這里,我們采用一種寬容的定義。

算法需要背嗎?我覺(jué)得算法是不需要背的,你也不可能背的下來(lái),光leetcode就有上千道題目,并且還在增加,怎么可能背的下來(lái)?所以對(duì)于現(xiàn)階段的程序員來(lái)說(shuō),算法分為兩類(lèi),一類(lèi)是你自己能推算出來(lái)的,這種不用背,一類(lèi)是你推算不出來(lái)的,比如KMP算法,這種也不用背,需要的時(shí)候直接Google就可以了。特別是對(duì)于前端以及80%的后端程序員來(lái)說(shuō),你需要什么算法,就直接使用現(xiàn)在的庫(kù)就行了,數(shù)組排序直接array.sort就可以,誰(shuí)沒(méi)事還非要去寫(xiě)一個(gè)快速排序?

那為什么面試前端的時(shí)候還必須要考算法?這個(gè)道理基本上類(lèi)似于通過(guò)考腦筋急轉(zhuǎn)彎來(lái)測(cè)試智商一樣,實(shí)際工作中是完全用不上的,就像高考的時(shí)候考一大堆物理、化學(xué)、生物,恨不得你上知天文,下知地理,上下五千年,精通多國(guó)語(yǔ)言,但其實(shí)你參加工作以后發(fā)現(xiàn)根本用不上一樣,這其實(shí)就是一個(gè)智商篩子,過(guò)濾一下而已。

所以,別管工作中用不用得到,如果你想通過(guò)這道篩子的話(huà),算法的東西多少還是應(yīng)該學(xué)習(xí)一些的。

單鏈表的數(shù)據(jù)結(jié)構(gòu)

說(shuō)實(shí)話(huà),我剛做這道題的時(shí)候,我也有點(diǎn)蒙。雖然上學(xué)的時(shí)候?qū)W過(guò)數(shù)據(jù)結(jié)構(gòu),鏈表、堆棧、二叉樹(shù)這些東西,但這么多年實(shí)際工作中用的很少,幾乎都快忘光了,不過(guò)沒(méi)關(guān)系,我們就把它當(dāng)成是腦筋急轉(zhuǎn)彎來(lái)做一下好了。

我們先來(lái)看一下它的數(shù)據(jù)結(jié)構(gòu)是什么樣的:

var reverseList = function(head) {
    console.log(head);
};
ListNode {  
  val: 1, next: ListNode {
    val: 2, next: ListNode {
      val: 3, next: [ListNode] } } }

一個(gè)對(duì)象里包含了兩個(gè)屬性,一個(gè)屬性是val,一個(gè)屬性是next,這樣一層一層循環(huán)嵌套下去。

通常來(lái)講,在前端開(kāi)發(fā)當(dāng)中,我們最常用的是數(shù)組。如果是用數(shù)組的話(huà),就太簡(jiǎn)單了,js數(shù)組自帶reverse方法,直接array.reverse反轉(zhuǎn)就行了。但是題目非要弄成鏈表的形式,說(shuō)實(shí)在的,我真沒(méi)有見(jiàn)過(guò)前端什么地方還需要用鏈表這種結(jié)構(gòu)的(除了面試的時(shí)候),所以說(shuō)這種題目對(duì)于實(shí)際工作是沒(méi)什么用處的,但是腦筋急轉(zhuǎn)彎的智商題既然這樣出了,我們就來(lái)看看怎么解決它吧。

循環(huán)迭代

首先想到的,這肯定是一個(gè)while循環(huán),循環(huán)到最后,發(fā)現(xiàn)nextnull就結(jié)束,這個(gè)很容易想。但關(guān)鍵是怎么倒序呢?這個(gè)地方需要稍微動(dòng)一下腦子。我們觀察一下,倒序之后的結(jié)果,1變成了最后一個(gè),也就是說(shuō)1nextnull,而2next1。所以我們一上來(lái)先構(gòu)建一個(gè)nextnull1結(jié)點(diǎn),然后讀到2的時(shí)候,把2next指向1,這樣不就倒過(guò)了嗎?所以一開(kāi)始的程序?qū)懗鰜?lái)是這樣的:

var reverseList = function(head) {
  let p = head;
  let q = { val: p.val, next: null };
  while (p.next !== null) {
    p = p.next;
    q = { val: p.val, next: q };
  }
  return q;
};

先初始化了一個(gè)q,它的nextnull,所以它就是我們的尾結(jié)點(diǎn),然后再一個(gè)一個(gè)指向它,這樣整個(gè)鏈表就倒序翻轉(zhuǎn)過(guò)來(lái)了。

第一個(gè)測(cè)試用例沒(méi)有問(wèn)題,于是就提交了,但是提交完了發(fā)現(xiàn)不對(duì),如果head本身是null的話(huà),會(huì)報(bào)錯(cuò),所以修改了一下:

var reverseList = function(head) {
  let p = head;
  if (p === null) {
    return null;
  }
  let q = { val: p.val, next: null };
  while (p.next !== null) {
    p = p.next;
    q = { val: p.val, next: q };
  }
  return q;
};

這回就過(guò)了。

遞歸

解決是解決了,但是這么長(zhǎng)的代碼,明顯不夠優(yōu)雅,我們嘗試用遞歸的方法對(duì)它進(jìn)一步優(yōu)化。

如果有全局變量的話(huà),遞歸本身并不復(fù)雜。但因?yàn)?b>leetcode里不允許用全局變量,所以我們只好構(gòu)造一個(gè)雙參數(shù)的函數(shù),把倒序之后的結(jié)果也作為一個(gè)參數(shù)傳進(jìn)去,這樣剛一開(kāi)始的時(shí)候q是一個(gè)null,隨著遞歸的層層深入,q逐漸包裹起來(lái),直到最后一層:

const reverseList = function(head) {
    let q = null;
    return r(head, q);
}
const r = function(p, q) {
    if (p === null) {
        return q;
    } else {
        return r(p.next, { val: p.val, next: q });
    }
}

這里我們終于理清了出題者的思路,用遞歸的方式我們可以把這個(gè)if判斷作為整個(gè)遞歸結(jié)束的必要條件。如果p不是null,那么我們就再做一次,把p的下一個(gè)結(jié)點(diǎn)放進(jìn)來(lái),比如說(shuō)1的下一個(gè)是2,那么我們這時(shí)候就從2開(kāi)始執(zhí)行,直到最后走到55的下一個(gè)結(jié)點(diǎn)是null,然后我們退回上一層,這樣一層層鉆下去,最后再一層層返回來(lái),就完成了整個(gè)翻轉(zhuǎn)的過(guò)程。

優(yōu)化代碼

遞歸成功之后,后面的事情就相對(duì)簡(jiǎn)單了。

怎么能把代碼弄簡(jiǎn)短一些呢?我們注意到這里這個(gè)if語(yǔ)句里面都是直接return,那我們干脆直接做個(gè)三元操作符就好了:

const reverseList = function(head) {
    let q = null;
    return r(head, q);
}
const r = function(p, q) {
    return p === null ? q : r(p.next, { val: p.val, next: q });
}

更進(jìn)一步,我們用箭頭函數(shù)來(lái)表示:

const reverseList = (head) => {
    let q = null;
    return r(head, q);
}
const r = (p, q) => {
    return p === null ? q : r(p.next, { val: p.val, next: q });
}

箭頭函數(shù)還有一個(gè)特色是如果你只有一條return語(yǔ)句的話(huà),連外面的花括號(hào)和return關(guān)鍵字都可以省掉,于是就變成了這樣:

const reverseList = (head) => {
    let q = null;
    return r(head, q);
}
const r = (p, q) => (p === null ? q : r(p.next, { val: p.val, next: q }));

這樣是不是看著就短多了呢?但是還可以更進(jìn)一步簡(jiǎn)化,我們把上面的函數(shù)再精簡(jiǎn),這時(shí)候你仔細(xì)觀察的話(huà),會(huì)發(fā)現(xiàn)第一個(gè)函數(shù)和第二個(gè)函數(shù)很類(lèi)似,都是在調(diào)用第二個(gè)函數(shù),那么我們能不能精簡(jiǎn)一下把它們合并呢?我們先把第一個(gè)函數(shù)變換為和第二函數(shù)的參數(shù)數(shù)目一致的形式:

const reverseList = (head, q) => r(head, q);
const r = (p, q) => (p === null ? q : r(p.next, { val: p.val, next: q }));

但這時(shí)候出現(xiàn)了一個(gè)問(wèn)題,如果q沒(méi)有初始值的話(huà),它是undefined,不是null,所以我們還需要給q一個(gè)初始值:

const reverseList = (head, q = null) => r(head, q);
const r = (p, q) => (p === null ? q : r(p.next, { val: p.val, next: q }));

這時(shí)候我們的兩個(gè)函數(shù)長(zhǎng)的基本一致了,我們來(lái)把它們合并一下:

const reverseList = (head, q = null) => (head === null ? q : reverseList(head.next, { val: head.val, next: q }));

看,這樣你就得到了一個(gè)一行代碼的遞歸函數(shù)可以解決單鏈表翻轉(zhuǎn)的問(wèn)題。

實(shí)話(huà)說(shuō),即使是像我這樣有多年經(jīng)驗(yàn)的程序員,要解決這樣的一個(gè)問(wèn)題,都需要這么長(zhǎng)的時(shí)間這么多步驟才能優(yōu)化完美,更何況說(shuō)一個(gè)大學(xué)剛畢業(yè)的孩子,很難當(dāng)場(chǎng)就一次性回答正確,能把思路說(shuō)出來(lái)就很不容易了,但你可以從這個(gè)過(guò)程中看到程序代碼是如何逐漸演進(jìn)的。背誦算法沒(méi)有意義,我覺(jué)得我們更多需要的是這一個(gè)思考的過(guò)程,畢竟編程是一個(gè)腦筋急轉(zhuǎn)彎的過(guò)程,不是唐詩(shī)三百首。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104314.html

相關(guān)文章

  • 前端面試 - 收藏集 - 掘金

    摘要:一基礎(chǔ)接口的意義百度規(guī)范擴(kuò)展回調(diào)抽象類(lèi)的意義我的前端面試經(jīng)歷百度前端掘金博主就讀于電子科技大學(xué),大三狗一枚面試是個(gè)漫長(zhǎng)的過(guò)程,從海投到收獲電話(huà)面試,一面二面三面,一個(gè)步驟出錯(cuò)那么后面就宣告終結(jié)。 一道常被人輕視的前端 JS 面試題 - 前端 - 掘金 目錄前言第一問(wèn)第二問(wèn)變量聲明提升函數(shù)表達(dá)式第三問(wèn)第四問(wèn)第五問(wèn)第六問(wèn)構(gòu)造函數(shù)的返回值第七問(wèn)最后前言 年前剛剛離職了,分享下我曾經(jīng)出過(guò)的一道...

    lpjustdoit 評(píng)論0 收藏0
  • 一道面試,到“我可能看了假源碼”

    摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對(duì)象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。同時(shí),將第一個(gè)參數(shù)以外的其他參數(shù),作為提供給原函數(shù)的預(yù)設(shè)參數(shù),這也是基本的顆粒化基礎(chǔ)。 今天想談?wù)勔坏狼岸嗣嬖囶},我做面試官的時(shí)候經(jīng)常喜歡用它來(lái)考察面試者的基礎(chǔ)是否扎實(shí),以及邏輯、思維能力和臨場(chǎng)表現(xiàn),題目是:模擬實(shí)現(xiàn)ES5中原生bind函數(shù)。也許這道題目已經(jīng)不再新鮮,部分讀者也會(huì)有思路來(lái)解答。社區(qū)上關(guān)于原生bind的研...

    Carson 評(píng)論0 收藏0
  • 一道面試,到“我可能看了假源碼”

    摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對(duì)象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。同時(shí),將第一個(gè)參數(shù)以外的其他參數(shù),作為提供給原函數(shù)的預(yù)設(shè)參數(shù),這也是基本的顆粒化基礎(chǔ)。 今天想談?wù)勔坏狼岸嗣嬖囶},我做面試官的時(shí)候經(jīng)常喜歡用它來(lái)考察面試者的基礎(chǔ)是否扎實(shí),以及邏輯、思維能力和臨場(chǎng)表現(xiàn),題目是:模擬實(shí)現(xiàn)ES5中原生bind函數(shù)。也許這道題目已經(jīng)不再新鮮,部分讀者也會(huì)有思路來(lái)解答。社區(qū)上關(guān)于原生bind的研...

    rockswang 評(píng)論0 收藏0
  • 一道面試,到“我可能看了假源碼”

    摘要:返回的綁定函數(shù)也能使用操作符創(chuàng)建對(duì)象這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。同時(shí),將第一個(gè)參數(shù)以外的其他參數(shù),作為提供給原函數(shù)的預(yù)設(shè)參數(shù),這也是基本的顆粒化基礎(chǔ)。 今天想談?wù)勔坏狼岸嗣嬖囶},我做面試官的時(shí)候經(jīng)常喜歡用它來(lái)考察面試者的基礎(chǔ)是否扎實(shí),以及邏輯、思維能力和臨場(chǎng)表現(xiàn),題目是:模擬實(shí)現(xiàn)ES5中原生bind函數(shù)。也許這道題目已經(jīng)不再新鮮,部分讀者也會(huì)有思路來(lái)解答。社區(qū)上關(guān)于原生bind的研...

    jlanglang 評(píng)論0 收藏0
  • 一道前端面試引發(fā)的思考

    摘要:直接開(kāi)始題目是厲害了說(shuō)句實(shí)話(huà)開(kāi)發(fā)中誰(shuí)寫(xiě)成這樣保證會(huì)被打死。不過(guò)面試就是面試,有面試官的考量點(diǎn)。官方是這么說(shuō)的。結(jié)果完美,不過(guò)小姐姐的意思是數(shù)組的方法會(huì)自動(dòng)觸發(fā)數(shù)組的。 直接開(kāi)始題目是 if(a==1 && a==2 && a==3){ alert(厲害了) } 說(shuō)句實(shí)話(huà)開(kāi)發(fā)中誰(shuí)寫(xiě)成這樣保證會(huì)被打死。 不過(guò)面試就是面試,有面試官的考量點(diǎn)。 我理解的點(diǎn)有兩個(gè) 1、隱式類(lèi)型轉(zhuǎn)換 先說(shuō)...

    gaomysion 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<