LeetCode刷题笔记 92. 反转链表 II

92. 反转链表 II

题目要求

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。

示例:

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

题解

https://github.com/soulmachine/leetcode

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode dummy(-1);
        dummy.next=head;

        ListNode *prev=&dummy;
        for(int i=0;i<m-1;i++)
            prev=prev->next;
        ListNode *head2=prev;  //要反转的部分的前一个元素
        prev=head2->next;  //要反转部分的第一个元素
        ListNode *cur=prev->next;
        for(int i=m;i<n;i++){
            prev->next=cur->next;
            cur->next=head2->next;
            head2->next=cur; //头插法
            cur=prev->next;
        }
        return dummy.next;
    }
};

出于对于此代码的想象力有限,利用leetcode的playground我将整个步骤打印了一遍查看细节,供读者参考。

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
        ListNode dummy(-1);
        dummy.next=head;

        ListNode *prev=&dummy;
        for(int i=0;i<m-1;i++){
            prev=prev->next;
            cout << "i"<<" "<<i<<" "<< "prev" << " "<< prev->val << " ";            
        }
            
        ListNode *head2=prev;
        cout << "head2"<< " " << head2->val << " ";
        prev=head2->next;
        cout << "prev" << " "<< prev->val << " ";
        ListNode *cur=prev->next;
        cout << "cur" << " "<< cur->val << " "<<endl;
        for(int i=m;i<n;i++){
            string out = listNodeToString(head);
            cout << "i"<<" "<<i <<"Listfromhead1"<< out << endl;  
            prev->next=cur->next;
            cout << "i"<<" "<<i<<" "<< "prev" << " "<< prev->val << " "<< "prev->next" << " "<< prev->next->val<<endl; 
            out = listNodeToString(head);
            cout << "i"<<" "<<i <<"Listfromhead2"<< out << endl;
            cur->next=head2->next;
            out = listNodeToString(head);
            cout << "i"<<" "<<i <<"Listfromhead3"<< out << endl;
            cout << "cur" << " "<< cur->val << " "<< "cur->next" << " "<< cur->next->val<<endl;
            head2->next=cur; //头插法
            out = listNodeToString(head);
            cout << "i"<<" "<<i <<"Listfromhead4"<< out << endl;
            cur=prev->next;
            out = listNodeToString(head);
            cout << "i"<<" "<<i <<"Listfromhead5"<< out << endl;
        }
        return dummy.next;
    }
};



int main() {
    string line;
    while (getline(cin, line)) {
        ListNode* head = stringToListNode(line);
        getline(cin, line);
        int m = stringToInteger(line);
        getline(cin, line);
        int n = stringToInteger(line);
        
        ListNode* ret = Solution().reverseBetween(head, m, n);

        string out = listNodeToString(ret);
        cout << out << endl;
    }
    return 0;
}

Listfromhead分别对应执行完某一条语句后链表的状态,以下为打印结果。

i 0 prev 1 head2 1 prev 2 cur 3 
i 2Listfromhead1[1, 2, 3, 4, 5]
i 2 prev 2 prev->next 4
i 2Listfromhead2[1, 2, 4, 5]
i 2Listfromhead3[1, 2, 4, 5]
cur 3 cur->next 2
i 2Listfromhead4[1, 3, 2, 4, 5]
i 2Listfromhead5[1, 3, 2, 4, 5]
i 3Listfromhead1[1, 3, 2, 4, 5]
i 3 prev 2 prev->next 5
i 3Listfromhead2[1, 3, 2, 5]
i 3Listfromhead3[1, 3, 2, 5]
cur 4 cur->next 3
i 3Listfromhead4[1, 4, 3, 2, 5]
i 3Listfromhead5[1, 4, 3, 2, 5]
[1, 4, 3, 2, 5]

大致总结下思路:

  1. 将head2定位到需要进行反转部分之前的位置,如本例中[2,3,4]前1的位置。
  2. 将prev指向需要进行反转部分的头部,如[2,3,4]中2的位置。
  3. 将cur指向prev后,如如[2,3,4]中3的位置。
  4. prev->next=cur->next,即将cur位置元素从链表中删除如[2,3,4]->[2,4]。状态对应Listfromhead2
  5. cur->next=head2->next,将cur链接向head2的下一个元素,即被反转区的第一个元素,如此时[2,4]的2,注意此时原链表并未改变,状态对应Listfromhead3
  6. head2->next=cur;,此时才将cur的元素插入到head2后面,亦即被改变区的首位,如[2,4]->[3,2,4]。状态对应Listfromhead4
  7. cur=prev->next,将当前指针移向改变后区间的下一位,如[3,2,4]由2->4,接下来将4的节点插到head2的后面,也就是被反转区的首位。
  8. 重复4~6,直到i=n
发布了18 篇原创文章 · 获赞 0 · 访问量 1799

猜你喜欢

转载自blog.csdn.net/g534441921/article/details/104150453