自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊獲取鏈表中倒數(shù)第K個(gè)節(jié)點(diǎn)

開發(fā) 前端
假設(shè)整個(gè)鏈表有n個(gè)節(jié)點(diǎn),那么倒數(shù)第K個(gè)節(jié)點(diǎn)就是從頭節(jié)點(diǎn)開始的第n-K+1個(gè)節(jié)點(diǎn)。如果我們能夠得到節(jié)點(diǎn)數(shù)n,那么只需要從頭節(jié)點(diǎn)開始往后走n-k+1步就可以了。

前言

給定一個(gè)單向鏈表的頭節(jié)點(diǎn),如何獲取該鏈表中倒數(shù)第K個(gè)節(jié)點(diǎn)(從1開始計(jì)數(shù))?本文將帶著大家一起解決這個(gè)問題,歡迎各位感興趣的開發(fā)者閱讀本文。

思路分析

我們通過一個(gè)例子來做進(jìn)一步的分析:

  • 準(zhǔn)備一個(gè)鏈表,它有6個(gè)節(jié)點(diǎn),從頭節(jié)點(diǎn)開始,其值依次為:1、3、5、9、15、21。
  • 獲取該鏈表的倒數(shù)第3個(gè)節(jié)點(diǎn)。

遍歷兩次鏈表

根據(jù)單向鏈表的定義,我們可知:想要獲取它的某個(gè)節(jié)點(diǎn),只能從頭節(jié)點(diǎn)開始順著其指針往后查找。假設(shè)整個(gè)鏈表有n個(gè)節(jié)點(diǎn),那么倒數(shù)第K個(gè)節(jié)點(diǎn)就是從頭節(jié)點(diǎn)開始的第n-K+1個(gè)節(jié)點(diǎn)。如果我們能夠得到節(jié)點(diǎn)數(shù)n,那么只需要從頭節(jié)點(diǎn)開始往后走n-k+1步就可以了。想要得到節(jié)點(diǎn)數(shù)n,就需要定義一個(gè)變量,從頭開始遍歷鏈表,每經(jīng)過一個(gè)節(jié)點(diǎn),這個(gè)變量就自增1。

也就是說,我們需要遍歷鏈表兩次,第一次計(jì)算出鏈表中節(jié)點(diǎn)的個(gè)數(shù),第二次就能獲取倒數(shù)第K個(gè)節(jié)點(diǎn),如下圖所示:

  • 第1次遍歷鏈表拿到了鏈表的長(zhǎng)度n=6。
  • 第2次遍歷鏈表獲取到了倒數(shù)第3個(gè)節(jié)點(diǎn)處(6-3+1)的值9。

圖片

遍歷一次鏈表

遍歷兩次鏈表來解決這個(gè)問題并不是最優(yōu)解,我們換個(gè)思路來考慮下這個(gè)問題:準(zhǔn)備兩個(gè)指針。

  • 第一個(gè)指針從鏈表的頭部開始遍歷向前走k-1(3-1=2)步,第二個(gè)指針保持不動(dòng)。
  • 從第k步開始,第二個(gè)指針也開始從鏈表的頭指針開始遍歷,兩指針同時(shí)向前走。
  • 由于兩個(gè)指針的距離始終保持在k-1,當(dāng)?shù)谝粋€(gè)指針到達(dá)鏈表的尾節(jié)點(diǎn)時(shí),第二個(gè)指針正好指向倒數(shù)第k個(gè)節(jié)點(diǎn)。

圖片

實(shí)現(xiàn)代碼

通過上面的分析,我們知道了如何用雙指針的思路,只遍歷一次鏈表就能獲取鏈表的倒數(shù)第K個(gè)節(jié)點(diǎn)。接下來,我們來看下代碼實(shí)現(xiàn)。

首先,我們?cè)O(shè)計(jì)一個(gè)名為GetLinkedListNode的類:

  • 內(nèi)部有2個(gè)私有變量。

pNext P1指針;

pHead P2指針。

  • 構(gòu)造方法接受1個(gè)參數(shù):鏈表頭節(jié)點(diǎn)。

對(duì)參數(shù)進(jìn)行校驗(yàn);

修改兩個(gè)指針的指向:默認(rèn)指向鏈表頭節(jié)點(diǎn)。

export class GetLinkedListNode {
// p1指針
private pNext: ListNode;
// p2指針(與p1指針的距離始終保持在k-1)
private pHead: ListNode;

constructor(listHead: ListNode) {
if (listHead == null) {
throw new Error("鏈表頭節(jié)點(diǎn)不能為空");
}

// 初始化兩個(gè)指針指向
this.pNext = listHead;
this.pHead = listHead;
}

上述代碼中,我們用了一個(gè)自定義類型ListNode,它描述了一個(gè)鏈表的節(jié)點(diǎn)應(yīng)該包含哪些屬性,對(duì)此感興趣的開發(fā)者請(qǐng)移步我的另一篇文章:鏈表與變相鏈表的實(shí)現(xiàn)。

緊接著,實(shí)現(xiàn)獲取倒數(shù)第K個(gè)節(jié)點(diǎn)函數(shù):

