LinkedList_LeetCode019
019题:
第一种方法:暴力解,借鉴002创建一个新的ListNode存储答案,先遍历原ListNode获得他的长度并把他放入map,然后读取map并创建出答案来。
其中创建的这个节点的第一位置其实是一个哑节点(dummy node)。用于简化某些极端情况!
public static ListNode Ssozh_removeNthFromEnd(ListNode head, int n){
// ListNode.pprint(head);
Map<Integer,Integer> map = new HashMap<>();
ListNode tmp = head;
int cnt = 0;
for(;;){
if (tmp.next != null) {
map.put(cnt,tmp.val);
tmp=tmp.next;
cnt++;
} else {
map.put(cnt,tmp.val);
// System.out.println(head.val);
break;
}
}
// System.out.println(cnt);
int j = 0;
ListNode ans = new ListNode(0); // this one will be remove
ListNode node = ans ;
for(;;){
if(j == cnt + 1) break;
if(j == cnt + 1 - n) {
j++;
continue;
}
node.next = new ListNode(map.get(j));
node = node.next;
j++;
System.out.println("j="+j);
}
return ans.next;
}
这种解法的内存占用大,用时慢。对于内存占用大,可以把创建一个新的ans链表改为在原链表上更改的方法。
方法二:依然是暴力解,但是对方法一进行了改进,将创建一个ListNode改为在head上直接改。
// ListNode.pprint(head);
ListNode tmp = head;
int cnt = 0; // len of head and 0 is start number.
for(;;){
if (tmp.next != null) {
tmp=tmp.next;
cnt++;
} else {
break;
}
}
if(n == cnt+1) return head.next; // if n == len ?
int j = 0;
ListNode node = head; // in fact this var 'node' could be replace with var 'tmp' and could be turn into dummy.
for(;;){
if(j == cnt +1- n){
node.next = node.next.next;
break;
}
node = node.next;
j++;
}
return head;
这里需要注意的是,上面无论是tmp,node都是引用,而ans其实是一个深拷贝的操作。这里面是没有浅拷贝的!
上面两种方法都是用了两次遍历,第三种方法比第二种方法快只用了一次遍历,但实质上这三种方法都是O(L)的时间复杂度。
第三种方法:双指针法,先一个指针走n步,然后第二个指针和第一个一次走到头。
public static ListNode removeNthFromEnd(ListNode head, int n){
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode first = dummy;
ListNode second = dummy;
for(int i=0;i<n+1;i++){
first = first.next; // move n times
}
while(first.next!=null){
first =first.next;
second = second.next;
}
second.next = second.next.next;
return dummy.next;
}
以上就是LeetCode019的三种解法,其中与链表相关的还有LeetCode002,与双指针相关的还有011MaxArea。后面会把这些相关的都一起写一下。