题目及用例及linklist
package pid019;
public class LinkList {
public class ListNode {
public int val;
public ListNode next;
ListNode(int x)
{ val = x;
next=null;
}
}
ListNode first;
public LinkList(int x){
first=new ListNode(x);
first.next=null;
}
public void addLast(int x){
ListNode a=first;
while(a.next!=null){
a=a.next;
}
ListNode b=new ListNode(x);
a.next=b;
}
public void printList(){
ListNode a=first;
System.out.println("print listnode");
while(a!=null){//直到最后一个不为空的节点
System.out.print(a.val+" ");
a=a.next;
}
System.out.println();
}
}
package pid019;
/* 删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
*/
import pid019.LinkList;
import pid019.LinkList.ListNode;
public class main {
public static void main(String[] args) {
LinkList a=new LinkList(1);
a.addLast(2);
a.addLast(5);
a.addLast(15);
LinkList b=new LinkList(-5);
b.addLast(0);
b.addLast(500);
b.addLast(-100);
a.printList();
test(a.first,2);
a.printList();
b.printList();
test(b.first,4);
b.printList();
}
private static void test(ListNode ito,int ito2) {
Solution solution = new Solution();
String rtn;
long begin = System.currentTimeMillis();
System.out.println();
//开始时打印数组
solution.removeNthFromEnd(ito,ito2);//执行程序
long end = System.currentTimeMillis();
//System.out.println(":rtn" );
//System.out.print(rtn);
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解法1(成功,11ms,很快)
先得到链表长度,再根据长度,从头开始减去节点,具体在解法中
package pid019;
import pid019.LinkList.*;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int length=0;
ListNode a=head;
ListNode temp;
while(a!=null){
length++;
a=a.next;
}
//比如5个,倒数第二就为第4个,为第三个与第五个相连,如果不是去掉第一个,为(length-n) (length-n).nex.next 相连
//如果是第一个,如果只有一个,返回null,否则将head的值改为下一个,next改为head.next.next
if(length==n){
if(length==1){//去掉只有一个的第一个
return null;
}
else{//去掉第一个
head.val=head.next.val;
temp=head.next;
head.next=temp.next;
temp.next=null;
return head;
}
}
else{
int i=1;
a=head;
while(i<length-n){
a=a.next;
i++;
}
temp=a.next;
a.next=temp.next;
temp.next=null;
return head;
}
}
}
解法二(成功,2ms,超快)
速度其实一样快,都是走length+n步,但看上去简洁了很多
双指针算法
先让一个指针走n-1步,然后再让一个指针指向头结点,然后两具指针一起走,直到前一个指针的next=null,后一个指针就是倒数第N个结点,删除倒数第N个结点就可以了。
如何删除,确定begin前的一个节点pre,让pre.next=begin.next即可
public ListNode removeNthFromEnd(ListNode head, int n) {
//双指针,后走的
ListNode begin=head;
///双指针,先走的
ListNode end=head;
//begin之前的node
ListNode pre=null;
//很明显,如果只有2个,n=1,end走1步时,end.next=null,此时的begin就是被删除的
for(int i=0;i<n-1;i++){
//end先走n-1步
end=end.next;
}
//直到end.next=null,此时的begin就是被删除的
while(end.next!=null){
end=end.next;
pre=begin;
begin=begin.next;
}
if(begin==head){
//删除头结点,直接返回next即可
return head.next;
}
//普通情况
pre.next=begin.next;
return head;
}