【HOT100第五天】搜索二维矩阵 II,相交链表,反转链表,回文链表

news2025/2/23 12:18:21

240.搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

先动手写写最简单方法,二重循环。

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m=matrix.size(),n=matrix[0].size();
        if(m==0||n==0) return{};
        for(auto& itx:matrix){
            for(auto& itxy:itx){
                if(itxy==target) return true;
            }
        }
        return false;
    }
};

优化方法的话,根据昨天做的题,感觉大多数矩阵相关的题目都是依靠找规律,那我们再看看例图:

 以“5”这一项为例,左边和上边的数比 5 小,右边和下边的数比 5 大。可以利用这一特点,从左下角或者右上角开始顺藤摸瓜。

以从右上角为例,如果target小于15,就向左移一位,如果target大于15,就向右移一位,以此类推,如果已经移出了矩阵的边界,说明没找到target的值,就返回false。

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        int m=matrix.size(),n=matrix[0].size();
        if(m==0||n==0) return{};
        int x=0,y=n-1;
        while(x<=m-1&&y>=0){
            if(matrix[x][y]==target) return true;
            else if(matrix[x][y]>target){
                y--;
            }
            else{
                x++;
            }
        }
        return false;
    }
};

160. 相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。

 虽然是简单题但其实是最让我痛苦的一道。!看一眼题目感觉还好理解,一看给的例子就懵了。

好了这种情况下先不要急,看一下方法体吧。输入是两个链表的头结点,输出的是相交节点。那目的先可以初步确定了。

一开始看到可能会没什么思路,这是正常的,因为题目对相交链表的表述不太清楚。这道题中相交链表的定义是一个从某一结点开始,两链表相交后,后面的结点完全相同。

验证一下它说的是不是这样,我添加了一个用例,在中间的某一位置相交,又在后面分开:

可见确实如此,糟老头子坏得很啊。

这样的话,两个链表相交的过程就可以简化成下面这样了👇

a1->a2->...->ai->c1->c2->...->cn
b1->b2->...->bj

设想一下,如果 1~i 和 1~j 的值相同就好了,那就意味着这两个链表长度相同,A和B链表上的指针到达相交结点的时间是相同的。

但事实是两个链表不一定长度相同,不过思路还是一样,是不是只要A和B两个链表的指针同时到达相交结点,就可以找到这个结点了?

我们现在已知,遍历A链表需要指针移动(i+n)次,遍历B链表需要指针移动(j+n)次,不如让A链表的指针遍历完A后再遍历一遍B链表,并且B链表指针遍历完B后再遍历A链表,这样的话,每一个指针都一共要移动(i+j+2n)次,那么第一个找到的满足(pa==pb)的结点,就一定是相交结点。

如果两个链表没有重合也不用担心,两个指针会在链表的尾部相遇,然后返回一个空指针。

这样就可以写出代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if(headA==nullptr||headB==nullptr) return nullptr;
        ListNode *pa=headB,*pb=headA;
        while(pa!=pb){
            if(pa) pa=pa->next;
            else pa=headB;
            if(pb) pb=pb->next;
            else pb=headA;
        }
        return pa;
    }
};

但再具体想一想,如果两链表后面的结点不一样,只有中间连续的1~n的结点相交的情况下,这个方法能不能用呢?答案是不能!因为相交结点后面的长度会影响到指针到达相交节点。比如说链表A如果是(i1+n+i2),链表B是(j1+n+j2),那用之前的两个都遍历的方法,A的指针pa第二次到达相交结点走过的路程是(i1+n+i2+j1),而链表B第二次到达相交结点走过的路程是(j1+n+j2+i1)!!!

 206. 反转链表

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

反转无非是把 a1 -> a2 -> a3 ->..._> an -> nullptr 改成 nullptr <- a1 <- a2 <-...<- an。

比如遍历用的指针是p,我们把p的next改成前驱结点就好了。不过前驱结点需要提前记录,而且为了在改变了p->next之后还可以继续遍历,就需要先把后继p->next存下来再改成前驱即可。所以整理一下,对结点的调整步骤为:

1. 保存后继

2. 把next改成前驱结点

3. 把当前结点改成前驱

4. 让p移向下一个结点

