反转链表问题全解析(一篇拿下)
0.理解下述代码
r = q->next;
q->next = p;
p = q;
q = r;
让2指向1,只需p指向1,q指向2(建议自己模拟一下上述代码)
1.反转链表(对照代码模拟0.样例就明白了)
题目链接:反转链表
递归版本
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
return reverse(pHead);
}
//翻转一段链表并返回头节点
ListNode* reverse(ListNode* head)
{
if(!head||!head->next)return head;
ListNode *t = head->next;
ListNode *h = reverse(head->next);
t->next = head;
head->next = nullptr;
return h;
}
};
迭代版本
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(!pHead)return pHead;
ListNode* p=NULL,*r,*q=pHead;
while(q!=NULL)
{
r = q->next;
q->next = p;
p = q;
q = r;
}
return p;
}
};
2.链表内指定区间反转(对照样例模拟一遍)
题目链接:链表内指定区间反转
版本一,将链表指定区间按照1.的方式翻转之后与其余链表拼接起来
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
ListNode* reverseBetween(ListNode* head, int m, int n) {
//添加一个头节点
ListNode *h = new ListNode(-1);
h->next = head;
int i = 0;
ListNode *u=h;
//u指向第m-1个节点
while(i<m-1)
{
i++;
u = u->next;
}
ListNode *p = u->next,*q = p->next,*r;
i++;i++;
//按照1.方式翻转一下
while(i<=n)
{
i++;
r = q->next;
q->next = p;
p = q;
q = r;
}
//此时p指向第n个节点,q指向第n+1个节点
u->next->next = q;
u->next = p;
return h->next;
}
};
版本二:类似头插法
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param m int整型
* @param n int整型
* @return ListNode类
*/
ListNode* reverseBetween(ListNode* head, int m, int n) {
//添加一个头节点
ListNode *h = new ListNode(-1);
h->next = head;
ListNode *pre = h;
//找到第m-1个节点
for(int i=0;i<m-1;++i)
{
pre = pre->next;
}
//开始反转第m个
ListNode *p = pre->next,*q = p->next;
for(int i=m;i<n;++i)
{
p->next = q->next;
q->next = pre->next;
pre->next = q;
//p不需要变化,始终指向子链表的尾节点
q = p->next;
}
return h->next;
}
};
3.链表中的节点每k个一组翻转
题目链接:链表中的节点每k个一组翻转
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
class Solution {
public:
/**
*
* @param head ListNode类
* @param k int整型
* @return ListNode类
*/
ListNode* reverseKGroup(ListNode* head, int k) {
// write code here
//求出长度
int len = get_len(head);
ListNode *res = new ListNode(-1),*now;
now = res;
for(int i=0;i<len/k;++i)
{
ListNode *p = nullptr,*q = new ListNode(-1),*r;
q = head;
//每k个按照第一题翻转
for(int j = 0;j<k;++j)
{
r = q->next;
q->next = p;
p = q;
q = r;
}
//拼接
now->next = p;
//更新head
head = q;
//now指向尾结点
while(now->next)now = now->next;
}
//最后不足k个不需要翻转
now->next = head;
return res->next;
}
int get_len(ListNode *h)
{
int res = 0;
while(h)
{
res++;
h = h->next;
}
return res;
}
};