前言:
“旋转链表”的题目是力扣题库上的第61题。我是使用Python3编写的解法,性能算不上好,在此仅仅只是阐述一下解法编程思想。仅供参考~
解法上可能会跟别人相同,所以要是看不懂下面的阐述的话可以去力扣对应的题目上查看其他人的解题思路~
问题描述:
题目的要求是:给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k
个位置。
LeetCode官方给的示例如下:
示例1:
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
示例2:
输入:head = [0,1,2], k = 4
输出:[2,0,1]
提示:
- 链表中节点的数目在范围
[0, 500]
内 -100 <= Node.val <= 100
0 <= k <= 2 * 109
解题思路:
首先,不要觉得题目叫旋转链表就想着要一次一次的旋转整个链表。
其次,旋转链表背后的含义是:每次旋转一次链表,就代表着处于链表的最后一个节点会被放到链表的第一个位置,以此往复,直至达到循环次数为止。简单点说就是将链表中后面的节点放到前面来。这样说可能会有点抽象,举个简单的例子,像示例1,它是需要将链表向右旋转2次,实际上就是将链表的后两个元素移动到链表的前面来。
然后,提示中给出k的取值范围是跟链表的长度没有什么关联的,就是说k的取值可以大于链表的长度。此时,我们需要知道一点,就是当k等于链表的长度时,旋转k次还是跟原来的链表是一样的。这可以让我们不用再老老实实的旋转k次链表,而是旋转(k除以链表长度的余数)次。像示例2,它是需要将链表向右旋转4次,而链表的节点数才三个,而我们可以不用旋转4次,而是旋转次就能达到旋转4次的效果。
最后,这里使用的是递归的方法实现的。
相关代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
# 递归方式旋转链表
def getAns(head,argList,k):
# 判断当前节点是否为空
if head is not None:
# 统计节点数
argList[0]+=1
# 标记当前在链表中的位置
index=argList[0]
# 判断当前节点是否为尾节点
if head.next is None:
# 获取真实需要右移的位置数
argList[1]=k%argList[0]
else:
# 递归调用
getAns(head.next,argList,k)
if argList[0]-index==argList[1]:
# 判断当前节点是否为需要移动的节点的前面一个节点
# 将当前节点后面需要放到链表前面的所有节点赋值给argList[2]
argList[2]=head.next
# 断开当前节点与下一节点的连接
head.next=None
elif argList[0]-index==0:
# 判断当前节点是否为最后一个节点
argList[3]=head
if index==1 and argList[1]>0:
# 判断当前节点是否为头结点,并且需要旋转(移动)的次数大于0
# 将需要旋转(移动)的最后一个节点的下一个节点指向当前节点
argList[3].next=head
elif argList[1]==0 and index==1:
# 判断当前节点是否为头结点,并且不需要旋转(移动)
argList[2]=head
if head is None:
# 链表为空返回None
return None
elif k==0:
# 旋转次数为0,直接返回链表
return head
else:
# argList:
# 下标 描述
# 0 代表链表长度
# 1 代表真实需要右移的位置数
# 2 返回的结果
# 3 代表需要旋转(移动)的尾节点
argList=[0,0,None,None]
getAns(head,argList,k)
return argList[2]
运行结果: