原题截图:
这个题的思路其实挺简单的,这个题与力扣的189题的轮转数组非常像,思路差不多,只是一个是数组,一个是链表;
这个题的思路:
(1)先反转整条链表;
(2)找到k的位置,以k为中心把链表分为前后两个部分,先将这两个部分断开,方便后续的操作。
(3)分别反转这前后两个部分的链表,再进行连接即可
注意:这个的题的k的值可以大于链表的长度,这个一定要注意。
代码:(核心代码)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct ListNode ListNode;
struct ListNode* rotateRight(struct ListNode* head, int k){
if(head == NULL || head->next == NULL)
return head;
ListNode *cur = head;
int len = 0;
//计算链表的长度
while(cur)
{
len++;
cur = cur->next;
}
//如果k在链表的开头,直接返回链表即可
k = k % len;
if(k==0) return head;
//思路:1.先反转链表
// 2.把链表分为2个部分,分别反转前半部分和后半部分再连接这两半部分即可
//反转整条链表
cur = head;
struct ListNode* n1 = NULL,*n2 = head,*n3 = head->next;
while(n2)
{
//反转
n2->next = n1;
//迭代
n1 = n2;
n2 = n3;
if(n3)
{
n3 = n3->next;
}
}
//反转后的n1为新的头结点
//反转前半部分
int m = k;
ListNode *pp = n1;//记录后半部分的链表的头结点
//迭代
ListNode *pre = NULL,*mid = n1;
cur = n1->next;
//找到后半部分的链表的头结点
while(m--)
{
pp = pp->next;
}
//反转前半部分
while(k--)
{
//反转
if(pre == NULL)
{
pre = pp;
}
mid->next = pre;
pre = mid;
mid = cur;
if(cur) cur = cur->next;
}
//找到反转后的前半部分的尾结点
cur = pre;
while(cur->next != pp && cur != pp)
{
cur = cur->next;
}
pp = cur->next;//记录后半部分的头结点
cur->next = NULL; //先让前半部分的尾结点指向空,后面再进行连接
//反转后半部分的链表
ListNode *pre2 = NULL,*mid2 = pp,*cur2 = pp->next;
while(mid2)
{
//反转链表(迭代)
mid2->next = pre2;
pre2 = mid2;
mid2 = cur2;
if(cur2) cur2 = cur2->next;
}
//连接前后半部分的链表
cur->next = pre2;
return pre;
}