题目描述
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
思路
- 一次扫描实现的意思是我们要在循环中想办法寻找到倒数第n+1个节点,然后将他的next改掉;
- 既然题目给出了定长的空间,我们就要合理利用,使用片段移动的方式来确定倒数第n+1个节点;
代码
public class Demo03 {
public static ListNode removeNthFromEnd(ListNode head, int n) {
if(n == 0){
return head;
}
//1.首先知道链表删除某元素是将上一个元素的next指向该元素的next元素。(跳过该元素)
//2.那么使用额外的list集合,在遍历时将链表元素添加,即可得得到倒数第n,n+1,n-1节点。
//将n+1赋值给n-1的next即可
return null;
}
/**
* 上边的方法采用了额外的集合来完成需求,增加了空间消耗
* 1.既然要移除倒数第n个元素,说明n是确定的,那么如何能使得不借助“外力”在循环中找到倒数第n个元素呢;
* 2.可以使用移动片段的方法;
* 3.假设从倒数第n个元素到链表末尾长度为L,那么如果有一个长度为L的片段左侧从初始位置开始移动;
* 4.当该片段的右侧到达链表末尾,理论上此时的左侧应该在倒数第n个元素处;
* 5.那么依照此方式我们也可以找到第n-1个元素;
* @param head
* @param n
* @return
*/
public static ListNode removeNthFromEnd2(ListNode head, int n) {
if(n == 0){
return head;
}
//1.声明一个起始节点方便控制。
ListNode listNode = new ListNode(0);
listNode.next = head;
ListNode first = listNode;
ListNode end = listNode;
//先让end元素往前移动n+1位
for (int i = 1;i<=n+1;i++){
end = end.next;
}
while (end!=null){
first = first.next;
end = end.next;
}
first.next = first.next.next;
return listNode.next;
}
}
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
总结
- 读题要认真,找出题中隐藏的条件;
- 培养自己的抽象思维,想法要独特但不失理智;
- 尽可能的压缩空间和时间,并在平时写代码的时候注意加以运用。