92. Reverse Linked List II。

Reverse a linked list from position m to n. Do it in-place and in one-pass.

For example:
Given 1->2->3->4->5->NULL, m = 2 and n = 4,

return 1->4->3->2->5->NULL.


题中让在一条链表中将给定位置中间的节点进行反转。可以使用两个栈node1和node2,node1存储位置m之前的节点,然后将m和n之前的节点存放在node2中。然后将node1中的节点依次取出,使用头插法插入到新链表来保证和之前链表顺序一致,因为m位置之前并不需要转换位置。node1取完之后将node2的依次取出链接到新链表,这样的话m和n之间的位置就进行了反转,然后再处理剩下的节点(也就是n位置之后的),依次添加到新链表之后即可。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if(!head || m==n) {
            return head;
        }

        ListNode* dummpy = new ListNode(0);
        dummpy->next = head;
        ListNode* temp = dummpy;
        ListNode* result = new ListNode(0);
        ListNode* tail = result;

        stack<ListNode*> node1;
        stack<ListNode*> node2;

        int num = n - m + 1;//需要加1,此时需要包含后面的那个节点

        m--;
        while(m) {//将m之前的都存放在node1栈中
            temp = temp->next;
            node1.push(temp);
            m--;
        }

        while(num&&temp) {
            temp = temp->next;
            node2.push(temp);
            num--;
        }

        if(temp) {
            temp = temp->next;//移动到变换后的一个节点
        }

        while(!node1.empty()) {//前面的顺序不变,所以使用头插法
            node1.top()->next = result->next;
            result->next = node1.top();
            if(tail == result) {
                tail = node1.top();
            }
            node1.pop();
        }


        while(!node2.empty()) {
            tail->next = node2.top();
            tail = tail->next;
            node2.pop();
        }

        while(temp) {
            tail->next = temp;
            tail = temp;
            temp = temp->next;
        }

        tail->next = nullptr;

        return result->next;
    }

};

也可以使用两个指针,第一个指针先移动到m位置,然后记录下此刻的位置,然后计算出此刻共需要反转多少个元素,从第一个指针所指的m位置开始遍历,反转一定的元素之后再遍历下面的元素。这个方法就是需要记录各个关键地方的位置。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if(!head || m==n) {
            return head;
        }


        ListNode* dummpy = new ListNode(0);
        dummpy->next = head;
        ListNode* start = dummpy;//指向需要变换的开头
        ListNode* tail = nullptr;//指向需要变换的结尾
        ListNode* temp = nullptr;
        ListNode* p1,*p2;

        int num = n - m;

        m--;

        while(m) {//运行到需要变换位置的前一个节点
            start = start->next;
            m--;
        }

        p1 = start;//记录中断的位置
        p2 = start->next;//记录转换后的最后一个位置(也就是m位置)

        start = start->next;//此刻的位置才是需要开始变换的位置
        temp = start->next;//指向下一个节点
        start->next = nullptr;

        while(temp && num) {//将m和n之间进行反转链接
            tail = temp->next;
            temp->next = start;

            start = temp;
            temp = tail;
            num--;
        }


        p1->next = start;//与前半部分对接


        while(temp) {//需要用temp而不是tail,因为tail可能为空(如果没有进while(temp&&num)tail就是空)
            p2->next = temp;
            p2 = temp;
            temp = temp->next;
        }

        return dummpy->next;
    }
};

还有一种极为简洁的写法,思路也是使用指针。与上述方法不同的是:上述方法将n和m中间的节点相当于是完全隔离出来进行反转,然后再次进行对接,也就是说将原链表断开了,单独处理n和m之间。下面这种方式是保证原链表不断的情况下进行n和m之间的反转,代码写的可以说是非常漂亮了。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        if(m == n)
            return head;
        n = n - m;
        ListNode* pre = new ListNode(0);
        ListNode* pre_stable = pre;
        pre->next = head;
        while(--m > 0)
            pre = pre->next;
        ListNode* p = pre->next;
        while(n-- > 0)
        {
            ListNode* q = p->next;
            p->next = p->next->next;
            q->next = pre->next;
            pre->next = q;
        }
        return pre_stable->next;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值