<LeetCode> 题36:翻转链表2(翻转指定部分)

1. 题目描述:

翻转链表中第m个节点到第n个节点的部分
注意:m,n满足1 ≤ m ≤ n ≤ 链表长度
例如:给出链表1->2->3->4->5->null, m = 2 和n = 4,返回1->4->3->2->5->null

2. 链表数据结构

/**
 * struct ListNode
 * {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
**/

3. 分析:

其实知道了如何翻转整个链表,我们完全可以按照翻转整个链表的迭代法的思路反转链表[m,n]之间的部分,这里需要指针特别记录一下m-1和n+1的位置,便于将翻转后的部分正确插入。时间复杂度为O(n),空间复杂度为O(1)。

4. 代码

4.1 写法1:

  1. 申请一个辅助链表,将第m到第n个节点依次插入到辅助链表头结点后,完成异地置逆。
  2. 将辅助链表插回到原链表的 m 到 n 之间。
class Solution 
{
public:
    ListNode *reverseBetween(ListNode *head, int m, int n)
    {
        if(head == NULL || m >= n)
            return head;//注意:这里不能写成return NULL
        ListNode *newHead = new ListNode(0); //原链表前增加头结点
        newHead->next = head;
        ListNode *tempHead = new ListNode(0); //辅助链表的头结点
        ListNode *pre = newHead; //需要置逆的前一个节点
        int i = 1; //第i个节点,永远指向需要被删除的那么节点
        while(pre->next != NULL && i < m) //将i指向第m个节点,pre指向第m-1个节点
        {
            pre = pre->next;
            i++;
        }
        ListNode *p = NULL;
        while(m <= n && pre->next != NULL)
        {
            p = pre->next;
            pre->next = p->next; //在原链表上去掉第i个节点
            p->next = tempHead->next;
            tempHead->next = p; //将第i个节点添加到辅助链表上
            m++;
        }
        p = tempHead;
        while(p->next != NULL) //p指向辅助链表的最后一个节点
        {
            p = p->next;
        }
        p->next = pre->next;
        pre->next = tempHead->next; //将辅助链表除头结点以外部分插入到原链表pre后面
        return newHead->next;
    }
};

参考博客:http://blog.csdn.net/yapian8/article/details/42773199

4.2 写法2:

关键点:
1、m=1?——设置标志,令m=2,对第一个结点最后进行处理
2、n=1?——-直接退出,不用移动
3、找到m-1结点所在的位置,一个一个交换,但要画图,交换之间相隔很多的时候,要设置中间指针。

class Solution 
{
public:

    ListNode *reverseBetween(ListNode *head, int m, int n)
    {
        if(n == 1 || m == n)  
            return head;  
        ListNode *p = head;  
        int i = 1;  
        int flag = 0;   //m=1的时候,进行标记,先不移动第一个数据,最后移动  
        if(m == 1)
        {  
            m = 2;  
            flag = 1;  
        }  
        while(i < m-1)
        { //p指向m-1的位置  
            p = p->next;  
            i++;  
        }  
        ListNode *q = p->next;  //q指向m的位置,直到循环截止,q的指针也不改变  
        while(m < n)
        {   //一个一个移动,不能只判断开始相邻的情况,多画几个找出规律  
            ListNode *h = p->next;  
            p->next = q->next;  
            q->next = q->next->next;  
            p->next->next = h;  
            m++;  
        }  
        if(flag)
        {       //如果m=1,那么将p移动到q结点的下一个,同时也要改变头指针的位置  
            head = p->next;  
            p->next = q->next;  
            q->next = p;  
        }  
        return head;  
    }
};

参考博客:http://blog.csdn.net/a45872055555/article/details/38533939

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值