题目
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
难点
1. 识别终止条件
2. 正确处理Java的引用
变量在=左边时为引用,在=右边时为引用指向的内存地址。
public static void main(String[] args) {
Node first = new Node(1);
first.next = new Node(2);
Node tmp = first.next;
first.next = new Node(9);
System.out.println(tmp.val);//2
System.out.println(first.next.val);//9
}
static class Node{
int val; Node next;
public Node(int val){
this.val = val;
}
@Override
public String toString() {
return "["+ val + "]";
}
}
3. 窗口(指针)移动处理
4. 临时变量保存何值的选择
错误的实例
1. 死循环
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
* 输入: 1->2->3->4->5->NULL
* 输出: NULL<-1<-2<-3<-4<-5
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(true){
ListNode tmp = prev;
prev = cur;
cur = cur.next;//1
if(cur == null) break;//2
prev.next = tmp;
cur.next = prev;//3
}
return prev;
}
}
2代码试图当窗口移动到NULL时成立并退出循环,但是1与3的执行实际上使得2永远无法达成,形成死循环
2. 错误的使用引用
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
* 输入: 1->2->3->4->5->NULL
* 输出: NULL<-1<-2<-3<-4<-5
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(cur != null){
ListNode tmp = prev;
prev = cur;//1
prev.next = tmp;//2
cur = cur.next;//3
}
return prev;
}
}
1的执行使得prev和cur引用指向了同一内存地址,2的执行实际上改变了cur.next的值,使得cur.next也被赋予了tmp,3显然就错了
3. 正确的做法
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
* 输入: 1->2->3->4->5->NULL
* 输出: NULL<-1<-2<-3<-4<-5
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(cur != null){
ListNode tmp = cur.next;
cur.next = prev;
prev = cur;
cur = tmp;
}
return prev;
}
}
总结
上面两道错误的解题思路还有个问题在于无法正确处理边界。我们通过tmp来保存中间变量,两道错题保存的是prev值。当窗口向右移动到NULL时,cur值会为null,此时我们返回的是prev而不是cur。这意味着我们无需处理cur.next的情况了,因为cur==null时会被舍弃。
swap需要临时变量tmp协助,前面两个错误的例题使用tmp来保存prev的内存地址指向的值,而实际上tmp只能保存cur.next的值。
错误示范
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head, prev = null;
while(cur != null){
ListNode tmp = prev;
prev = cur;
prev.next = tmp;
cur = cur.next;//1
cur.next = prev;//2
}
return prev;
}
}
两个错误:
1)1中cur已经被赋予了其他值,2这时候的cur.next不再等于1中的cur.next。显然需要中间变量来处理
2)1中cur赋值后可能为null,到2会发生空指针异常。因此cur赋值后不能再被使用,应直接进入循环判断条件。
结论:实际上这道题解题通过迭代解决方式单一。tmp只能保存cur.next,而不是保存prev。这样可以使得cur=tmp(cur在赋值后不会再在代码块中使用)