C++力扣刷题——2.链表篇

力扣刷题指南

(若有侵权会及时删除,请联系告知!)

第一题(知识点:链表的旋转和反转)

24.两两交换链表中的节点

题目描述

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例

在这里插入图片描述

示例1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例2:
输入:head = []
输出:[]

示例3:
输入:head = [1]
输出:[1]

思路分析

  • 知识点:链表翻转、递归——参考题解画手大鹏
  • 本题的递归和非递归解法其实原理类似,都是更新每两个节点的链表形态来完成整个链表的调整。

方法一:递归算法

递归需要注意以下三个条件,分别是:

  1. 返回值
  2. 调用单元做了什么
  3. 终止条件

在本题中:
1.返回值:交换完成的子链表的头结点,即 L 2 L2 L2
2.调用单元:设需要交换的两个点为 h e a d head head n e x t next next, h e a d head head 连接后面交换完成的子链表, n e x t next next 连接 h e a d head head ,完成交换。
3.终止条件: h e a d head head 为空指针或者 n e x t next next 为空指针,也就是当前无节点或者只有一个节点,无法进行交换。

示例代码

/**
 * 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 {
public:
    ListNode* swapPairs(ListNode* head) {
        if(head == nullptr || head->next == nullptr)
            return head;
        ListNode * p1 = head;
        ListNode * p2 = p1->next;
        ListNode * p3 = p2->next;
        p1->next = swapPairs(p3);
        p2->next = p1;
        return p2;
    }
};

复杂度分析

  • 时间复杂度: O ( n ) , O(n), O(n)其中 n n n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度: O ( n ) , O(n), O(n)其中 n n n 是链表的节点数量。空间复杂度主要取决于递归调用的栈空间。

方法二:非递归算法,注意L0/L1/L2/L3的指针交换过程,分析同方法一

示例代码

/**
 * 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 {
public:
    ListNode* swapPairs(ListNode* head) {
       ListNode * dummy = new ListNode(-1);
       dummy->next = head;
       ListNode * p0 = dummy;
       ListNode * p1 = head;
       while(p1 && p1->next)
       {
           ListNode * p2 = p1 -> next;
           ListNode * p3 = p2 -> next;

           p0->next = p2;
           p2->next = p1;
           p1->next = p3;

           p0 = p1;
           p1 = p3;
       }
       return dummy->next;
    }
};

复杂度分析

  • 时间复杂度: O ( n ) , O(n), O(n)其中 n n n 是链表的节点数量。需要对每个节点进行更新指针的操作。
  • 空间复杂度: O ( 1 ) O(1) O(1)

第二题(知识点:链表的旋转和反转/快慢指针)

61.旋转链表

题目描述

给你一个链表的头节点 h e a d head head,旋转链表,将链表每个节点向右移动 k k k 个位置。

示例

在这里插入图片描述
在这里插入图片描述

示例代码

/**
 * 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 {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head == nullptr) return nullptr;
        ListNode *fast = head;
        ListNode *slow = head;
        int n = 0;
        //计算链表中节点个数
        while(fast != nullptr)
        {
            n++;
            fast = fast->next;
        }
        k = k % n;
        if(k == 0) return head; 
        fast = head;
        int ans = 0;
        //双指针--快指针先向前移动k步
        while(ans < k)
        {
            fast = fast->next;
            ans++;
        }
        //快慢指针同时向前移动,直到快指针指向节点的下一个节点为空指针
        while(fast->next)
        {
            fast = fast->next;
            slow = slow->next;
        }
        //开始调整位置
        ListNode * newHead = nullptr;
        newHead = slow->next;
        fast->next = head;
        slow->next = nullptr;
        return newHead;
    }
};

复杂度分析

  • 时间复杂度: O ( n ) , O(n), O(n)其中 n n n 是链表的节点数量。
  • 空间复杂度: O ( 1 ) O(1) O(1)

第三题(知识点:链表的旋转和反转)

206.反转链表

题目描述

给你单链表的头节点 h e a d head head ,请你反转链表,并返回反转后的链表。

示例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

示例代码一:迭代法

示例一: 1->2->3->4->5->null
翻转后: 5->4->3->2->1->null
我们需要存储节点cur以及它的前驱节点pre,同时在交换的过程中节点的next指针位置会发生改变
,因此交换之前需要存储其节点的下一个位置,代码如下
/**
 * 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 {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr) return nullptr;
        ListNode* pre =  nullptr;
        ListNode* cur = head;
        while(cur != nullptr)
        {
            ListNode * temp = cur -> next;
            cur -> next = pre;
            pre = cur;
            cur = temp;
        }
        return pre;
    }
};

复杂度分析

  • 时间复杂度: O ( n ) , O(n), O(n)其中 n n n 是链表的节点数量,需要遍历链表一次。
  • 空间复杂度: O ( 1 ) O(1) O(1)

示例代码二:递归法——参考官方题解评论区大佬NoColor96的代码

    /**
     * 以链表1->2->3->4->5举例
     * @param head
     * @return
     */
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            /*
                直到当前节点的下一个节点为空时返回当前节点
                由于5没有下一个节点了,所以此处返回节点5
             */
            return head;
        }
        //递归传入下一个节点,目的是为了到达最后一个节点
        ListNode newHead = reverseList(head.next);
                /*
            第一轮出栈,head为5,head.next为空,返回5
            第二轮出栈,head为4,head.next为5,执行head.next.next=head也就是5.next=4,
                      把当前节点的子节点的子节点指向当前节点
                      此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null
                      此时链表为1->2->3->4<-5
                      返回节点5
            第三轮出栈,head为3,head.next为4,执行head.next.next=head也就是4.next=3,
                      此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null
                      此时链表为1->2->3<-4<-5
                      返回节点5
            第四轮出栈,head为2,head.next为3,执行head.next.next=head也就是3.next=2,
                      此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null
                      此时链表为1->2<-3<-4<-5
                      返回节点5
            第五轮出栈,head为1,head.next为2,执行head.next.next=head也就是2.next=1,
                      此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null
                      此时链表为1<-2<-3<-4<-5
                      返回节点5
            出栈完成,最终头节点5->4->3->2->1
         */
        head.next.next = head;
        head.next = null;
        return newHead;
    }

复杂度分析

  • 时间复杂度: O ( n ) , O(n), O(n)其中 n n n 是链表的节点数量。
  • 空间复杂度: O ( n ) , O(n), O(n), n是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为n层
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

highlight2333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值