第二章 链表问题
2.2 在单链表和双链表中删除倒数第 K 个节点
【题目】
分别实现两个函数,一个可以删除单链表中倒数第 K 个节点,另一个可以删除双链表中倒数第 K 个节点。
【要求】
如果链表长度为 N,时间复杂度达到 O(N),额外空间复杂度达到 O(1)。
【难度】
士 ★☆☆☆
【题解】
对于单链表,如果链表为空或者 K<1,则参数是无效的,直接返回即可。否则让链表从头开始走到尾,每移动一步,就让 K 的值减一。当链表走到尾部,如果 K>0,则不用调整链表,因为链表没有倒数第 K 个节点;如果 K=0,则链表倒数第 K 个节点就是头节点,删去头节点即可;如果 K<0,则重新从头节点开始走,每走一步,就让 K 的值加一,当 K=0,移动到的节点就是倒数第 K 个节点的前一个节点,删去下一个节点即可。因为如果链表长度为 N ,要删除倒数第 K 个节点,倒数第 K 个节点的前一个节点就是第 N-K 个节点。在第一次遍历后,K 的值变为 K-N。第二次遍历时,K 的值不断加一直到等于 0,第二次遍历就会停到第 N-K 个节点的位置。
对于双链表,与单链表的处理方式一样,注意 last 指针的重连即可。
【实现】
- RemoveSingleLinkedListLastKthNode
public class RemoveSingleLinkedListLastKthNode {
private static class Node {
public int value;
public Node next;
public Node(int value) {
this.value = value;
}
}
private Node head;
public RemoveSingleLinkedListLastKthNode(int[] arr) {
buildSingleLinkedList(arr);
}
private void buildSingleLinkedList(int[] arr) {
if (arr != null && arr.length != 0) {
Node preNode = this.head = new Node(arr[0]);
for (int i = 1; i < arr.length; i++) {
preNode = preNode.next = new Node(arr[i]);
}
}
}
public void removeSingleLinkedListLastKthNode(int lastKth) {
if (this.head == null || lastKth < 1) {
return;
}
Node curNode = this.head;
while (curNode != null) {
--lastKth;
curNode = curNode.next;
}
/**
*
*/
if (lastKth == 0) {
this.head = this.head.next;
} else if (lastKth < 0) {
curNode = this.head;
while (++lastKth != 0) {
curNode = curNode.next;
}
curNode.next = curNode.next.next;
} else {
// 超出范围
}
}
}
- RemoveDoubleLinkedListLastKthNode.java
public class RemoveDoubleLinkedListLastKthNode {
private static class Node {
public int value;
public Node last;
public Node next;
public Node(int value) {
this.value = value;
}
}
private Node head;
public RemoveDoubleLinkedListLastKthNode(int[] arr) {
buildDoubleLinkedList(arr);
}
private void buildDoubleLinkedList(int[] arr) {
if (arr != null && arr.length != 0) {
Node preNode = this.head = new Node(arr[0]);
for (int i = 1; i < arr.length; i++) {
preNode.next = new Node(arr[i]);
preNode.next.last = preNode;
preNode = preNode.next;
}
}
}
public void removeDoubleLinkedListLastKthNode(int lastKth) {
if (this.head != null && lastKth >= 1) {
Node curNode = this.head;
while (curNode != null) {
--lastKth;
curNode = curNode.next;
}
if (lastKth == 0) {
this.head = this.head.next;
this.head.last = null;
} else if (lastKth < 0) {
curNode = this.head;
while (++lastKth != 0) {
curNode = curNode.next;
}
curNode.next = curNode.next.next;
if (curNode.next != null) {
curNode.next.last = curNode;
}
}
}
}
}
- Test.java
public class Test {
private RemoveSingleLinkedListLastKthNode singleLinkedList;
private RemoveDoubleLinkedListLastKthNode doubleLinkedList;
public Test(int[] arr) {
this.singleLinkedList = new RemoveSingleLinkedListLastKthNode(arr);
this.doubleLinkedList = new RemoveDoubleLinkedListLastKthNode(arr);
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
Test test = new Test(arr);
test.singleLinkedList.removeSingleLinkedListLastKthNode(3);
test.doubleLinkedList.removeDoubleLinkedListLastKthNode(3);
}
}