题目如下:
Given a list, rotate the list to the right by k places, where k is non-negative.
For example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.
分析如下:
(1)主干部分的代码是,找到右边的k个节点,把右边的k个节点整体移动到最左边来。left_mark代表左边部分的最后一个节点,right_mark代表右边部分的第一个节点。
(2)主干部分相关的edge cases and corner cases:
(2.1)注意到k可能比n还大,根据题意,rotate也是可以实现的。用len代表链表的长度,也就是链表的节点的总数。
(2.2)如果k==length,那就不用移动,实际上,如果k%length==0,都不用移动。
(2.3)如果k%length!=0,一定会发生移动,移动的个数为k%length。
(2.4)注意到单链表题目中判断head是否为NULL,就和树题目中判断root是否为NULL一样,基本是惯例。
(2.5)另外k<=0时,算是输入不合法,也要进行判断。
(3)比较有意思的地方是,为什么求链表的长度(节点个数)的这段代码是这样的?为什么起始状态和终止条件是这样的?
while(p!=NULL){
len++;
end_mark=p;
p=p->next;
}
因为
A B C D E NULL (起点为head,即起点为A)
1 2 3 4 5(第一次循环结束,len=1,第k次循环结束,len=k)
注意到第一次循环结束,len=1,那么第len次循环结束,len=length。为了使得len增长到len,循环必须进行len次,而while(..)中的p起始状态为p==head,所以终止条件必须为p走到最后一个节点E的下一个节点,也就是NULL节点。
(4) 为什么找寻左边部分的最后一个节点的代码是这样的?
while(i<len-k-1&&left_mark!=NULL){
left_mark=left_mark->next;
i++;
}
A B C D E NULL
1 2 3 4 5
假设k=2,那么左边部分将为 A B C,右边部分将为 D E,也就是 A(1) B(2) C(3) D(4) E(5),括号中的数字表示下标。假设下标从1开始,那么显然左边部分的最后一个节点的下标将是length-k=5-2=3,现在需要从起始节点走到length-k节点,也就是从A(1)走到A(3),注意到起始节点处还没开始走已经在A(1)了,所以实际需要走的步数是 length-k-1,所以i实际上增加了length-k-1次。所以while语句这么写。我的代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *rotateRight(ListNode *head, int k) {
if(head==NULL||k<=0)
return head;
ListNode* p=head;
ListNode* left_mark=head;
ListNode* right_mark=head;
ListNode* end_mark=head;
int len=0;
while(p!=NULL){
len++;
end_mark=p;
p=p->next;
}
k=k%len;
if(k==0) //边界条件 bug1: 之前写成了if(len==l),另外没有考虑到可能k大于n。
return head;
int i=0;
while(i<len-k-1&&left_mark!=NULL){
left_mark=left_mark->next;
i++;
}
if(left_mark!=NULL)
right_mark=left_mark->next;
end_mark->next=head;
head=right_mark;
left_mark->next=NULL;
return head;
}
};
update: 2014-12-30
题目很直白,所以下面代码的思路和上面代码其实是一样的,只是简洁了一点点。注意写代码之前要考虑corner case。
//28ms
/*
*corner case 1: 可能K大于length
*corner case 2: 可能head为NULL
*/
class Solution {
public:
ListNode *rotateRight(ListNode *head, int k) {
if (head == NULL) return head;
int length = 0;
ListNode* previous = head;
ListNode* current = head;
ListNode* tail = head;
while (current != NULL) {
length++;
tail = current;
current = current->next;
}
k = k % length;
if (k == 0 ) return head;
current = head;
k = length - k;
while (k > 0) {
previous = current;
current = current->next;
k--;
}
tail->next = head;
previous->next = NULL;
return current;
}
};