/**
 * 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) return nullptr;
        ListNode* p=head;
        ListNode* pre=nullptr;
        while(p!=nullptr){
            ListNode* next=p->next;
            p->next=pre;
            pre=p;
            p=next;
        }
        return pre;
    }
};

234. 回文链表

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

克服恐惧的最好方法就是避免恐惧(。。),不会操作链表但是向想写出来,就先把它复制进数组里再对它使用双指针!过了就是胜利✌

/**
 * 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:
    bool isPalindrome(ListNode* head) {
        vector<int> nums;
        while(head!=nullptr){
            nums.emplace_back(head->val);
            head=head->next;
        }
        int left=0,right=nums.size()-1;
        while(left<right){
            if(nums[left]==nums[right]){
                left++;
                right--;
            }
            else{
                return false;
            }
        }
        return true;
    }
};

说笑了,下面看看正规方法来做。

 我们刚刚既然已经写过了反转链表,那这一次不如用上。

直接在它给的链表上改,把前一半链表都反转,后一半链表不变,然后用两个指针分别遍历前后两段,一边遍历一边比较。

如何实现只反转一半?怎么找到链表的中点?这里可以使用快慢指针,快指针一次进两格,慢指针一次进一格,那么当fast或者fast->next为空时,slow所在的位置就是中点了。

不过要注意,当结点数为奇数时,我们需要用中点后面那个点作为后半部分的起始点。 

如何判断链表是奇数个还是偶数个?在纸上画一下,以题目提供的测试用例为例:

fast经历的结点索引值是0,2,“4”。所以当结点是偶数个时,fast==nullptr,以此类推,当结点为奇数个时,fast->next=nullptr。

梳理一下目前我们用到的变量,快慢指针是肯定的,fast用来确定奇偶和中点,slow摸到中点顺便用于反转链表,pre是反转用到的前驱结点,next是反转用到的后继结点。

当摸到中点并且完成反转时,我们的链表变成了这样👇(以4个和5个结点的链表为例)

a1 <- a2   a3 -> a4 -> a5 【pre在a2的位置,slow在a3的位置,next在a4的位置,fast在a5的位置】

a1 <- a2  a3 -> a4 【pre在a2的位置,slow在a3的位置,next在a4的位置,fast在a4后面的位置】

因此,偶数个结点的话用pre和slow来遍历一下链表就行了,奇数个结点的话就把slow处理一下再遍历。

/**
 * 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:
    bool isPalindrome(ListNode* head) {
        if(head==nullptr||head->next==nullptr) return true;
        ListNode* slow=head;
        ListNode* fast=head;
        ListNode* pre=nullptr;
        ListNode* next=nullptr;
        //快指针在链表尾部,慢指针在中点
        while(fast&&fast->next){
            fast=fast->next->next;
            next=slow->next;
            slow->next=pre;
            pre=slow;
            slow=next;
        }
        //fast为空是偶数,fast不为空是奇数
        if(fast!=nullptr){
            slow=slow->next;
        }
        
        //利用pre和slow比较是否相等
        while(slow!=nullptr&&pre!=nullptr){
            if(slow->val!=pre->val){
                return false;
            }
            slow=slow->next;
            pre=pre->next;
        }
        return true;
    }
};

这题下次还是用复制进数组的方法吧(。。。。)

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

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

相关文章

.NET 9与C# 13革新:新数据类型与语法糖深度解析

记录&#xff08;Record&#xff09;类型 使用方式&#xff1a; public record Person(string FirstName, string LastName); 适用场景&#xff1a;当需要创建不可变的数据结构&#xff0c;且希望自动生成 GetHashCode 和 Equals 方法时。不适用场景&#xff1a;当数据结构需…

冠层四流近似模型的发展历史

1. Kunbelka-Munk theory This is the earlist model using a two-stream approximation d I d z − ( k s ) I s J d J d z ( k s ) J − s I \begin{aligned} &\frac{dI}{dz} -(ks)IsJ\\ &\frac{dJ}{dz} (ks)J - sI \end{aligned} ​dzdI​−(ks)IsJdzdJ​(…

MySQL-关联查询和子查询

目录 一、笛卡尔积 二、表连接 1、内部连接 1.1 等值连接 1.2 非等值连接 2、外部链接 2.1 左外连接-LEFT JOIN 2.2 右外连接-RIGHT JOIN 2.3 全关联-FULL JOIN/UNION 三、子查询 1、嵌套子查询 2、相关子查询 3、insert和select语句添加数据 4、update和select语…

云计算虚拟化-kvm创建虚拟机

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 虚拟化&#xff0c;简单来说就是把一台服务器/PC电脑&#xff0c;虚拟成多台独立的虚拟机&#xff0c;每台虚拟机之间相互隔…

计算机编程中的设计模式及其在简化复杂系统设计中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 计算机编程中的设计模式及其在简化复杂系统设计中的应用 计算机编程中的设计模式及其在简化复杂系统设计中的应用 计算机编程中的…

编程考古-计算机发展(中)

晶体管计算机时代 尽管真空管技术标志着计算机步入了现代化的门槛&#xff0c;但其固有的局限性——庞大的体积、高昂的能耗、频繁的故障以及不菲的成本——极大地阻碍了其普及与实际应用。 晶体管的早期 Point-contact transistor 点接触晶体管 1947年&#xff0c;贝尔实验…

vue2+3 —— Day5/6

自定义指令 自定义指令 需求&#xff1a;当页面加载时&#xff0c;让元素获取焦点&#xff08;一进页面&#xff0c;输入框就获取焦点&#xff09; 常规操作&#xff1a;操作dom “dom元素.focus()” 获取dom元素还要用ref 和 $refs <input ref"inp" type&quo…

报错 No available slot found for the embedding model

报错内容 Server error: 503 - [address0.0.0.0:12781, pid304366] No available slot found for the embedding model. We recommend to launch the embedding model first, and then launch the LLM models. 目前GPU占用情况如下 解决办法: 关闭大模型, 先把 embedding mode…

Maven 构建项目

Maven 是一个项目管理和构建工具&#xff0c;主要用于 Java 项目。它简化了项目的构建、依赖管理、报告生成、发布等一系列工作。 构建自动化&#xff1a;Maven 提供了一套标准化的构建生命周期&#xff0c;包括编译、测试、打包、部署等步骤&#xff0c;通过简单的命令就可以执…

【C++笔记】C++三大特性之多态

【C笔记】C三大特性之多态 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】C三大特性之多态前言一.多态1.1 多态的概念1.2 虚函数1.3 虚函数的重写/覆盖1.4 多态的定义及实现 二.虚函数重写的⼀些其他问题2.1 协变(…

【项目实战】基于 LLaMA-Factory 通过 LoRA 微调 Qwen2

【项目实战】基于 LLaMAFactory 通过 LoRA 微调 Qwen2 一、项目介绍二、环境准备1、环境准备2、安装LLaMa-Factory3、准备模型数据集3.1 模型准备3.2 数据集准备 三、微调1、启动webui2、选择参数3、训练 四、测试五、总结 一、项目介绍 LLaMA-Factory是一个由北京航空航天大学…

内容占位符:Kinetic Loader HTML+CSS 使用CSS制作三角形原理

内容占位符 前言 随着我们对HTML和CSS3的学习逐渐深入&#xff0c;相信大家都已经掌握了网页制作的基础知识&#xff0c;包括如何使用HTML标记构建网页结构&#xff0c;以及如何运用CSS样式美化页面。为了进一步巩固和熟练这些技能&#xff0c;今天我们一起来完成一个有趣且实…

SpringSecurity 鉴权认证入门讲解

​ Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富。 ​ 一般来说中大型的项目都是使用SpringSecurity 来做安全框架。小项目有Shiro的比较多&#xff0c;因为相比与Sp…

【插件】多断言 插件pytest-assume

背景 assert 断言一旦失败&#xff0c;后续的断言不能被执行 有个插件&#xff0c;pytest-assume的插件&#xff0c;可以提供多断言的方式 安装 pip3 install pytest-assume用法 pytest.assume(表达式,f’提示message’) pytest.assume(表达式,f‘提示message’) pytest.ass…

虾皮:LLM注意力机制的下沉现象分析

&#x1f4d6;标题&#xff1a;When Attention Sink Emerges in Language Models: An Empirical View &#x1f310;来源&#xff1a;arXiv, 2410.10781 &#x1f31f;摘要 &#x1f538;语言模型&#xff08;LM&#xff09;将大量注意力分配给第一个标记&#xff0c;即使它在…

MyBatis的select标签的resultType属性

在MyBatis框架中&#xff0c;映射文件中select标签的resultType属性&#xff0c;用于指定从数据库查询返回结果集需要映射的Java类型&#xff0c;即Mapper接口中方法返回值类型(或集合中的泛型类型)&#xff0c;可以是基本数据类型、基本数据类型的包装类型、自定义的PO类型、集…

ubuntu20.04如何升级python3.8到python3.10

主要参考了这两个链接&#xff1a; 如何在Ubuntu 20.04安装Python 3.10 | myfreaxhttps://www.myfreax.com/how-to-install-python-3-10-on-ubuntu-20-04/#:~:text%E5%9C%A8%E8%B0%83%E8%AF%95%E5%92%8C%E5%85%B6%E4%BB%96%E5%B7%A5%E5%85%B7%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%B…

AWTK-WIDGET-WEB-VIEW 发布

awtk-widget-web-view 是通过 webview 提供的接口&#xff0c;实现的 AWTK 自定义控件&#xff0c;使得 AWTK 可以方便的显示 web 页面。 项目网址&#xff1a; https://gitee.com/zlgopen/awtk-widget-web-view webview 提供了一个跨平台的 webview 接口&#xff0c;是一个非…

丹摩征文活动|FLUX.1+ComfyUI部署与使用

丹摩征文活动&#xff5c;FLUX.1ComfyUI部署与使用 1.引言 在人工智能飞速发展的今天&#xff0c;丹摩智算平台&#xff08;DAMODEL&#xff09;以其卓越的AI算力服务脱颖而出&#xff0c;为开发者提供了一个简化AI开发流程的强大工具。通过租赁GPU资源&#xff0c;丹摩智算平…

性能高于Transformer模型1.7-2倍,彩云科技发布基于DCFormer架构通用大模型云锦天章

2017年&#xff0c;谷歌发布《Attention Is All You Need》论文&#xff0c;首次提出Transformer架构&#xff0c;掀开了人工智能自然语言处理&#xff08;NLP&#xff09;领域发展的全新篇章。Transformer架构作为神经网络学习中最重要的架构&#xff0c;成为后来席卷全球的一…