LeetCode/反转链表搬砖操作(2、k、指定区间)

1. 反转指定区间链表

先记录反转区域的前驱节点
之后再将反转区域节点按头插法插到该前驱节点
最后再连接一下反转区域后面的节点

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode*pre= new ListNode();
        pre->next=head;//记录首指针,最后用于输出
        int count = right-left+1;//需要反转的长度
        if(count==1) return head;//不需要反转
        if(left==1) head=pre;//从首位反转,要定位到首位前一位
        else{
        while(--left>1){
            head = head->next;//定位到反转的头部前一个元素
        }}
        
        ListNode*reversehead= new ListNode();
        reversehead=head;//记录反转区域头部的前驱
        head=head->next;//进入反转区域
        reversehead->next=NULL;//断开链表

        ListNode*end= head;//记录反转区域首节点,也是结束时尾结点
        while(head!=NULL&&count!=0){
            ListNode*node = head;//更新要插入节点
            head=head->next;//该节点要准备插入,赶紧定位记录下一节点
            node->next=reversehead->next;//头插法插入前驱右半截
            reversehead->next=node;//并入到前驱后
            count--;
        }
        end->next=head;//串联两链表
        return pre->next;
    }
};

2. 两两交换链表中的节点(2个一组翻转链表)

两个一组同时更改链表结构,需要记录多个变量
也可以使用双重循环,两个一组进行头插法,只需两个变量

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* pre = new ListNode();//头结点用于返回值
        pre->next = head;
        ListNode*  curhead = head;
        ListNode* curpre =pre;
        ListNode*  nexthead;//提前记录下一轮的首节点
        ListNode* nextpre;//提前记录下一轮前驱      
        while(curpre->next&&curpre->next->next){//如果还需要交换
            ListNode* second = curhead->next;
            nexthead = second ->next;//下一次的首节点是第二个节点的后继
            nextpre = curhead;//下一次的前驱是当前首节点,因为等下会交换
            //改变指针
            curpre ->next = second;
            second ->next = curhead;
            nextpre->next = nexthead;
            //后移继续处理
            curhead = nexthead;
            curpre = nextpre;
        }
        return pre->next;
    }
};

3. k个一组翻转链表

只用记录当前前驱和下一次的前驱两个变量即可
采用头插法将每个节点插入到当前前驱
根据计数进行一次当前前驱变更

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode*pre= new ListNode();
        pre->next=head;//记录首指针,最后用于输出
        ListNode*curpre = pre;//记录当前区域前驱节点
        ListNode*curhead = pre;//(本可以不赋值,为了统一操作)
        int count;
        while(head!=NULL){//遍历所有节点
        //赋值放在前面,防止遍历完后被覆盖掉
            count = k;
            curpre= curhead;//上次尾结点作为新区域前驱节点
            curpre->next=NULL;//断开链表
            curhead= head;//记录反转区域首节点,也是结束时尾结点
            while(head!=NULL&&count!=0){//翻转k个节点
                ListNode*node = head;//更新要插入节点
                head=head->next;//该节点要准备插入,赶紧定位记录下一节点
                node->next=curpre->next;//头插法插入
                curpre->next=node;//并入到前驱后
                count--;
            }
        }
         //对未满k的再转回来(题目要求)
        if(count==0) return pre->next;
        
        head = curpre->next;
        curpre->next = NULL;
        while(head!=NULL){
            ListNode*node = head;//更新要插入节点
            head=head->next;//该节点要准备插入,赶紧定位记录下一节点
            node->next=curpre->next;//头插法插入前驱右半截
            curpre->next=node;//并入到前驱后
        }
        return pre->next;
    }
};

4. 旋转链表

将链表每个节点向右移动k个位置(纯搬砖题)

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        ListNode*pre = new ListNode();
        //这个程序一共设了头结点、尾结点、更新后首节点、更新尾结点这四个节点,用于记录和更改链表结构
        pre->next = head;
        int len=0;//记录链表长度
        ListNode*end;//记录尾节点
        while(head){
            end = head;
            head = head ->next;
            len++;
        }
        if(len==0) return 0;//极端情况
        k = k%len;//取一下余数,得到真实移动次数

        head = pre ->next;//重新开始
        if(k==0) return head;//极端情况
        int headindex = len - k;
        ListNode* tail;
        for(int i=0;i<headindex;i++){
            if(i==headindex-1) tail = head; //记录更新后尾结点
            head = head ->next;
        }
        //各节点连接,更改结构
        end ->next = pre->next;
        pre->next = head;
        tail ->next = nullptr;

        return pre->next;
    }
};
posted @ 2022-07-25 14:57  失控D大白兔  阅读(40)  评论(0编辑  收藏  举报