您的位置:首页 > 其它

LeetCode(60)RotateList

2014-01-25 23:28 295 查看
题目如下:

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;
    }
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: