力扣top100-链表类题易错点总结-c++实现(更新中)

tip1 来自“合并两个有序链表”

题目链接戳这里
在这里插入图片描述
在这里插入图片描述

  • 这道题注意的就是如果是要返回一个新链表的头结点,一定要新建一个头结点:
ListNode* prehead = new ListNode(-1); 
  • 之后再对prehead的next进行添加,而不是对传进来的参数节点(比如list1)进行遍历、或其他改变后,再直接返回参数节点(当list1遍历的时候指向了尾结点,这样就找不到开始的头结点了)!
  • 代码如下
/**
 * 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* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* prehead = new ListNode(-1); // 申请一片新的空间的办法
        ListNode* pre = prehead; // 暂时指向这片区域,然后之后只更改next
        while (list1 != nullptr && list2 != nullptr) {
            if (list1->val > list2->val) {
                pre->next = list2;
                list2 = list2->next;
            } else {
                pre->next = list1;
                list1 = list1->next;
            }
            pre = pre->next;
        }
        if (list1 != nullptr)
            pre->next = list1;
        else if (list2 != nullptr)
            pre->next = list2;
        return prehead->next;
    }
};

跟上上一道题的方法,如果是新建节点怎么做?

  • 用“双数相加”来说,题目链接:link

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

  • 必须用的方法是,不能自己猜想链表结构写别的代码:
//j%10的位置写新的val
//然后插入下一个点
ListNode* temp = new ListNode(j % 10);
            pre->next = temp;
  • 题目的代码如下
/**
 * 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* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* preHead = new ListNode(-1);
        ListNode* pre = preHead;
        int j = 0;
        // 模拟的思路
        while (l1 != nullptr || l2 != nullptr || j != 0) {
            int n1 = l1 ? l1->val : 0;
            int n2 = l2 ? l2->val : 0;
            j = j + n1 + n2;
            // 插入新节点一定要用这种新建的方式
            ListNode* temp = new ListNode(j % 10);
            pre->next = temp;
            j = j / 10;
            pre = pre->next;
            if (l1)
                l1 = l1->next;
            if (l2)
                l2 = l2->next;
        }
        // 结束条件 l1加完了 或者l2加完了

        return preHead->next;
    }
};

另一道用快慢指针的题

  • 所以head不能动,但是可以新建指针指向head,并移动新的指针!
    题目链接

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

  • 思路就是快慢指针,快指针比慢指针先走n-1步,当慢指针指向末尾的时候,快指针指向的节点就是待删除的节点
  • 该思路满足“进阶”思路中的“一遍扫描”!
/**
 * 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* removeNthFromEnd(ListNode* head, int n) {
        // 删除链表的倒数第n个节点
        // 想保留头结点,就新建一个节点去动!
        // head千万不能动,建立两个快慢指针!
        ListNode* preHead = new ListNode(-1);
        preHead->next = head;
        ListNode* fast = preHead;
        ListNode* slow = preHead;
        if (!head->next && n == 1)
            return nullptr;
        int count = n - 1; // 先让fast
        while (fast != nullptr && count) {
            fast = fast->next;
            count--;
        }
        // 直到fast 这个逻辑有点问题 改一下!
        while (fast != nullptr && fast->next != nullptr &&
               fast->next->next != nullptr) {
            fast = fast->next;
            slow = slow->next;
        }
        // 当前的fast指向倒数第二个节点
        ListNode* slow2 = slow; // 1
        slow2 = slow2->next;    // 2
        // fast=fast->next;
        // 此时fast指向了最后一个节点;slow2这个点是要被去除的
        slow->next = slow2->next; // 成功去除
        return preHead->next;
    }
};

指针只是指针

以下代码是k个一组翻转链表的代码,一道困难题,而我之前总是觉得head指针指错了,直到加了这个代码:

  • 为什么这句话至关重要?因为slow指向了head 但是不代表更新slow就更新了head
            if (slow->next == head)
                head = p1;
            

题目链接是这个:题目链接
代码如下:

/**
 * 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* reverseKGroup(ListNode* head, int k) {
        if (k == 1)
            return head;
        ListNode* preHead = new ListNode(-1);
        preHead->next = head;
        ListNode* slow = preHead;

        ListNode* fast = preHead;
        int count = k;
        ListNode* p1;
        ListNode* p2;
        ListNode* nxt;
        fast = fast->next;
        while (fast) {
            while (count - 1) {
                // 如果在移动过程中就遇到空了,其实已经可以return了
                if (fast->next == nullptr)
                    return head;
                fast = fast->next;
                count--;
            } // 让fast指向最后一个点 只是验证了还剩下这么多节点
            fast = fast->next; // 移到下一个节点
            p1 = slow->next;
            p2 = slow->next->next;

            while (p2 != fast) {
                nxt = p2->next; // 存下来的
                p2->next = p1;
                p1 = p2;
                p2 = nxt;
            }
            // 如果p2==next了
            slow->next->next = fast;
            // 至关重要
            if (slow->next == head)
                head = p1;
          
            slow->next = p1;
            while (slow->next != fast) {
                slow = slow->next;
            }
            count = k;
        }
        return head;
    }
};
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Beiwen_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值