  • 接受一個(gè)參數(shù)K(從1開始),對(duì)參數(shù)進(jìn)行有效性校驗(yàn)。
  • 修改p1指針的指向,將其指向k-1節(jié)點(diǎn),k的范圍也要做一下規(guī)避處理(其值大于鏈表總節(jié)點(diǎn)數(shù))。
  • 同步修改p1、p2指針的指向,直至p1指針指向尾節(jié)點(diǎn),p2指針正好指向倒數(shù)第K個(gè)節(jié)點(diǎn)。
// 獲取倒數(shù)第K個(gè)節(jié)點(diǎn)
getCountdownNode(k: number): ListNode {
if (k <= 0) {
throw new Error("需要獲取的倒數(shù)節(jié)點(diǎn)數(shù)必須大于0");
}

// p1指針先走,將其指向鏈表的k-1位置
for (let i = 0; i < k - 1; i++) {
// k可能出現(xiàn)大于鏈表總節(jié)點(diǎn)的情況,需要進(jìn)行規(guī)避
if (this.pNext.next != null) {
this.pNext = this.pNext.next;
} else {
throw new Error("需要找的節(jié)點(diǎn)不存在");
}
}

// 兩個(gè)指針同時(shí)向前走,直至p1指針指向尾節(jié)點(diǎn)
while (this.pNext.next) {
this.pNext = this.pNext.next;
if (this.pHead.next) {
this.pHead = this.pHead.next;
}
}

// p2節(jié)點(diǎn)正好指向倒數(shù)第K個(gè)節(jié)點(diǎn)
return this.pHead;
}

完整代碼請(qǐng)移步:GetLinkedListNode.ts。

小tips:我們?cè)趯懘a的時(shí)候,一定要盡可能地考慮各種邊界情況的處理,最大程度的避免一些錯(cuò)誤的發(fā)生,提升代碼的健壯性。

例如上述代碼中所做的處理,最大程度的避免了程序因取不到值而引發(fā)的異常報(bào)錯(cuò)問題,我們也管這種做法稱為防御性編程。

這是一種良好的編程習(xí)慣,在編寫代碼的時(shí)候多問問自己“如果不······那么······”這樣的問題,提前預(yù)見在什么地方可能會(huì)出現(xiàn)問題,并為這些可能出現(xiàn)的問題制定處理方式。這樣,當(dāng)異常情況發(fā)生時(shí),軟件的行為也盡在我們的掌握之中,而不至于出現(xiàn)不可預(yù)見的事情。

測(cè)試用例

接下來,我們將前言中的例子代入上個(gè)章節(jié)所實(shí)現(xiàn)的函數(shù)中,驗(yàn)證下它能否得出正確的結(jié)果。

const linkedList = new LinkedList();
linkedList.push(1);
linkedList.push(3);
linkedList.push(5);
linkedList.push(9);
linkedList.push(15);
linkedList.push(21);

const getLinkedListNode = new GetLinkedListNode(linkedList.getHead());
const resultNode = getLinkedListNode.getCountdownNode(3);
console.log(resultNode);

運(yùn)行結(jié)果如下所示,成功的解決了文章前言中所講的問題。

圖片

完整代碼請(qǐng)移步:GetLinkedListNode-test.ts。

注意:上述代碼中用到的LinkedList是自定義的一個(gè)類,它實(shí)現(xiàn)了鏈表這個(gè)數(shù)據(jù)結(jié)構(gòu)。

示例代碼

本文所列舉的代碼,其完整版請(qǐng)移步:

  • GetLinkedListNode.ts
  • GetLinkedListNode-test.ts
責(zé)任編輯:武曉燕 來源: 神奇的程序員
相關(guān)推薦

2021-08-10 07:57:03

算法鏈表倒數(shù)

2021-02-03 13:23:42

鏈表倒數(shù)結(jié)點(diǎn)

2022-01-17 09:23:02

LeetCode刪除鏈表算法

2021-04-14 10:19:18

鏈表倒數(shù)結(jié)點(diǎn)

2020-10-19 13:27:19

鏈表倒數(shù)結(jié)點(diǎn)

2023-04-17 07:33:11

反轉(zhuǎn)鏈表移除鏈表

2022-03-01 07:52:38

鏈表指針節(jié)點(diǎn)

2012-06-19 14:23:04

云計(jì)算中國(guó)

2012-02-17 09:43:13

手機(jī)網(wǎng)速移動(dòng)互聯(lián)

2012-02-17 09:45:04

網(wǎng)速手機(jī)

2012-08-10 10:53:03

云計(jì)算BSA商業(yè)軟件聯(lián)盟

2012-06-18 10:07:17

云計(jì)算實(shí)力榜

2022-02-16 09:12:22

LeetCode升序鏈表鏈表數(shù)組

2018-03-01 13:32:28

宏碁游戲本PC行業(yè)

2021-09-22 22:57:41

手機(jī)流量通信

2021-08-14 09:48:02

ReentrantLock多線編程

2021-11-05 07:59:25

HashMapJava知識(shí)總結(jié)

2019-11-01 11:19:25

轉(zhuǎn)鏈表LeetCode代碼

2022-11-14 14:55:05

軟件開發(fā)程序員薪資

2012-02-21 17:17:51

手機(jī)網(wǎng)速網(wǎng)速
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)