【LeetCode & 剑指offer刷题】链表题1:14 反转链表 206. Reverse Linked List(系列)

【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

206. Reverse Linked List

Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
Follow up:
A linked list can be reversed either iteratively or recursively. Could you implement both?
 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
//迭代法
//O(n),O(1)
class Solution
{
public :
    ListNode * reverseList ( ListNode * head )
    {
        if ( head == nullptr ) return nullptr ;
       
        ListNode * pre = nullptr , * cur = head ,* next ; //三个指针分别保存之前,当前,下一个结点
        while ( cur )
        {
            next = cur -> next ; //保存原链表该结点的下一个结点,以免变换指向之后无法遍历到下一个结点
            cur -> next = pre ; //变换指向
           
            pre = cur ; //更新指针
            cur = next ; //更新指针
        }
        return pre ; //最后pre指向最后一个结点,cur指向null
    }
};
 
//递归法(不太好理解)
/*
O(n) O(n)(来自递归栈)
Assume from node nk+1 to nm had been reversed and you are at node nk.
n1 → … → nk-1 → nk → nk+1 ← … ← nm
We want nk+1’s next node to point to nk.
So,
nk.next.next = nk;
*/
class Solution
{
public :
    ListNode * reverseList ( ListNode * head )
    {
        if ( head == nullptr || head -> next == nullptr ) return head ;
       
        ListNode * p = reverseList ( head -> next ); //递归之后为从后往前开始转向
        head -> next -> next = head ;
        head -> next = nullptr ;
        return p ;
    }
};
 
92 .   Reverse Linked List II
Reverse a linked list from position   m   to   n . Do it in one-pass.
Note:  1 ≤   m     n   ≤ length of list.
Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL
 
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
/*
问题:翻转链表 2 (位置 m~n 翻转)
方法: m~n位置处的链表进行翻转,然后连接m-1位置与n位置,m位置与n+1位置
例:
Input: 1 -> 2 -> 3 -> 4 -> 5 -> NULL, m = 2, n = 4
翻转得, 1 <-> 2(m) <- 3 <- 4(n)    5 -> NULL
连接得, 1 -> 4 -> 3 -> 2 -> 5 -> NULL
*/
class Solution
{
public :
    ListNode * reverseBetween ( ListNode * head , int m , int n )
    {
        // 异常情况处理(严格来说,还需判断 m,n 值是否超出链表长度 , 题目已经有此条件)
        if (! head || ! head -> next || m < 0 || n < 0 || m >= n ) return head ;
      
        // prehead的应用: 头结点前的结点,方便索引,方便分析(链表用1开头+prehead分析较好,序号可以与步数对应起来)
        // 且指向了链表的头结点,当 m=1 时,原头结点被换到后面,若返回 head 会出错,
        // 而用 prehead 会指向新头结点,故返回 prehead.next 不会出错
        ListNode prehead ( 0 );
        prehead . next = head ;
       
        ListNode * cur = & prehead ;
        for ( int i = 1 ; i <= m - 1 ; i ++)
            cur = cur -> next ; // 最后 cur 处在 m-1 位置
       
        ListNode * pre = cur ;
        ListNode * next ;
        cur = cur -> next ; // cur 处在 m 位置
        ListNode * prefirst = pre , * first = cur ; // 保存 m-1 位置和 m 位置处的结点
       
        for ( int i = m ; i <= n ; i ++) // 翻转位置 m~n 处的链表
        {
            next = cur -> next ;
            cur -> next = pre ;
           
            pre = cur ; // 更新指针
            cur = next ; // 更新指针
        } // 退出时, pre n 处, cur n+1
       
        prefirst -> next = pre ; // 连接 m-1 n 位置
        first -> next = cur ; // 连接 m n+1 位置
       
        return prehead . next ;
    }
};
 
 
 
 

猜你喜欢

转载自www.cnblogs.com/wikiwen/p/10225166.html
今日推荐