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;
}
};