Leetcode 61. 旋转链表

题目描述
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
在这里插入图片描述
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]

C++
会超时的思路

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    /*
    就是连续K次右移一个
    每次右移一个的时候,其实就是重新尾链接到头部,然后找到合适的位置断开,从而更改了链表头、 这个过程如果每次右移都需要找链表尾,就很耗时,会超时
    */
public:

    
    ListNode* rotateRight(ListNode* head, int k) {
        if(!head)  return head;
        //执行K次右移1
        while(k){
             head=right_one(head);
             k--;
        }
           
        return head;
    }
    //执行一次右移的操作: 新head=原tail; 新tail=原tail_pre 
    ListNode* right_one(ListNode* head){
            //遍历一次找链表尾
            ListNode* tail=head;
            ListNode* tail_pre=head; //链表的倒数第二个指针
            while(tail->next!=nullptr)
                if(tail->next->next==nullptr)
                    tail_pre=tail;
                tail=tail->next;
                
            tail->next=head;  //成环
            head=tail; 
            tail_pre->next=nullptr;  //重新断开
            return head;
    }
};

那就只能空间换时间了,可是还是超时

测试用例:
[1,2,3]
2000000000

好卑鄙的测试用例…,但是看到这个测试用例,我突然想到应该用上数学知识


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    /*
    就是连续K次右移一个
    每次右移一个的时候,其实就是重新尾链接到头部,然后找到合适的位置断开。
    断开后新的head为原来的tail,新的tail为原tail的前驱。为了找到每个tail的前驱,实行空间换时间。设置一个字典{“node”:“node的前驱”},就可以只执行一次找尾指针的操作了.
    */
public:

    ListNode * tail_pre;
    ListNode * tail;
    unordered_map<ListNode*,ListNode*>  pre_map;
    ListNode* rotateRight(ListNode* head, int k) {
        if(!head)  return head;
         //遍历一次找链表尾
         if(!head->next) return head;
         ListNode * pre=head;
         tail= head->next;
         
        while(pre->next!=nullptr){
            pre_map[tail]=pre;
            pre=tail;
            if(tail->next!=nullptr)
                tail=tail->next;
        }
        pre_map[head]=tail;
        //执行K次右移1
        while(k){
             head=right_one(head);
             k--;
        }
           
        return head;
    }
    //执行一次右移的操作: 新head=原tail; 新tail=原tail的前驱 
    ListNode* right_one(ListNode* head){
           
            tail->next=head;  //成环
            head=tail; 
            tail=pre_map[tail];
            tail->next=nullptr;  //重新断开
            return head;
    }
};

时间上100%
空间上5%
emmmm…真的是空间换时间了


class Solution {
    /*
   注意K>链表长的时候会存在大量浪费
    */
public:

    ListNode * tail_pre;
    ListNode * tail;
    unordered_map<ListNode*,ListNode*>  pre_map;
    int count=0; //链表长度
    ListNode* rotateRight(ListNode* head, int k) {
        if(!head)  return head;
         
         if(!head->next) return head;
         //先计算是链表的第几个元素要做表头

         ListNode * pre=head;
         tail= head->next;
         //遍历一次找链表尾
         count=1;
        while(pre->next!=nullptr){
            pre_map[tail]=pre;
            pre=tail;
            if(tail->next!=nullptr)
                tail=tail->next;
            count++;
        }
        //K
        pre_map[head]=tail;
        //K<count ,就还执行K次
        //执行K次右移1
        //K==count,返回原来的head就行
        
        //K>count的时候们就可以缩减K
        if(k==count){
            return head;
        }
        else if(k>count){
            k=k%count;
        }
         while(k){
             head=right_one(head);
             k--;
        }
       

           
        return head;
    }
    //执行一次右移的操作: 新head=原tail; 新tail=原tail的前驱 
    ListNode* right_one(ListNode* head){       
            tail->next=head;  //成环
            head=tail; 
            tail=pre_map[tail];
            tail->next=nullptr;  //重新断开
           
            return head;
    }
};

我再优化空间试试…

 
class Solution {
    /*
   继续优化。不再使用字典了
    */
public:

    ListNode * tail;
    int count=0; //链表长度
    ListNode* rotateRight(ListNode* head, int k) {
        if(!head)  return head;
         if(!head->next) return head;
         ListNode* cur=head;
         while(cur->next){
             count++;
             cur=cur->next;
         }
         tail=cur;
         count++; 
         //不用旋转的情况
         if((k%count)==0)
                return head; 
        //需要旋转的情况
        k=k%count;  //旋转k次后,head为原链表的倒数第K个节点
            //找原链表的倒数第K个节点,也就是整数第count-K+1个节点
        //先找到新头节点的前一个节点
        ListNode * pre=head;
        for(int i=2;i<=count-k;i++)
        {   
            pre=pre->next;
        }
        tail->next=head; //成环
        head=pre->next;    //新的头
        pre->next=nullptr; //新的尾指针
        return head;
    }
       
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值