61.Rotate-List.md 6.0 KB
Newer Older
daydaytech's avatar
daydaytech 已提交
1
## 题目地址(61. 旋转链表)
daydaytech's avatar
daydaytech 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

https://leetcode-cn.com/problems/rotate-list/

## 题目描述

```
给定一个链表,旋转链表,将链表每个节点向右移动 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
示例 2:

输入: 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
```

## 快慢指针法
L
lucifer 已提交
29

daydaytech's avatar
daydaytech 已提交
30
### 前置知识
L
lucifer 已提交
31 32

- 求单链表的倒数第 N 个节点
daydaytech's avatar
daydaytech 已提交
33

daydaytech's avatar
daydaytech 已提交
34
### 思路一
L
lucifer 已提交
35

daydaytech's avatar
daydaytech 已提交
36 37
1. 采用快慢指
2. 快指针与慢指针都以每步一个节点的速度向后遍历
L
lucifer 已提交
38 39
3. 快指针比慢指针先走 N 步
4. 当快指针到达终点时,慢指针正好是倒数第 N 个节点
daydaytech's avatar
daydaytech 已提交
40

daydaytech's avatar
daydaytech 已提交
41 42 43 44
### 思路一代码

- 伪代码

daydaytech's avatar
daydaytech 已提交
45
```js
L
lucifer 已提交
46 47 48 49 50 51 52
快指针 = head;
慢指针 = head;
while (快指针.next) {
  if (N-- <= 0) {
    慢指针 = 慢指针.next;
  }
  快指针 = 快指针.next;
daydaytech's avatar
daydaytech 已提交
53
}
daydaytech's avatar
daydaytech 已提交
54 55
```

daydaytech's avatar
daydaytech 已提交
56 57 58 59
- 语言支持: JS

JS Code:

daydaytech's avatar
daydaytech 已提交
60
```js
L
lucifer 已提交
61 62 63 64 65 66
let slow = (fast = head);
while (fast.next) {
  if (k-- <= 0) {
    slow = slow.next;
  }
  fast = fast.next;
daydaytech's avatar
daydaytech 已提交
67
}
daydaytech's avatar
daydaytech 已提交
68 69
```

daydaytech's avatar
daydaytech 已提交
70
### 思路二
daydaytech's avatar
daydaytech 已提交
71

L
lucifer 已提交
72 73 74 75 76 77 78
1. 获取单链表的倒数第 N + 1 与倒数第 N 个节点
2. 将倒数第 N + 1 个节点的 next 指向 null
3. 将链表尾节点的 next 指向 head
4. 返回倒数第 N 个节点

例如链表 A -> B -> C -> D -> E 右移 2 位,依照上述步骤为:

daydaytech's avatar
daydaytech 已提交
79 80 81
1. 获取节点 C 与 D
2. A -> B -> C -> null, D -> E
3. D -> E -> A -> B -> C -> nul
L
lucifer 已提交
82
4. 返回节点 D
daydaytech's avatar
daydaytech 已提交
83

L
lucifer 已提交
84 85 86 87
> 注意:假如链表节点长度为 len,  
>  则右移 K 位与右移动 k % len 的效果是一样的  
>  就像是长度为 1000 米的环形跑道,  
>  你跑 1100 米与跑 100 米到达的是同一个地点
daydaytech's avatar
daydaytech 已提交
88

daydaytech's avatar
daydaytech 已提交
89
### 思路二代码
daydaytech's avatar
daydaytech 已提交
90

daydaytech's avatar
daydaytech 已提交
91
- 伪代码
daydaytech's avatar
daydaytech 已提交
92 93 94 95 96 97 98 99 100 101

```js
  获取链表的长度
  k = k % 链表的长度
  获取倒数第k + 1,倒数第K个节点与链表尾节点
  倒数第k + 1个节点.next = null
  链表尾节点.next = head
  return 倒数第k个节点
```

L
lucifer 已提交
102
- 语言支持: JS, JAVA, Python, CPP, Go, PHP
daydaytech's avatar
daydaytech 已提交
103 104 105

JS Code:

