力扣题目
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
代码一
思路是两次遍历,第一次求得一共有多少结点,第二次遍历找到要删除结点的前一个位置,
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int count = 0;
ListNode p = new ListNode();
p = head;
//求得一共有多少结点
while(p!=null){
count++;
p = p.next;
}
int i = 0;
ListNode res = new ListNode();
res.next = head;
ListNode q = res;
//找到要删除结点的前一个位置
while(i<count-n){
q = q.next;
i++;
}
q.next = q.next.next;//删除目标节点
return res.next;
}
}
1.存储结点有一个技巧,那就是新建一个头结点res,让res.next指向head,同时让指针q指向res,操作时对q进行操作,那么有个好处,就是当第一个结点被删除时,res.next仍然能指向新链表的第一个结点,注意返回时要返回res.next,这在链表删除操作时很常用,题目203. 移除链表元素也用到了
“在对链表进行操作时,一种常用的技巧是添加一个哑节点(dummy node),它的 \textit{next}next 指针指向链表的头节点。这样一来,我们就不需要对头节点进行特殊的判断了。
例如,在本题中,如果我们要删除节点 yy,我们需要知道节点 yy 的前驱节点 xx,并将 xx 的指针指向 yy 的后继节点。但由于头节点不存在前驱节点,因此我们需要在删除头节点时进行特殊判断。但如果我们添加了哑节点,那么头节点的前驱节点就是哑节点本身,此时我们就只需要考虑通用的情况即可。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-b-61/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。”
代码二
栈,先进栈,然后将n个结点出栈,这时当前栈顶也就是要删除结点的前驱结点。注意,也要添加哑节点并且进栈
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode res = new ListNode(0,head);
ListNode cur = res;
Deque<ListNode> stack = new LinkedList<ListNode>();
while(cur!=null){
stack.push(cur);
cur = cur.next;
}
for(int i = 0;i<n;i++){
stack.pop();
}
ListNode temp = stack.peek();
temp.next = temp.next.next;
return res.next;
}
}
代码三
快慢指针,让两个指针相差n,当快指针为null时,慢指针就是我们要找的结点。也要设置哑节点。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode res = new ListNode(0,head);
ListNode slow = res;
ListNode fast = head;
//slow和fast实际上隔开了n+1个结点
for(int i = 0;i<n;i++){
fast = fast.next;
}
while(fast!=null){
fast = fast.next;
slow = slow.next;
}
//slow指向目标节点的前驱结点
slow.next = slow.next.next;
return res.next;
}
}