当前位置: 首页 > article >正文

代码随想录算法【Day4】

Day4

1.链表的题目,要在草稿纸上模拟清晰后就简单了

2.双指针更加灵活的应用。

3.环形链表多练习。

24. 两两交换链表中的节点
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* _dummyHead = new ListNode(0); //虚拟头结点
        _dummyHead -> next = head;
        ListNode* cur = head;
        ListNode* pre = _dummyHead;
        ListNode* tmp;
        while(cur != NULL && cur -> next != NULL){
            tmp = cur -> next -> next;
            //三个步骤
            pre -> next = cur -> next; 
            cur -> next -> next = cur;
            cur -> next = tmp;
            //更新值
            pre = cur;
            cur = tmp;
        }
        ListNode* result = _dummyHead->next;
        delete _dummyHead;
        return result;
    }
};
19.删除链表的倒数第N个节点

直接法:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //直接法,需要两次遍历
        ListNode* _hummyHead = new ListNode(0); //虚拟头结点
        _hummyHead -> next = head;
        ListNode* tmp = nullptr, *cur = _hummyHead; 
        int count = 0; //记录节点个数
        if(cur -> next == NULL) return head;
        while(cur -> next != NULL){
            cur = cur -> next;
            count ++;
        }
        cur = _hummyHead;
        int m = count - n;
        //移动到要删除的节点的前一个位置
        while(m--){
            cur = cur -> next;
        }
        //删除操作
        if(cur -> next -> next != nullptr) 
                tmp = cur -> next ->next;
        delete cur -> next;
        cur -> next = tmp;
        return _hummyHead -> next;
    }
};

第一次写,没有加“if(cur -> next == NULL) return head;”这句,程序一直报错,在这里我debug了很久。

要注意,cur -> next为nullptr的话,cur -> next -> next 就是非法的。

双指针法

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //快慢指针,只用遍历一遍就可以删除节点
        ListNode *_hummyHead = new ListNode(0);
        _hummyHead -> next = head;
        ListNode *slow = _hummyHead, *fast = _hummyHead;
        //先正常写,然后判断边界情况
        while (n --){
            fast = fast -> next;
        }
        while(fast -> next != nullptr){
            slow = slow -> next;
            fast = fast -> next;
        }
        //删除节点
        ListNode *tmp = slow -> next;
        slow -> next = tmp -> next;
        delete tmp;
        return _hummyHead -> next;
    }
};
面试题 02.07. 链表相交

有点类似模拟题,思路清晰后挺简单的。

题目示例里面提到的,“题目条件如果两个链表相交则不能为 0”,意思是,0代表了NULL。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        //相交的节点指地址是相同的,值相同的节点不一定地址相同
        ListNode* curA = headA;
        ListNode* curB = headB;
        int lenA = 0, lenB =0;
        while(curA != NULL){
            lenA ++;
            curA = curA -> next;
        }
        while(curB != NULL){
            lenB ++;
            curB = curB -> next;
        }
        curA = headA;
        curB = headB;
        //让curA成为最长链表的头
        if(lenA < lenB){
            swap(lenA, lenB);
            swap(curA, curB);
        }
        int gap = lenA - lenB;
        //让两表对齐
        while(gap --){
            curA = curA -> next;
        }
        while(curA != curB && curA != nullptr){
            curA = curA -> next;
            curB = curB -> next;
        }
        return curA;
    }
};
142.环形链表II

1.如何判断链表有环?

快慢指针相遇

2.假如慢指针每次移动一步,快指针每次移动两步,会不会存在这样的一个情况,即快慢指针永远无法相遇?

可以这样来看,慢指针相对于快指针静止,快指针每次相对移动一步来遇到慢指针,所以不存在永远无法相遇的情况。

3.如何判断快慢指针一定会相遇?

假如快指针每次移动5步,慢指针每次移动2步,以3步为单位的相对移动。

