leetcode 61题这道题是一道中等难度题目,但是在很多公司中都有考到这道题,因此在这里尝试着借助图的方法理解一下思考过程;
方法一,寻找切分点,通过设置不同的K值,寻找规律,当k大于链表长度的时候,每次操作1个链表长度的时候相当于保持不变,所以我们可以在链表长度内考虑这个问题,因为其他的长度都可以认为有周期性。不难发现,假设链表长度L,则切分点为L - k%L ,
在切分点处,让前半部分的最后部分指向null,作为链表尾,后半部分的尾部指向前半部分部分的头,构成新的链表,其中过程利用快慢指针的方法,分别找到第一部分和第二部分的结尾和开头,即new_head = slowListNode.next;这一语句
//解法2 不使用循环链表
class Solution {
public ListNode rotateRight(ListNode head, int k) {
ListNode old_head = head; //用于计算链表长度
ListNode new_head = head; //用于重新计算头节点
if(head == null || k == 0)
return head;
int lengthOfLink = 1;
while(old_head.next != null){
lengthOfLink++;
old_head = old_head.next;
}
int splitOfLink = lengthOfLink - k%lengthOfLink;
if(k%lengthOfLink == 0)
return head;
ListNode fastListNode = head; // 快指针先找到对应的位置
ListNode slowListNode = head; //慢指针最终指向队尾
int cnt = 1;
while(fastListNode.next != null){
fastListNode = fastListNode.next;
if(cnt < splitOfLink){
slowListNode = slowListNode.next;
}
cnt++;
}
new_head = slowListNode.next;
slowListNode.next = null;
fastListNode.next = head;
return new_head;
}
}
方法二,用循环链表,这个时候操作更简单,先使得链表为循环链表,找到队头和队尾相邻,然后在循环k之后断开,tail部分指向队尾,新的head作为队头即可
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if(head == null || k == 0) //这一步很关键,用于处理边缘情况
return head;
ListNode old_head = head;
ListNode tail = null;
int lengthOfLink = 1;
while(old_head.next != null){
old_head = old_head.next;
lengthOfLink++;
}
tail = old_head;
tail.next = head;
old_head = head; //构建循环链表
int splitOfLink = lengthOfLink - k%lengthOfLink;
for(int i = 0 ;i<splitOfLink;i++){
old_head = old_head.next;
tail = tail.next;
}
tail.next = null;
return old_head;
}
}