1、描述

给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数

例1:输入:1->2->3->4->5->null,k = 2

          输出:4->5->1->2->3->null

           解释:向右旋转1步:5->1->2->3->4->null

                       向右旋转2步:4->5->1->2->3->null

例1:输入:0->1->2->null,k = 4

          输出:2->0->1->null

           解释:向右旋转1步:2->0->1->null

                       向右旋转2步:1->2->0->null

                       向右旋转3步:0->1->2->null

                       向右旋转4步:2->0->1->null

 

2、算法

解法一

思想:链表中的点已经相连,一次旋转操作意味着:

         1)先将链表闭合成环

         2)找到相应的位置断开这个环,确定新的链表头和链表尾

步骤:

1)找到旧的尾部并将其与链表头相连 old_tail.next = head,整个链表闭合成环,同时计算出链表的长度 n。

2) 找到新的尾部,第 (n - k % n - 1) 个节点 ,新的链表头是第 (n - k % n) 个节点。

3) 断开环 new_tail.next = None,并返回新的链表头 new_head。

时间复杂度:O(n)

func rotateRight(_ head: ListNode?, _ k: Int) -> ListNode? {
     
        if head==nil {
            return nil
        }
        if  head?.next == nil {
            return head
        }
        
        //将链表闭合成环
        var old_tail : ListNode? = head
        //代表链表的长度
        var n : Int = 1
        while old_tail?.next != nil {
            old_tail = old_tail?.next
            n += 1
        }
        old_tail?.next = head
        
        //找到新的尾部:(n - k % n - 1)
        //新的头部:(n - k % n)
        var new_tail : ListNode? = head
        var i = 0
        while i<n-k%n-1{
            new_tail = new_tail?.next
            i += 1
        }
        let new_head : ListNode? = new_tail?.next
        
        //断开环
        new_tail?.next = nil
        
        return new_head
    }
    

解法二:

思想:利用双指针
步骤:
1)求链表长度,然后用k膜一下长度,这样才是真正的右移k位
2)双指针,快指针先走k步,然后再和慢指针一起一次走一步,当快指针到结尾的时候,慢指针到倒数第k个节点
3)这个时候指来指去就行了

func rotateRight(_ head: ListNode?, _ k: Int) -> ListNode? {
      
        if head==nil {
            return nil
        }
        if  head?.next == nil {
            return head
        }
        var length = 0
        var cur : ListNode? = head
        while cur != nil {
            cur = cur?.next
            length += 1
        }
        cur = head
        var k = k % length
        
        var lastK : ListNode? = head
        //快指针先走k步
        for _ in 0..<k {
            cur = cur?.next
        }
        //在和慢指针一起一次走一步
        while cur?.next != nil {
            cur = cur?.next
            lastK = lastK?.next
        }
        
        cur?.next = head
        var res = lastK?.next
        lastK?.next = nil
        
        return res
        
    }

解法三:

 思想:右移k个位置,本质就是将前 len - k % len 个节点放到最后去         
分为几个核心步骤:
1) 求出链表的长度,以及最后的一个节点
2)截取前 len - k % len 个节点
3)将两段链表进行拼接
 算法解释:利用dummyHead减少算法理解成本

func rotateRight(_ head: ListNode?, _ k: Int) -> ListNode? {
       
        if head==nil {
            return nil
        }
        if  head?.next == nil {
            return head
        }
        
        let dummyHead : ListNode? = ListNode(-1)
        dummyHead?.next = head
        var p = dummyHead
        
        //整个链表的长度
        var len = 0
        while p?.next != nil {
            p = p?.next
            len += 1
        }
        
        //得到最后一个节点
        var last : ListNode? = p
        
        //截取 前 len-k%len 个节点
        var k = k % len
        k = len - k
        p = dummyHead
        while k > 0 {
            p = p?.next
            k -= 1
        }
        //将两段链表进行拼接
        last?.next = dummyHead?.next
        dummyHead?.next = p?.next
        p?.next = nil
        
        return dummyHead?.next
        
        
    }