2020-8-04 每日刷题札记–反转链表Ⅱ

2020-8-04 反转链表Ⅱ

在这里插入图片描述
今天比较晚,只写了一种方法–头插法,对于[m,n],我们要做的就是,把m后面的数一个一个的放到m的前面(插到m位置,原本的m自动后移了)
第一次让m+1插到m位置
第二次让m+2插到m位置(注意这里所说的是位置,而非数据,m位置其实是前一次插过来的的m+1)
第三次让m+3插到m位置
以此类推…直到n插入m位置(此时原来的m已经到n位置了)
每一次迭代都插到m位置,经过n-m次迭代,就完成了调换,也就是头插法的本意啦!
举例说明,形象生动
1->2->3->4->5
1->3->2->4->5
1->4->3->2->5
转换完成!
调换过程中的指针变换我们在代码中解释

①自己写的方法,有点累赘~,记下来作对比吧

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) 
    {
    
    
    	//这一步不要也可以,个人喜好
        if(m == n || !head)
        {
    
    
            return head;
        }
        //上述所讲的头插法至少有3个节点,这里对只有2个节点的调换的情况单独讨论
        if(m==1&&n==2&&!head->next->next)
        {
    
    
            head->next->next = head;
            ListNode* temp = head->next;
            head->next = NULL;
            return temp;
        }
        //设置一个虚拟节点
        struct ListNode dummy;
        dummy.next = head;
        //pre一开始在-1的位置
        ListNode* pre = &dummy;
        //pre来到m-1的位置
        for(int i=1;i < m;i++)
        {
    
    
            pre = pre->next;
        }
        //cur在m的位置
        ListNode* cur = pre->next;
        //开始扫描
        for(int j = m;j < n; j++)
        {
    
    
        	//m+1插到m位置(交换他们的后驱指针哦!)
        	//可以看到cur从原本的m现在后移到了m+1的位置
        	//每一次迭代cur都是指向2,但是它都会在链表上后移一个位置
        	//而pre是一直没有动的,一直都在m-1的位置,它要指向插过来的数据
        	//这样每一次迭代都会将cur与后一位进行链表意义上的位置交换直到完成
            ListNode* temp=cur->next;
            cur->next = temp->next;
            temp->next = pre->next;
            pre->next = temp;
        }
        return dummy.next;
    }
};

同样思路简洁代码(我太菜了)

class Solution {
    
    
public:
    //思路:head表示需要反转的头节点,pre表示需要反转头节点的前驱节点
    //我们需要反转n-m次,我们将head的next节点移动到需要反转链表部分的首部,需要反转链表部分剩余节点依旧保持相对顺序即可
    //比如1->2->3->4->5,m=1,n=5
    //第一次反转:1(head) 2(next) 3 4 5 反转为 2 1 3 4 5
    //第二次反转:2 1(head) 3(next) 4 5 反转为 3 2 1 4 5
    //第三次发转:3 2 1(head) 4(next) 5 反转为 4 3 2 1 5
    //第四次反转:4 3 2 1(head) 5(next) 反转为 5 4 3 2 1
    ListNode* reverseBetween(ListNode* head, int m, int n) {
    
    
        ListNode *dummy=new ListNode(-1);
        dummy->next=head;
        ListNode *pre=dummy;
        for(int i=1;i<m;++i)pre=pre->next;
        head=pre->next;
        for(int i=m;i<n;++i){
    
    
            ListNode *nxt=head->next;
            //head节点连接nxt节点之后链表部分,也就是向后移动一位
            head->next=nxt->next;
            //nxt节点移动到需要反转链表部分的首部
            nxt->next=pre->next;
            pre->next=nxt;//pre继续为需要反转头节点的前驱节点
        }
        return dummy->next;
    }
};

直接翻转法,借鉴我们昨天解决的反转链表Ⅰ,每一次迭代都直接改变指针,1->2直接改为1<-2,最后对头部和尾部的指针进行操作(m接n+1,m-1接n),从而形成局部翻转

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    ListNode* reverseBetween(ListNode* head, int m, int n) {
    
      
        ListNode *dummy = new ListNode(-1);
        dummy->next = head;

        // 第m-1个节点
        ListNode *pre=dummy;
        for(int i=1; i<m; i++){
    
    
            pre = pre->next;
        }

        // 第m个节点
        ListNode *t, *cur=pre->next, *mNode=pre->next;
        // 头插法
        for(int i=m; i<=n; i++){
    
    
            t = cur->next;
            cur->next = pre->next;
            pre->next = cur;
            cur = t;
        }
        // 第m个节点指向第n+1个节点
        mNode->next = cur;
        
        return dummy->next;
    }
};

猜你喜欢

转载自blog.csdn.net/weixin_45336082/article/details/107804108