引言
本篇博文中核心是對單鏈表的數據操作,從不同角度分析問題,尋求不同的結果。分享給大家。
題目
存在一個單鏈表,尋找這個單鏈表倒數第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);
}
這種方法效率最高,但是不易想到,但是如果有看過關於類似指針追擊,找環這樣問題的,應該還是可以運用的上。它只需要遍歷一遍鏈表就可以處理完結果。
總結
在鏈表中做數據處理的時候,尤其是查找特定條件下的元素,都可以考慮一下多指針是否可以解決問題,往往會有很大收穫。
希望對你有所幫助