java面試算法題(2)

引言

本篇博文中核心是對單鏈表的數據操作,從不同角度分析問題,尋求不同的結果。分享給大家。

題目

存在一個單鏈表,尋找這個單鏈表倒數第K的元素。比如{1->2->3->4->5},倒數第2個元素爲4。

分析一

最容易想到的是:我們自己先遍歷一遍鏈表,獲取鏈表的總長度爲N,那麼我們就知道倒數第K的元素位置就是N-K。然後重新遍歷該鏈表,尋找N-K位置的元素就可以了。

實現代碼一


package com.brickworkers;

/**
 * 
 * @author Brickworker
 * Date:2017年6月28日下午2:25:55 
 * 關於類Example.java的描述:在單鏈表中尋找倒數第K個元素
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public class Example<T> {

    //定義一個頭節點
    Node head = null;

    //定義一個內部類,表示一個鏈表的節點
    class Node{
        private T t;
        Node next;
        public Node(T t) {
            this.t = t;
        }
    }

    //鏈表插入數據
    public void insert(T t){
        Node node = new Node(t);
        //如果頭結點是空,那就是首次插入
        if(head == null){
            head = node;
        }else {
            //如果頭結點不爲空,那麼尋找最後爲空的位置插入
            Node p = head;
            while(p.next!= null){
                p = p.next;
            }
            p.next = node;
        }

    }

    //展示鏈表狀態
    public void print(){
        Node p = head;
        while(p!=null){
            System.out.print(p.t + "->");
            p = p.next;
        }
        System.out.print("null\n");
    }


    //打印倒數第K個元素
    //分析一
    public void analysis1(int K){
    if(K < 1){
            throw new IllegalArgumentException("K參數不合法");
        }
        //先遍歷一次鏈表獲得總長度
        int count = 0;
        Node p = head;
        while(p !=null ){
            count ++;
            p = p.next;
        }

        //再遍歷一遍鏈表獲得對於的值
        count = count - K;//把倒數轉成順序遍歷的位置
        p = head;
        while(count > 0){
            p = p.next;
            count --;
        }
        System.out.println("倒數第" + K +"個元素爲:" + p.t);

    } 

    public static void main(String[] args) {
        //構建一個鏈表
        Example<Integer> example = new Example<Integer>();
        example.insert(1);
        example.insert(2);
        example.insert(3);
        example.insert(4);
        example.insert(5);
        //打印鏈表結構
        example.print();
        //獲取倒數第三個元素
        example.analysis1(3);
    }

}
//
//1->2->3->4->5->null
//倒數第3個元素爲:3

在上面的代碼中,構建了一個自定義的單鏈表結構。這種解決方式是最容易想到,而且代碼寫起來也非常順利。

分析二

第二種容易想到的辦法就是蠻力法,如果從鏈表中的某一個節點開始,遍歷K個元素到達鏈表尾部,那麼這個開始的節點就是倒數第K個節點。那麼實現上來說,我們就需要對每一個節點嘗試進行遍歷K個元素,查看是否到達鏈表尾部就可以了。比如開始的節點爲C,那麼只要保證C.(K-1).next !=null && C.K.next ==null的時候C就是我們要尋找的節點。但是在代碼中,我們從頭開始遍歷,只需要恰好出現最後一個爲null的時候就可以確認倒數第K個數了。

實現代碼二

//爲了節省篇幅,只提供核心代碼,其餘代碼和實現代碼一是一樣的,只需要把下面代碼嵌入使用就可以
    public void analysis2(int K){
        if(K < 1){
            throw new IllegalArgumentException("K參數不合法");
        }
        //從頭開始遍歷鏈表
        Node p = head;
        while(getIndex(p, K) != null){
            p = p.next;
        }
        System.out.println("倒數第" + K +"個元素爲:" + p.t);
    }

    //獲取當前位置後k個數
    private Node getIndex(Node n, int k){
        while(k > 0){
            n = n.next;
            k --;
        }
        return n;

    }

在上述的代碼中,其實時間複雜度比分析一種的還要高,假如存在n個元素,那麼最差時間複雜度就是O(kn),效率比較低下,但是可以拓展思維能力。

分析三

還有一個最高效解決這個問題的辦法:指針追擊。設置兩個指針,其中一個指針先行k步,然後兩個指針同時向前移動。當先行的指針爲null的時候,那麼後面這個指針所指向的元素就是倒數第K個元素。

實現代碼三

public void analysis3(int K){
        if(K < 1){
            throw new IllegalArgumentException("K參數不合法");
        }
        //設立兩個指針
        Node fast = head;//快行K步
        Node slow = head;
        while(K > 0){
            //中途出現了null值,一般考慮K值不合法的情況
            if(fast == null){
                throw new IllegalArgumentException("K參數不合法");
            }
            fast = fast.next;
            K --;
        }
        //兩個指針同時向前移動
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        System.out.println("倒數第" + K +"個元素爲:" + slow.t);
    }

這種方法效率最高,但是不易想到,但是如果有看過關於類似指針追擊,找環這樣問題的,應該還是可以運用的上。它只需要遍歷一遍鏈表就可以處理完結果。

總結

在鏈表中做數據處理的時候,尤其是查找特定條件下的元素,都可以考慮一下多指針是否可以解決問題,往往會有很大收穫。

希望對你有所幫助

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