RotateList [source code]

public class RotateList {
static
/******************************************************************************/
class Solution {
    public ListNode rotateRight(ListNode head, int _k) {
        if (head == null || head.next == null || _k == 0)
            return head;
        ListNode dummy = new ListNode (0);
        dummy.next = head;
        ListNode slow = dummy, fast = dummy;
        int k = _k;
        while (k > 0) {
            if ((fast = fast.next) == null) {
                return rotateRight (head, _k % (_k - k));
            }
            k--;
        }
        while (fast.next != null) {
            slow = slow.next;
            fast = fast.next;
        }
        ListNode res = slow.next;
        slow.next = null;
        fast.next = dummy.next;
        dummy.next = null;
        return res;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        RotateList.Solution tester = new RotateList.Solution();
        int[][] inputs = {
            {1,2,3,4,5}, {2}, {4,5,1,2,3},
            {1,2}, {3}, {2,1},
            {}, {1}, {},
        };
        for (int i = 0; i < inputs.length / 3; i++) {
            ListNode head = ListNode.buildListNode (inputs[3 * i]);
            ListNode ans = ListNode.buildListNode (inputs[3 * i + 2]);
            int k = inputs[3 * i + 1][0];
            System.out.println (Printer.separator ());
            String input_str = ListNode.serialize (head), ans_str = ListNode.serialize (ans);
            String output_str = ListNode.serialize (tester.rotateRight (head, k));
            System.out.printf ("%s and %d -> %s, expected: %s\n", 
                input_str, k, Printer.wrap (output_str, output_str.equals (ans_str) ? 92 : 91), ans_str
            );
        }
    }
}

list的题目, 那么inverse和快慢指针是很常见的小技巧, 脑子里有一个印象, 不知道这题能不能用到;

另外, 熟悉一个表达方式:

rotate the list to the right by k places

意思是右边半段的长度是k;

稍微想了一下, 感觉这题其实就是一个等间隔快慢指针的思路, 前面被坑过两次, 这次不会被坑了; 这种题目因为实际上N是未知的(规定只能1pass), 所以我们不知道N, 只知道K;

另外, dummy head, pre-leaf termination, 这些都是LinkedList题目里面很常见的小技巧了;

感觉写的主逻辑是没有问题的, 但是被test2给break的很烦人, 好像K超过list长度的时候, 必须得手动找到N然后取模; 很不想这么做, 因为这样就不是1pass了; 后来想了一个折中的办法: 判断出来K超界的时候, 再去重新调用一个取模之后的invocation.

后来发现这个办法其实应该是最优的办法了, 因为实际上, 当你发现你超界的时候, 你就已经知道N了, 所以实际上根本不需要专门多走一个pass再来找N;

最后的速度是17ms (31%), 还可以;

linkedlist: input null

好像LinkedList的题目里面, input是Null的Corner Case特别多, 不知道是为什么, 是因为是自定义结构的关系吗? 反正以后碰到这种题目长一个心眼;


没有editorial;


@dong.wang.1694 said in My clean C++ code, quite standard (find tail and reconnect the list):

There is no trick for this problem. Some people used slow/fast pointers to find the tail node but I don't see the benefit (in the sense that it doesn't reduce the pointer move op) to do so. So I just used one loop to find the length first.

class Solution {  
public:  
    ListNode* rotateRight(ListNode* head, int k) {  
        if(!head) return head;  

        int len=1; // number of nodes  
        ListNode *newH, *tail;  
        newH=tail=head;  

        while(tail->next)  // get the number of nodes in the list  
        {  
            tail = tail->next;  
            len++;  
        }  
        tail->next = head; // circle the link  

        if(k %= len)   
        {  
            for(auto i=0; i<len-k; i++) tail = tail->next; // the tail node is the (len-k)-th node (1st node is head)  
        }  
        newH = tail->next;   
        tail->next = NULL;  
        return newH;  
    }  
};

他这个观点是错误的, 我认为我的算法average肯定比他的更快;

@fastcode said in My clean C++ code, quite standard (find tail and reconnect the list):

This is my solution. The difference is, when k <= lens, NO need to traverse the lists twice! Only once!
The time consuming is 8ms.

class Solution {  
public:  
    ListNode* rotateRight(ListNode* head, int k) {  
        if(!k || !head || !head->next)  
            return head;  
        ListNode *fast = head;  
        int lens = 1;  
        while(k--)  
        {  
            if(fast->next)  
            {  
                fast = fast->next;  
                lens ++;  
            }  
            else  
            {  
                fast = head;  
                k %= lens;  
            }  
        }  
        if(fast == head)  
            return head;  
        ListNode *slow = head;  
        while(fast->next)  
        {  
            fast = fast->next;  
            slow = slow->next;  
        }  
        ListNode *newhead = slow->next;  
        slow->next = NULL;  
        fast->next = head;  
        return newhead;  
    }  
};

这个算是开窍的; 他处理的思路跟我实际上是类似的;


当K超界的时候, 官方给出的解释:

@1337c0d3r said in What to do when k is greater than size of list ?:

Let's start with an example.

Given [0,1,2], rotate 1 steps to the right -> [2,0,1].

Given [0,1,2], rotate 2 steps to the right -> [1,2,0].

Given [0,1,2], rotate 3 steps to the right -> [0,1,2].

Given [0,1,2], rotate 4 steps to the right -> [2,0,1].

So, no matter how big K, the number of steps is, the result is always the same as rotating K % n steps to the right.

@wangdingqiao said in What to do when k is greater than size of list ?:

@introom rotate could be better explained as "shift to right".

所以这个modN并不是一个很trivial的东西, 而是实际上你可以自己证明的; 这里也是熟悉一下rotate的定义;


@mo10 said in Clean Java Solution with Brief Explanation:

The basic idea is to link the tail of the list with the head, make it a cycle. Then count to the rotate point and cut it.

    if (head == null)  
            return head;  

        ListNode copyHead = head;  

        int len = 1;  
        while (copyHead.next != null) {  
            copyHead = copyHead.next;  
            len++;  
        }  

        copyHead.next = head;  

        for (int i = len - k % len; i > 1; i--)  
            head = head.next;  

        copyHead = head.next;  
        head.next = null;  

        return copyHead;  
    }

好像都是这个思路; 说起来很好听, cycle啊, 首尾相连啊, 其实本质还是就是几个关键位置的指针操作, 知道怎么做就行了, 用一个具体的例子来帮助开发;


discussion基本就都大同小异了, 好像很少很少人意识到eager calculate length是有害处的;

submission最优解, 其实基本就是波动内快一点;

class Solution {  
    public ListNode rotateRight(ListNode head, int k) {  
        if (head==null||head.next==null) return head;  
        ListNode dummy=new ListNode(0);  
        dummy.next=head;  
        ListNode fast=dummy,slow=dummy;  

        int i;  
        for (i=0;fast.next!=null;i++)//Get the total length   
            fast=fast.next;  

        for (int j=i-k%i;j>0;j--) //Get the i-n%i th node  
            slow=slow.next;  

        fast.next=dummy.next; //Do the rotation  
        dummy.next=slow.next;  
        slow.next=null;  

        return dummy.next;  
    }  
}

还是一开始就算length的方法;


Problem Description

Given a list, rotate the list to the right by k places, where k is non-negative.

Example:

Given 1->2->3->4->5->NULL and k = 2,  

return 4->5->1->2->3->NULL.

Difficulty:Medium
Total Accepted:129.9K
Total Submissions:532K
Contributor:LeetCode
Related Topics
linked listtwo pointers
Similar Questions
Rotate ArraySplit Linked List in Parts

results matching ""

    No results matching ""