206-反转链表

开始学习的时候对这一类问题十分混乱,尤其是指针的调用,这里面引用一位leetcode大佬huwt的解析,觉得很好拿来分享一下。

也体会到了大佬的话:这种题就要多画图,寻找每一次过程的关系,多总结,就做好了,作为第二天leetcode的重头戏。

好理解的双指针
定义两个指针: pre 和 cur ;pre 在前 cur 在后。
每次让 pre 的 next 指向 cur ,实现一次局部反转
局部反转完成之后, pre 和 cur 同时往前移动一个位置
循环上述过程,直至 pre 到达链表尾部

 1 class Solution {
 2 public:
 3     ListNode* reverseList(ListNode* head) {
 4         ListNode* cur = NULL, *pre = head;
 5         while (pre != NULL) {
 6             ListNode* t = pre->next;
 7             pre->next = cur;
 8             cur = pre;
 9             pre = t;
10         }
11         return cur;
12     }
13 };

递归的思想:

使用递归函数,一直递归到链表的最后一个结点,该结点就是反转后的头结点,记作 retret .
此后,每次函数在返回的过程中,让当前结点的下一个结点的 nextnext 指针指向当前节点。
同时让当前结点的 nextnext 指针指向 NULLNULL ,从而实现从链表尾部开始的局部反转
当递归函数全部出栈后,链表反转完成。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if (head == NULL || head->next == NULL)
        {
            return head;
        }

        ListNode* curr = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return curr;
    }
};

 总结:

链表反转的口诀

  1. 保存前进方向
  2. 斩断后路,不忘前事
  3. 继续前行
// 链表反转口诀:斩断后路,不忘前事,才能重获新生
func reverseList(head *ListNode) *ListNode {
    var pre *ListNode = nil
    cur := head
    for nil != cur {
        // 1.(保存一下前进方向)保存下一跳
        temp := cur.Next
        // 2.斩断过去,不忘前事
        cur.Next = pre
        // 3.前驱指针的使命在上面已经完成,这里需要更新前驱指针
        pre = cur
        // 当前指针的使命已经完成,需要继续前进了
        cur = temp
    }
    return pre
}

猜你喜欢

转载自www.cnblogs.com/nxnslc-blog/p/12375136.html