本质上是看以3步为单位的移动,是否一定能遍历环上的所有节点

所以只有当环长L不是3的倍数时才能相遇

4.环的入口怎么找?

快慢指针的运动如下图所示:

假设快慢指针在环中的某一点相遇,设:

①slow = x + y

(而不是 slow = x+y+n(y+z),因为慢指针被快指针追上的时候,慢指针一定在走第一圈)

②fast = x + y + n(y+z)

因为fast = 2 * slow

有等式: 2 * (x + y) = x + y + n(y +z)

得到:x = n(y + z) - y,整理得:③x = (n - 1)(y + z) + z,其中n ≥ 1

由③式可知,让慢指针1和慢指针2分别从起点和相遇点出发,他们总会在环的入口相遇,这样就找到了环的入口。

5.慢指针被快指针追上的时候,为什么一定是在慢指针走第一圈的时候?

假设快指针已经走了3圈,把环铺开,如下图,慢指针没转完一圈,一定就被快指针追上了。

以下是我ac的代码,做的多余判断太多了,建议去看一下网站上的代码。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        //判断是否有环
        //记得考虑一下只有一个节点的情况和没有节点的情况
        ListNode* slow = head, *fast = head;
        if(head == nullptr || head->next == NULL) return NULL;
        while(fast != nullptr && fast->next != NULL){
            slow = slow -> next;
            fast = fast -> next -> next;
            if(slow == fast) break;
        }
        if(fast == nullptr|| fast->next == NULL) return NULL;
        //如果有环,返回入环的第一个节点
        ListNode *cur = head;
        while(cur != slow){
            slow = slow -> next;
            cur = cur -> next;
        }
        return cur;
    }
};

以下是我第一次写的报错的代码,刚开始就让快指针走了两步,导致表达式发生变化,所以报错,代码一定要严格按照表达式来。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        //判断是否有环
        //特殊判断一下只有一个节点的情况和没有节点的情况
        if(head == NULL && head -> next == NULL) return NULL;
        ListNode* slow = head, *fast = head -> next -> next;
        while(fast != nullptr && slow != fast){
            slow = slow -> next;
            fast = fast -> next -> next;
        }
        if(fast == nullptr) return NULL;
        //如果有环,返回入环的第一个节点
        ListNode *cur = head;
        while(cur != slow){
            slow = slow -> next;
            cur = cur -> next;
        }
        return cur;
    }
};

http://www.kler.cn/a/456653.html

相关文章:

  • C#封送类
  • C++——deque的了解和使用
  • pyside6总结
  • 技术速递|调用异步功能 - WinForms 在 .NET 9 中的未来发展
  • 模型 10-10-10旁观思维
  • 【AIGC-ChatGPT职业提示词指令】智能职业规划助手:基于SVG可视化的职业发展指南系统
  • Docker和Kubernetes(K8s)区别
  • js正则表达式 校验邮箱,非法字符限制输入
  • 在Linux的世界中怎么玩转定时器任务
  • WebSocket 在实时比分推送中的应用
  • JVM调优实践篇
  • 虚幻5 UE5 UNREALED_API d虚幻的
  • gesp(二级)(17)洛谷:B4064:[GESP202412 二级] 寻找数字
  • Linux快速入门-一道简单的Makefile编程题目
  • windows C#-显式实现接口成员
  • Datawhale AI冬令营 动手学AI Agent
  • iOS 苹果开发者账号: 查看和添加设备UUID 及设备数量
  • 服务器广播算法
  • SQL 实战:动态表创建与多表更新的高级 SQL
  • windows上设置svn忽略
  • Pandas03
  • Scrum框架下的前端任务分配
  • 【ETCD】【实操篇(十九)】ETCD基准测试实战
  • 【MySQL — 数据库基础】深入解析MySQL数据库操作:创建、使用、删除及字符集管理
  • jwt在express中token的加密解密实现方法
  • FastAPI vs Flask 专业对比与选择