【代码随想录37期】 第一周总结

news2024/11/30 8:53:18

周末再写一遍

【代码随想录37期】Day01 二分查找 + 移除元素
【代码随想录37期】Day02 有序数组的平方、长度最小的子数组、螺旋矩阵Ⅱ
【代码随想录37期】Day03 移除链表元素、设计链表、反转链表
【代码随想录37期】Day04 两两交换链表中的节点、删除链表的倒数第N个节点、链表相交、环形链表II

补充

长度最小的子数组

v2.0:使用滑动窗口
滑动窗口的思想其实很简单,传统暴力使用两个for循环分别控制窗口的边界
滑动窗口重点在于滑~ 所以其中一个边界是靠条件来操控的
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0, len = 0,left = 0;
        vector<int> result;
        result.push_back(0);
        for(int right = 0; right<nums.size();right++){
            sum+=nums[right];
            len++;
            while(sum>=target&&left<nums.size()){
                result.push_back(len);
                sum-=nums[left++];
                len--;
            }
        }
        sort(result.begin(), result.end());
        return result.size()>1?result[1]:result[0];
    }
};

v3.0:
前面使用vector有点大材小用,这里将result声明为INT32_MAX可以直接迭代
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0, len = 0,left = 0,result = INT32_MAX;

        for(int right = 0; right<nums.size();right++){
            sum+=nums[right];
            len++;
            while(sum>=target&&left<nums.size()){
                result = len<result?len:result;
                sum-=nums[left++];
                len--;
            }
        }
        return result==INT32_MAX?0:result;
    }
};
v4.0:
int minSubArrayLen(int target, vector<int>& nums) {
    int left = 0, right = 0, len = 0, sum = 0, min = INT32_MAX;
    for (; right < nums.size(); right++)
    {
        sum += nums[right];
        len++;
        while (sum >= target)
        {
            if (len < min)
                min = len;
            sum -= nums[left];
            len--;
            left++;
        }
    }
    return min==INT32_MAX? 0 : min;
}

关键点

为什么要写INTMAX_32?

题目条件:1 <= nums.length <= 10^ 5,写一个比10^5大的数就行
INT_MAX 和 INT_MIN 是 C++ 的两个宏,代表了整型变量能够存储的最大正整数和最小负整数,分别为 2147483647 和 -2147483648,这两个宏在头文件 <limits.h> 中定义。
2147483647约等于10的9次方
9223372036854775807(long long)约等于10的18次方
记忆方法:2的10次幂(1024)约等于10的3次幂,那2的32次约等于10的9次幂,2的64次约等于10的18次

为什么最后一种写法while不用加left < nums.size()?

已知进入for循环时right<nums.size(),要满足sum >= target,left与right之间至少要有一个数,也就是nums[right],此时left<right<nums.size();

设计链表


class MyLinkedList {
public:
    struct LinkNode
    {
        int val;
        LinkNode* next;
        LinkNode() :val(0), next(nullptr) {};
        LinkNode(int n) :val(n), next(nullptr) {};
    };

    MyLinkedList() {
        dummyHead = new LinkNode();
        size = 0;
    }

    int get(int index) {
        if (index > size - 1)
            return -1;

        LinkNode* curNode = dummyHead->next;
        while (index--)
        {
            curNode = curNode->next;
        }
        return curNode->val;
    }

    void addAtHead(int val) {
        LinkNode* newNode = new LinkNode(val);
        newNode->next = dummyHead->next;
        dummyHead->next = newNode;
        size++;
    }

    void addAtTail(int val) {
        LinkNode* newNode = new LinkNode(val);
        LinkNode* curNode = new LinkNode();
        curNode = dummyHead;
        while (curNode->next)
        {
            curNode = curNode->next;
        }
        curNode->next = newNode;
        size++;
    }

    void addAtIndex(int index, int val) {
        if (index > size)
            return;
        LinkNode* newNode = new LinkNode(val);
        LinkNode* curNode = new LinkNode();
        curNode = dummyHead;
        while (index--)
        {
            curNode = curNode->next;
        }
        newNode->next = curNode->next;
        curNode->next = newNode;
        size++;
    }

    void deleteAtIndex(int index) {
        if (index > size-1)
            return;
        LinkNode* curNode = new LinkNode();
        curNode = dummyHead;
        while (index--)
        {
            curNode = curNode->next;
        }
        LinkNode* toDelete = curNode->next;
        curNode->next = curNode->next->next;
        delete toDelete;
        size--;
    }

private:
    LinkNode* dummyHead;
    int size;
};