daydaytech's avatar
daydaytech 已提交
106
```js
L
lucifer 已提交
107 108 109 110 111 112 113 114 115 116 117 118 119
var rotateRight = function (head, k) {
  if (!head || !head.next) return head;
  let count = 0,
    now = head;
  while (now) {
    now = now.next;
    count++;
  }
  k = k % count;
  let slow = (fast = head);
  while (fast.next) {
    if (k-- <= 0) {
      slow = slow.next;
daydaytech's avatar
daydaytech 已提交
120
    }
L
lucifer 已提交
121 122 123 124 125 126
    fast = fast.next;
  }
  fast.next = head;
  let res = slow.next;
  slow.next = null;
  return res;
daydaytech's avatar
daydaytech 已提交
127 128 129
};
```

daydaytech's avatar
daydaytech 已提交
130 131
JAVA Code:

daydaytech's avatar
daydaytech 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
```java
class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head == null || head.next == null) return head;
        int count = 0;
        ListNode now = head;
        while(now != null){
            now = now.next;
            count++;
        }
        k = k % count;
        ListNode slow = head, fast = head;
        while(fast.next != null){
            if(k-- <= 0){
                slow = slow.next;
            }
            fast = fast.next;
        }
        fast.next = head;
        ListNode res = slow.next;
        slow.next = null;
        return res;
    }
}
```

daydaytech's avatar
daydaytech 已提交
158 159
Python Code:

daydaytech's avatar
daydaytech 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
```py
class Solution:
    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        # 双指针
        if head:
            p1 = head
            p2 = head
            count = 1
            i = 0
            while i < k:
                if p2.next:
                    count += 1
                    p2 = p2.next
                else:
                    k = k % count
                    i = -1
                    p2 = head
                i += 1
L
lucifer 已提交
178

daydaytech's avatar
daydaytech 已提交
179 180 181
            while p2.next:
                p1 = p1.next
                p2 = p2.next
L
lucifer 已提交
182

daydaytech's avatar
daydaytech 已提交
183 184 185 186 187 188 189 190 191
            if p1.next:
                tmp = p1.next
            else:
                return head
            p1.next = None
            p2.next = head
            return tmp
```

L
lucifer 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
CPP Code:

```cpp
class Solution {
    int getLength(ListNode *head) {
        int len = 0;
        for (; head; head = head->next, ++len);
        return len;
    }
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if (!head) return NULL;
        int len = getLength(head);
        k %= len;
        if (k == 0) return head;
        auto p = head, q = head;
        while (k--) q = q->next;
        while (q->next) {
            p = p->next;
            q = q->next;
        }
        auto h = p->next;
        q->next = head;
        p->next = NULL;
        return h;
    }
};
```

daydaytech's avatar
daydaytech 已提交
221
Go Code:
daydaytech's avatar
daydaytech 已提交
222

daydaytech's avatar
daydaytech 已提交
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
```go
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func rotateRight(head *ListNode, k int) *ListNode {
	if head == nil || head.Next == nil {
		return head
	}
	n := 0
	p := head
	for p != nil {
		n++
		p = p.Next
	}
	k = k % n
    // p 为快指针, q 为慢指针
	p = head
	q := head
    for p.Next!=nil {
        p = p.Next
        if k>0 {
            k--
        } else {
            q = q.Next
        }
    }
    // 更新指针
    p.Next = head
    head = q.Next
    q.Next = nil

	return head
}
```

PHP Code:
daydaytech's avatar
daydaytech 已提交
263

daydaytech's avatar
daydaytech 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
```php
/**
 * Definition for a singly-linked list.
 * class ListNode {
 *     public $val = 0;
 *     public $next = null;
 *     function __construct($val) { $this->val = $val; }
 * }
 */
class Solution
{

    /**
     * @param ListNode $head
     * @param Integer $k
     * @return ListNode
     */
    function rotateRight($head, $k)
    {
        if (!$head || !$head->next) return $head;

        $p = $head;
        $n = 0;
        while ($p) {
            $n++;
            $p = $p->next;
        }
        $k = $k % $n;
        $p = $q = $head; // $p 快指针; $q 慢指针
        while ($p->next) {
            $p = $p->next;
            if ($k > 0) $k--;
            else $q = $q->next;
        }
        $p->next = $head;
        $head = $q->next;
        $q->next = null;

        return $head;
    }
}
```

daydaytech's avatar
daydaytech 已提交
307
**复杂度分析**
daydaytech's avatar
daydaytech 已提交
308

L
lucifer 已提交
309 310
- 时间复杂度:节点最多只遍历两遍,时间复杂度为$O(N)$
- 空间复杂度:未使用额外的空间,空间复杂度$O(1)$