輸入一個(gè)單向鏈表,輸出該鏈表中倒數(shù)第k個(gè)結(jié)點(diǎn)。

分析:為了得到倒數(shù)第k個(gè)結(jié)點(diǎn),很自然的想法是先走到鏈表的尾端,再從尾端回溯k步。
可是輸入的是單向鏈表,只有從前往后的指針而沒有從后往前的指針。因此我們需要打開我們的思路。
既然不能從尾結(jié)點(diǎn)開始遍歷這個(gè)鏈表,我們還是把思路回到頭結(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)(從0開始計(jì)數(shù))。
如果我們能夠得到鏈表中結(jié)點(diǎn)的個(gè)數(shù)n,那我們只要從頭結(jié)點(diǎn)開始往后走n-k-1步就可以了。
如何得到結(jié)點(diǎn)數(shù)n?這個(gè)不難,只需要從頭開始遍歷鏈表,每經(jīng)過一個(gè)結(jié)點(diǎn),計(jì)數(shù)器加一就行了。
這種思路的時(shí)間復(fù)雜度是O(n),但需要遍歷鏈表兩次。第一次得到鏈表中結(jié)點(diǎn)個(gè)數(shù)n,第二次得到從頭結(jié)點(diǎn)開始的第n--k-1個(gè)結(jié)點(diǎn)即倒數(shù)第k個(gè)結(jié)點(diǎn)。如 果鏈表的結(jié)點(diǎn)數(shù)不多,這是一種很好的方法。
但如果輸入的鏈表的結(jié)點(diǎn)個(gè)數(shù)很多,有可能不能一次性把整個(gè)鏈表都從硬盤讀入物理內(nèi)存,那么遍歷兩遍意味著一個(gè)結(jié) 點(diǎn)需要兩次從硬盤讀入到物理內(nèi)存。我們知道把數(shù)據(jù)從硬盤讀入到內(nèi)存是非常耗時(shí)間的操作。
我們能不能把鏈表遍歷的次數(shù)減少到1?如果可以,將能有效地提高代碼執(zhí)行的時(shí)間效率。如果我們在遍歷時(shí)維持兩個(gè)指針,第一個(gè)指針從鏈表的頭指針開始遍歷,在第k-1步之前,第二個(gè)指針保持不動;在第k-1步開始,第二個(gè)指針也開始從鏈表的頭指針開始遍歷。
由于兩個(gè)指針的距離保持在k-1,當(dāng)?shù)谝粋€(gè)(走在前面的)指針到達(dá)鏈表的尾結(jié)點(diǎn)時(shí),第二個(gè)指針(走在后面的)指針正好是倒數(shù)第k個(gè)結(jié)點(diǎn)。
這種思路只需要遍歷鏈表一次。對于很長的鏈表,只需要把每個(gè)結(jié)點(diǎn)從硬盤導(dǎo)入到內(nèi)存一次。因此這一方法的時(shí)間效率前面的方法要高。

定義結(jié)點(diǎn):

/**
 * 節(jié)點(diǎn)
 */
public class Node {
    //數(shù)據(jù)域
    int data;
    //指針域
    Node next;

    public Node(int data) {
        this.data = data;
    }

    public Node getNext() {
        return next;

    }

    public void setNext(Node node) {
        this.next = node;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

}

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

 public static Node findKNode(Node head, int k) {
        if (head == null || k < 1) {
            return null;
        }
        Node firstNode = head;
        Node secondNode = head;
        for (int i = 0; i < k - 1; i++) {
            if (firstNode.next != null) {
                firstNode = firstNode.next;
            } else {
                return null;
            }
        }
        while (firstNode.next != null) {
            firstNode = firstNode.next;
            secondNode = secondNode.next;
        }
        return secondNode;
    }

測試代碼:

public class FindKNode {
    public static void main(String args[]) {
        //頭節(jié)點(diǎn)
        Node head = null;
        //當(dāng)前節(jié)點(diǎn)
        Node curNode = null;
        for (int i = 0; i < 10; i++) {
            if (i != 0) {
                Node node = new Node(i + 1);
                curNode.setNext(node);
                curNode = node;
            } else {
                head = new Node(i);
                curNode = new Node(i + 1);
                head.setNext(curNode);
            }

        }
        Node kNode = findKNode(head,5);
        System.out.println("倒數(shù)第K個(gè)節(jié)點(diǎn)是:"+kNode.getData());
    }
  
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載請注明出處:http://m.itdecent.cn/p/c65d9d753c31 在上一篇博客《數(shù)據(jù)結(jié)構(gòu)...
    Alent閱讀 3,616評論 4 74
  • B樹的定義 一棵m階的B樹滿足下列條件: 樹中每個(gè)結(jié)點(diǎn)至多有m個(gè)孩子。 除根結(jié)點(diǎn)和葉子結(jié)點(diǎn)外,其它每個(gè)結(jié)點(diǎn)至少有m...
    文檔隨手記閱讀 13,703評論 0 25
  • 大學(xué)的時(shí)候不好好學(xué)習(xí),老師在講臺上講課,自己在以為老師看不到的座位看小說,現(xiàn)在用到了老師講的知識,只能自己看書查資...
    和玨貓閱讀 1,565評論 1 3
  • 課程介紹 先修課:概率統(tǒng)計(jì),程序設(shè)計(jì)實(shí)習(xí),集合論與圖論 后續(xù)課:算法分析與設(shè)計(jì),編譯原理,操作系統(tǒng),數(shù)據(jù)庫概論,人...
    ShellyWhen閱讀 2,478評論 0 3
  • 文/小小瓶 2016.07.07 今天是一個(gè)平常的日子,生活平靜如水,幾個(gè)月來,不曾泛起半點(diǎn)波瀾。她卻很是不安。 ...
    小小瓶閱讀 632評論 5 5

友情鏈接更多精彩內(nèi)容