##关键点

为什么有的时候curNode = dummyHead?,有时候curNode = dummyHead->next?

总之都会有一个while循环,无论是while(curNode)还是while(curNode->Next)
宗旨有2:

  1. 当链表为空时也可以访问curNode;
  2. curNode遍历完curNode指向最后一个节点而不是nullptr;
    一般考虑这两个情况即可,也就是链表的边界情况

反转链表

1. 用指针定义的结构体或类的成员用->访问,cur->next等价于(*cur).next
2. 链表双指针重要的是指针朝向的更新,循环条件看看是不是快指针,但是返回的指针注意不要是指向null的
3. 指针的结构体:
struct LinkedList{
    int val;
    LinkedList* next;
};

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* tmp;
        ListNode* cur = head;
        ListNode* pre = nullptr;
        while(cur){
            tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;

    }
};

v2.0:使用虚拟头节点来做这道题,可见虚拟头节点并不是必要的

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) {
        ListNode *dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode *slow = nullptr;
        ListNode *fast = head;
        ListNode *tmp;
        while(fast){
            tmp = fast->next;
            fast->next = slow;
            slow = fast;
            fast = tmp;
        }
        // delete dummyHead;
        dummyHead = nullptr;
        return slow;

    }
};

v3.0:写反转链表完全不需要虚拟头节点,把nullptr"作为"头节点即可
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* left = nullptr;
        ListNode* right = head;
        while (right)
        {
            ListNode* tmp = right->next;
            right->next = left;
            left = right;
            right = tmp;
        }

        return left;
    }
};

为什么反转链表不需要虚拟头节点?什么情况下需要呢?

反转链表中,我们如果有虚拟头节点,最后还要去掉,因为我们最后的head发生了变化,不能直接通过虚拟头节点访问了,所以在这里是冗余的,涉及到最终无法访问head节点、head节点发生变化导致无法从虚拟头节点访问时,就不要用虚拟头节点。

两两交换链表中的节点

