我要把所有链表反转的题目刻在DNA上

165 阅读3分钟

这两天笔试被反转链表折磨得不轻,明明在Leetcode上做反转链表时已经能够一分钟内BUGfree了,但是题目稍微变一点又变成憨憨了,究其原因是一些细节没有做到位,遂写文总结下。

最基础的反转链表

解法:head指针指向链表的第一个元素;tail指针,或者便于一般性反转过程的pre指针,则指向最后一个元素的下一个元素(这里的NULL)。然后就是一套经典组合拳了:

ListNode* ReverseList(ListNode *head) {
    ListNode *pre = NULL, *cur = head;
    while(cur) {
        ListNode *next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}

这里需要注意的点是:什么时候结束反转,以及结束后,哪个指针存储着新链表的头?

在这一套传统艺能中,执行完一轮循环体内容,pre和cur间是没有相连关系的,当cur等于NULL时,pre指向着最后一个结点,此时pre就是新链表的头指针

稍微进阶:反转部分链表

现在来沿用最基本的反转链表中的思想:left指针指向需要反转的链表头,而right指针指向需要反转的链表的最后一个元素的下一个

相比于上一题,这题需要注意的点是,链表反转完你得接回去啊!!right记录着反转链表的下一个了,因此这里需要添加一个指针,这个指针的下一个节点是反转链表的头

还有一点,上一题反转后直接返回pre就是头结点了,在这里,要是一般情况返回个head也OK了。但特殊值,head结点可能是反转链表的头结点,这时它就不在head的位置了!于是通用的做法是定义一个哑结点dummyHead,dummyHead->next = head。返回时返回dummyHead->next。

ListNode *Reverse(ListNode *head, ListNode *tail) {        
    ListNode *pre = tail, *cur = head;        
    while(cur != tail) {            
        ListNode *next = cur->next;            
        cur->next = pre;            
        pre = cur;            
        cur = next;        
    }        
    return pre;    
}    

ListNode* reverseBetween(ListNode* head, int left, int right) {
    //重点:哑结点,解决头指针被反转的特殊情况        
    ListNode *dummyHead = new ListNode(-1, head);        
    //声明两个指针,用来保存反转的区间        
    ListNode *l = dummyHead, *r = head;        
    //注意到题目定义第一个结点的下标为1,于是声明一个临时下标,初始值为1        
    int i = 1;       
 
    //首先找到需要反转链表的头结点的前一个        
    while(i != left) {            
        l = l->next;            
        ++i; //不要随便把++写进判断语句里       
    }        
    //此时反转链表头指针的位置是l->next,用同样的方法寻找右指针        
    //由于右指针是指向最后一个元素的下一个元素,因此判断条件为i == right + 2        
    r = l;        
    while(i++ != right + 2) {            
        r = r->next;        
    }

    //拼接
    l->next = Reverse(l->next, r);    
                    
    return dummyHead->next;    
}

再进阶:K个一组反转链表

其实也没什么进阶的,就是多反转几次而已。

总结

  1. 记住自己熟悉的一套反转模板,我是喜欢左闭右开,那么不管是原始的反转还是附加条件的反转,我都写好一个反转函数,接下来要做的就是找到传入的参数。
  2. 哑结点!永远不要忽略头指针作为反转链表一部分的情况。