連結串列問題——在單鏈表和雙鏈表中刪除倒數第K個節點
【題目】
分別實現兩個函式,一個可以刪除單鏈表中倒數第K個節點,另一個可以刪除雙鏈表中倒數第K個節點。
【要求】
如果連結串列長度為N,時間複雜度達到O(N),時間複雜度達到O(N),額外空間複雜度達到O(1)
【解答】
本題較為簡單,實現方式也是多種多樣的,這裡只介紹一種方法。
先來看看單鏈表如何調整。如果連結串列為空或者K值小於1,這種情況下,引數是無效的,直接返回即可。除此之外,讓連結串列從頭開始走到尾,每移動一步,就讓k的值減1。
連結串列:1->2->3,K=4,連結串列根本不存在倒數第4個節點。
走到的節點:1->2->3
K變化為:3 2 1
連結串列:1->2->3,K=3,連結串列倒數第3個節點是1節點
走到的節點:1->2->3
K變化為:2 1 0
連結串列:1->2->3,K=2,連結串列倒數第2個節點是2節點
走到的節點:1->2->3
K變化為:1 0 -1
由以上三種情況可知,讓連結串列從頭開始走到尾,每移動一步,就讓K值減1,當連結串列走到結尾時,如果K值大於0,說明不用調整連結串列,因為連結串列根本沒有倒數第K個節點,此時將原連結串列直接返回即可;如果K值等於0,說明連結串列倒數第K個節點就是頭結點,此時直接返回head.next,也就是原連結串列的第二個節點,讓第二個節點作為連結串列的頭返回即可,相當於刪除頭節點;接下來,說明一下如果K值小於0,該如何處理。
先明確一點,如果要刪除連結串列的頭結點之後的某個節點,實際上需要找到要刪除節點的前一個節點,比如:1->2->3,如果想刪除節點2,則需要找到節點1,然後把節點1連到節點3上(1->3),以此來打到刪除節點2的目的。
如果K值小於0,如何找到要刪除節點的前一個節點呢?方法如下:
1.重新從頭節點開始走,每移動一步,就讓K的值加1。
2.當K等於0是,移動停止,移動到的節點就是要刪除節點的前一個節點。
【程式碼實現】
public class Node{
public int value;
public Node next;
public Node(int data){
this.value = data;
}
}
public Node removeLastKthNode(Node head,int lastKth){
if(head == null || lastKth < 1){
return head;
}
Node cur = head;
while(cur != null ){
lastKth--;
cur = cur.next;
}
if(lastKth==0){
head = head.next;
}
if(lastKth<0){
cur = head;
while(++lastKth!=0){
cur = cur.next;
}
cur.next = cur.next.next;
}
return head;
}
雙鏈表的調整和單鏈表的處理幾乎一樣,只需要注意雙鏈表的刪除和單鏈表的刪除不一樣就好了
【程式碼實現】
public class DoubleNode{
public int value;
public DoubleNode last;
public DoubleNode next;
public DoubleNode(int data){
this.value = data;
}
}
public DoubleNode removeLastKthNode(DoubleNode head,int lastKth){
if(head==null || lastKth < 1){
return head;
}
DoubleNode cur = head;
while(cur!=null){
lastKth--;
cur = cur.next;
}
if(lastKth==0){
head = head.next;
head.last = null;
}
if(lastKth<0){
cur = head;
while(++lastKth!=0){
cur = cur.next;
}
DoubleNode newNext = cur.next.next;
cur.next = newNext;
if(newNext!=null){
newNext.last = cur;
}
}
return head;
}