/**
 * 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 *dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode *cur = dummyHead; 

        while(cur->next&&cur->next->next){
            ListNode* tmp = cur->next; // 记录临时节点
            ListNode* tmp1 = cur->next->next->next; // 记录临时节点
            cur->next = cur->next->next;    // 步骤一
            cur->next->next = tmp;          // 步骤二
            cur->next->next->next = tmp1;   // 步骤三
            cur = cur->next->next; // cur移动两位,准备下一轮交换
        }
        return  dummyHead->next;
    }
};
class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
    ListNode* dummyHead = new ListNode();
    dummyHead->next = head;
    ListNode* pre = dummyHead;
    
    while (pre->next&&pre->next->next)
    {
        ListNode* left = pre->next;
        ListNode* right = pre->next->next;
        pre->next = right;
        left->next = right->next;
        right->next = left;
        pre = left;
    }
    return dummyHead->next;
}
};

关键点

为什么要判断pre->next&&pre->next->next?

检查pre->next->next是因为循环体中会访问pre->next->next的next,不检查会越界
检查pre->next是因为要检查pre->next->next首先要访问pre->next的next,不检查也会越界

这道题有些绕

确实,我目前是这样理解的,主要有三个指针需要交换,除了两个节点还有两个节点的前一个节点,也就是pre,left和right
这道题的left和right要写成局部变量,不然不好处理while的条件

删除链表中的倒数第N个节点

注意使用虚拟头节点,可以避免对头节点的判断,防止各种复杂情况

/**
 * 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) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;
        while(n--&&fast){
            fast = fast->next;
        }
        fast = fast->next;
        while(fast){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;

        return dummyHead->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* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode* slow = dummyHead;
        ListNode* fast = dummyHead;
        while(n--&&fast){
            fast = fast->next;
        }
        fast = fast->next;
        while(fast){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;

        return dummyHead->next;

    }
};
ListNode* removeNthFromEnd(ListNode* head, int n) {
	ListNode* dummyHead = new ListNode();
	dummyHead->next = head;
	ListNode* fast = dummyHead;
	while (n--)
	{
		fast = fast->next;
	}
	ListNode* slow = dummyHead;
	while (fast->next)
	{
		slow = slow->next;
		fast = fast->next;
	}
	ListNode* todelete = slow->next;
	slow->next = slow->next->next;
	
	delete todelete;
	return dummyHead->next;
}

关键点

为什么不直接返回head?

因为head有可能被删掉

这种题该怎么写?

链表题主要需要想象节点之间的连接关系,一定要画图来做,我常用的一个例子就是:
虚拟节点(0)->head(1)->(2)->(3)->(4)->nullptr

环形链表Ⅱ

这道题值得多做几遍

v1.0 这道题很巧妙,是看了随想录的讲解才做出来的
1. 判断有无环:定义快慢指针,快指针一次走两个节点,慢指针走一个,快指针追上慢指针说明有环
2. 追上时需要纸笔列下式子,此时快慢指针走过的节点数量,然后要求的是从开始节点到进入环的节点的长度
3. 具体推导可以看随想录,总之就是需要列一下式子就可以找出关系了~
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *dummyHead = new ListNode(0);
        dummyHead->next = head;
        ListNode *fast = head;
        ListNode *slow = head;
        ListNode *aux = head;
        while(fast&&fast->next){
            fast= fast->next->next;
            slow = slow->next;
            if(fast==slow){
                while(aux!=slow){
                    slow=slow->next;
                    aux=aux->next;
                }
                return aux;
            }
        }
        return nullptr;
        
    }
};

靠视觉记忆记住这张图吧

快指针走了:a + b + k(b+c)

慢指针走了:a + b

所以a +b + k(b+c) = 2(a+b)

得到a + b = k (b + c)

所以a - c = k(b+c)
补充一个哈希表做法保底:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* detectCycle(ListNode* head) {
    unordered_set<ListNode*> visited;
    ListNode* cur = head;
    while (cur)
    {
        if (visited.count(cur))
        {
            return cur;
        }
        visited.insert(cur);
        cur = cur->next;
    }
    return nullptr;
}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1667822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Baidu Comate智能编码助手:AI编程时代提升效率的好帮手

目录 写在前面一、如何安装二、如何使用场景需求体验步骤 三、AI 编程实战指令功能插件功能知识库功能 四、问题建议五、体验总结&#x1f680;写在最后 写在前面 Baidu Comate 是基于文心大模型的 AI编程工具&#xff0c;它结合百度积累多年的编程现场大数据和外部优秀开源数据…

JavaWeb文件上传/下载(Servlet)

效果 文件下载 文件上传 项目概述 Jakarta EE9&#xff0c;Web项目 项目文件结构 0 maven依赖&#xff0c;资源文件 <!-- lombok插件--> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId&g…

proteus示波器不弹出来

运行后示波器没有弹出来 点击调试&#xff08;Debug&#xff09;在点击Digital Oscilloscope 完成

[OpenGL高级光照] 阴影改善

目录 一 阴影失真 二 阴影改善 2.1 减小片段深度值 2.2 降低纹理 2.3 注意事项 三 消除Repeat的问题 3.1 让裁剪矩阵的立方体变大 ​3.2 利用采样范围重置 四 精度问题 本章节源码 点击此处 一 阴影失真 在上一篇中,实现了阴影效果之后,但是我们会发现阴影效果中地面…

Linux基础之进程的基本概念

目录 一、进程的基本概念 1.1 什么是进程 1.2 PCB的概念 1.3 进程的查看 1.3.1 查看进程方式一 1.3.2 查看进程的方式二 1.4 父进程与子进程 一、进程的基本概念 1.1 什么是进程 进程是什么&#xff1f; 课本概念&#xff1a;程序的一个执行实例&#xff0c;正在执行的…

GENRE

1、整体设计 该工作&#xff08;GENRE&#xff09;在新闻推荐的场景下&#xff0c;用 LLM 构造了三个不同的prompts&#xff0c;分别来进行新闻摘要的改写&#xff0c;用户画像的构建&#xff0c;还有样本增强。 2、分模块介绍 摘要改写&#xff1a;把新闻的title&#xff0c;…

Golang | Leetcode Golang题解之第84题柱状图中最大的矩形

题目&#xff1a; 题解&#xff1a; func largestRectangleArea(heights []int) int {n : len(heights)left, right : make([]int, n), make([]int, n)for i : 0; i < n; i {right[i] n}mono_stack : []int{}for i : 0; i < n; i {for len(mono_stack) > 0 &&am…

亚信安慧AntDB新篇章:数据库技术飞跃

随着大数据时代的到来&#xff0c;对数据库的需求愈发强烈。在这一背景下&#xff0c;国产数据库逐渐崭露头角&#xff0c;亚信安慧AntDB作为重要的代表产品之一正积极参与到激烈的市场竞争中。亚信安慧AntDB不仅追求技术的革新和突破&#xff0c;同时也致力于满足用户日益增长…

国内智能搜索工具实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

数据与结构--堆

堆 堆的概念 堆&#xff1a;如果有一个关键码的集合K{k0,k1,k2,…,kn-1}&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中&#xff0c;并满足ki<k2i1且ki<k2i2&#xff08;或满足ki>k2i1且ki>k2i2&#xff09;&#xff0c;其中i0,1,2,…

综合性练习(验证码案例)

目录 一、需求 二、准备工作 三、约定前后端交互接口 1、需求分析 2、接口定义 四、Hutool工具介绍 1、引入依赖 2、测试使用Hutool生成验证码 五、实现服务器端代码 代码解读&#xff1a; 六、调整前端页面代码 七、运行测试 随着安全性的要求越来越高&#xff0c…

数据库 MySQL 四种事务隔离级别代码演示 -- 读未提交;读已提交;可重复读;串行化

前提 # 设置数据库隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL 隔离级别;# 查询事务隔离级别 select transaction_isolation;事务处理的分离水平对应的数据整合情况&#xff1a; 隔离级别非提交读取&#xff08;脏读&#xff09;不可重复读取幻读READ UNCOMMITED√√√…

【JVM】Class文件的格式

目录 概述 Class文件的格式 概述 Class文件是JVM的输入&#xff0c;Java虚拟机规范中定义了Class文件的结构。Class文件是JVM实现平台无关、技术无关的基础。 1:Class文件是一组以8字节为单位的字节流&#xff0c;各个数据项目按顺序紧凑排列 2:对于占用空间大于8字节的数据…

Geopandas以及CMakeList程序编写技巧

Geopandas官方文档 Geopandas官方文档 reset_index()函数 pandas库中的reset_index()函数是用于重新设置数据框索引的方法。 例如&#xff1a;当我对于文件数据进行了一系列操作后&#xff0c;例如设置了索引set_index&#xff0c;那么会导致数据的索引框发生变化&#xff…

Linux网络编程】传输层中的TCP和UDP(UDP篇)

【Linux网络编程】传输层中的TCP和UDP&#xff08;UDP篇&#xff09; 目录 【Linux网络编程】传输层中的TCP和UDP&#xff08;UDP篇&#xff09;传输层再谈端口端口号范围划分认识知名端口号netstatiostatpidofxargs UDP协议UDP协议端格式UDP的特点面向数据报UDP的缓冲数据UDP使…

08 - hive的集合函数、高级聚合函数、炸裂函数以及窗口函数

目录 1、集合函数 1.1、size&#xff1a;集合中元素的个数 1.2、map&#xff1a;创建map集合 1.3、map_keys&#xff1a; 返回map中的key 1.4、map_values: 返回map中的value 1.5、array 声明array集合 1.6、array_contains: 判断array中是否包含某个元素 1.7、sort_a…

最佛系的打字练习软件——TL(TypeLetters)

有朋友开玩笑说&#xff1a;TL&#xff08;TypeLetters&#xff09;是最佛系的打字练习软件。真的吗&#xff1f;仔细看&#xff0c;好像还真有这么点意思&#xff1a; 无竞速&#xff1a;TL没有速度显示&#xff0c;初学者逐个认清键位&#xff0c;无需关心速度&#xff0c;中…

不训练也能给模型加上各种超能力?

之前我写过一篇 Sakana 与 Jamba (qq.com) Sakana也好,Jamba也罢,其实都是模型合并的一种比较好的项目实践,今天我们可以讨论一下普通开发者是否能像做一个项目一样,合并多个模型,达到自己想要的效果(GPU的连载后面写,东西太多,再给2篇也不知道能不能写完 ) 不同于Sakan…

Apifox 教程:如何实现跨语言调用(Java、PHP、Python、Go 等)

在一些特定场景下&#xff0c;比如需要在 Apifox 中对文件进行读写、加密、转换格式或者进行其它业务的操作时&#xff0c;仅使用 Apifox 内置的 JS 类库可能无法满足业务需求&#xff0c;这时&#xff0c;就可以借助「外部程序」作为解决方案。 外部程序是保存在「外部程序目…

嵌入式 - GPIO编程简介

An Introduction to GPIO Programming By Jeff Tranter Wednesday, June 12, 2019 编者按&#xff1a;本 2019 年博客系列是 ICS 最受欢迎的系列之一&#xff0c;现已更新&#xff08;2022 年 12 月&#xff09;&#xff0c;以确保内容仍然准确、相关和有用。 本博客是 Integr…