C++相交链表和反转链表详解

目录
  • 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。
    • 思路
  • 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
    • 双指针思路
    • 递归
  • 总结

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

思路

简单来说,就是求两个链表交点节点的 指针。 这里同学们要注意,交点不是数值相等,而是指针相等。

为了方便举例,假设节点元素数值相等,则节点指针相等。

看如下两个链表,目前curA指向链表A的头结点,curB指向链表B的头结点:

我们求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到,和curB 末尾对齐的位置,如图:

此时我们就可以比较curA和curB是否相同,如果不相同,同时向后移动curA和curB,如果遇到curA == curB,则找到焦点。

否则循环退出返回空指针。

/**
 * 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) {
        ListNode* curA=headA;
        ListNode* curB=headB;
        int lenA=0;
        int lenB=0;
        while(curA!=nullptr){  // 求链表A的长度
            lenA++;
            curA=curA->next;
        }
        while(curB!=nullptr){  // 求链表B的长度
            lenB++;
            curB=curB->next;
        }
        //现在的curA,curB已经指向最后一个节点了,需要重新指向头结点
        curA=headA;
        curB=headB;
        if(lenA<lenB){  //假设链表A的长度大于链表B,否则交换
            swap(lenA,lenB);
            swap(curA,curB);
        }
        //gap是两个链表长度的差值
        int gap=lenA-lenB; // gap=lenA-lenB 错误,要有返回类型
        while(gap){     // 让curA和curB在同一起点上(末尾位置对齐)
            gap--;
            curA=curA->next;
        }
        while(lenB){   // 遍历curA 和 curB,遇到相同则直接返回
            if(curA==curB)
                return curA; // return curA(val) 返回节点中的值,这个写法是错误的  直接return curA
            curA=curA->next;
            curB=curB->next;
            lenB--;
        }
        return nullptr;  //没有交点则返回空
    }
};

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

示例 1:

输入:head = [1,2,3,4,5]

输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]

输出:[2,1]

示例 3:

输入:head = []

输出:[]

双指针思路

首先判断链表是否为空,为空则返回nullptr。

接下来定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。

然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。

为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。

最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。

/**
 * 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* per=nullptr;
        ListNode* cur=head;
        ListNode* temp; //建立一个指针
        while(cur){  //没必要写 while(cur!=nullptr),写了这个还要判断cur,会浪费时间,直接cur就可以
            temp=cur->next; //保存cur的下一个节点
            cur->next=per; //cur的下一个节点指向per,实现反转
            per=cur;  //cur=per;错误,是把cur的节点赋值给per
            cur=temp; //temp=cur;错误,是把temp(原来的cur->next)的节点赋值给cur
        }
        return per;
    }
};

递归

/**
 * 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* reverse(ListNode* per,ListNode* cur){  //返回的是一个链表,其返回值是指针
        if(cur==nullptr)  //递归的终止条件
            return per;
        ListNode* temp=cur->next;
        cur->next=per;
        return reverse(cur,temp); // 调用要写return
    }
    ListNode* reverseList(ListNode* head) {
        if(head==nullptr) //链表判空
            return nullptr;
        return reverse(NULL,head); // 调用要写return
    }
};

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 带你粗略了解C++中的深浅拷贝

    目录 一. 背景 二. 代码实现 三. 问题 四. 解决方法 总结 一. 背景 首先看这样一个问题,在Car类中聚合了Engine类 二. 代码实现 下面给出类Car与类Engine的定义 Car.h #ifndef COPY__CAR_H_ #define COPY__CAR_H_ #include "Engine.h" #include <string> using namespace std; class Car { public: // 构造函数 Car(); Ca

  • 一篇文章带你了解C++语法基础--字符串

    目录 总结 字符与整数的关联在于ASCII码:每一个常用字符都对应一个-128 ~ 127 的数字,二者之间是可以进行相互转换的: #include <iostream> using namespace std; int main(){ char wordOne = 'a'; cout << int(wordOne) << endl; int number = 66; cout << char(number) << endl; return 0;

  • 带你了解C++this指针的用法及其深究

    目录 前言 一.this指针是个什么东东,重要吗? 二.案例理解 主要的用途 总结 前言 今天,码神像一个新车手一样,尝试着用模板来更新一下,不要建议哦,毕竟没有放弃爱情的拓海也不是真正的车神,哈哈,发车了 一.this指针是个什么东东,重要吗? 首先,我以码神的名义起誓,this指针绝对重要,尤其是对于c++这个面向对象编程的语言来说! 有的码手可能要说了:你说重要就重要?那我还说不重要呢? 这个么,空口无凭,我现在来举一个例子: 我们知道对于一个类来说,要有很多工作要做,其中类的成员函数可以

  • 带你粗略了解C++流的读写文件

    目录 读写文本文件 二进制读写文件 按指定格式读写文件 总结 读写文本文件 C++的IO流: IO:向设备输入数据和输出数据 设备有: 1)文件 2)控制台 3)特定的数据类型(stringstream) C++中,必须通过特定的已经定义好的类, 来处理IO(输入输出) C++的 IO类库为: 文件流:对文件进行读写操作 头文件: < fstream > ifstream 对文件输入(读文件) ofstream 对文件输出(写文件) fstream 对文件输入或输出 文件的打开方式: 模式标志

  • c++网络编程下Linux的epoll技术和Windows下的IOCP模型

    目录 一.IOCP和Epoll之间的异同 1.异 2.同 二:Epoll理解与应用. 1.epoll是什么? 2.epoll与select对比优化 3.epoll是怎么优化select问题的 三.epoll的几个函数的介绍: 1.epoll_create函数 2.epoll_ctl函数 3.epoll_wait函数 4.条件触发和边缘触发 四.IOCP理解与应用 1.传统服务器的网络IO流程 2.使用IOCP的基本步骤 一.IOCP和Epoll之间的异同 1.异 1).IOCP是WINDOWS系

  • JS调用C++函数抛出异常及捕捉异常详解

    目录 总结 本文讲述如何利用v8::TryCatch捕捉js代码中发生的异常. 首先,声明TryCatch对象. v8::TryCatch trycatch( isolate ); 然后,定义抛出异常的函数: void ThrowException( const v8::FunctionCallbackInfo<v8::Value>& info ) { v8::Isolate* isolate = info.GetIsolate(); v8::HandleScope scope( is

  • C++ GetDlgItem用法案例详解

    GetDlgItem的用法小结 GetDlgItem用于获得指定控件ID的窗体指针,函数原型如下: HWND GetDlgItem( HWND hDlg, int nIDDlgItem ); CWnd* GetDlgItem(int nID) const; 它的使用说明中有这样一行字,**The returned pointer may be temporary and should not be stored for later use. **,那说明,它返回的指针有可能是有效的,有可能是无效

  • C++ namespace案例详解

    在C++语言编写的程序中,变量和函数等的作用范围是有一定限制的.比如,在函数体中定义的一个临时变量就不可以在函数体外使用.为了解决变量和函数等的作用范围,在C++语言中引入了名空间的概念,并增加了关键字namespace和using 在一个名空间中可以定义一组变量和函数,这些变量和函数的作用范围一致,可以将这些变量和函数称为这个名空间的成员. 通过名空间,可以在同一个文件中使用相同的变量名或函数名,只要它们属于不同的名空间.另外,名空间可以使得代码操作具有相同名字但属于不同库的变量.而且,名空间

  • C语言数据结构 链表与归并排序实例详解

    C语言数据结构 链表与归并排序实例详解 归并排序适合于对链表进行原址排序,即只改变指针的连接方式,不交换链表结点的内容. 归并排序的基本思想是分治法:先把一个链表分割成只有一个节点的链表,然后按照一定顺序.自底向上合并相邻的两个链表. 只要保证各种大小的子链表是有序的,那么最后返回的链表就一定是有序的. 归并排序分为分割和合并两个子过程.分割是用递归的方法,把链表对半分割成两个子链表:合并是在递归返回(回朔)的时候,把两个有序链表合并成一个有序链表. (注意:只有一个节点的链表一定是有序的) 这

  • C语言之复杂链表的复制方法(图示详解)

    什么是复杂链表? 复杂链表指的是一个链表有若干个结点,每个结点有一个数据域用于存放数据,还有两个指针域,其中一个指向下一个节点,还有一个随机指向当前复杂链表中的任意一个节点或者是一个空结点.今天我们要实现的就是对这样一个复杂链表复制产生一个新的复杂链表. 复杂链表的数据结构如下: typedef int DataType; //数据域的类型 //复杂链表的数据结构 typedef struct ComplexNode { DataType _data ; // 数据 struct Complex

  • C语言实现单链表的基本功能详解

    1.首先简单了解一下链表的概念: 要注意的是链表是一个结构体实现的一种线性表,它只能从前往后,不可以从后往前(因为next只保存下一个节点的地址).在实现单链表的操作时,需要用指针来操作.很简单,注释写的很详细,欢迎大家指正哈哈哈哈~之前写的太烂了重新写了一下..... 2.代码展示: #include <stdio.h> #include <assert.h> #include <stdlib.h> typedef struct linklist { int data

  • Java数据结构之环形链表和约瑟夫问题详解

    目录 一.环形链表 1.创建结点 2.添加小结点 3.显示循环链表 二.约瑟夫问题 1.问题描述 2.首先确定圈大小及开始位置 3.出圈操作 4.出圈方法完整代码 总结 一.环形链表 1.创建结点 环形链表其实也很好理解,就是将单链表的头和尾连接起来,就形成了环形链表. public class Node { public int data; public Node next; public Node(int data) { this.data = data; } @Override publi

  • C++逆向分析移除链表元素实现方法详解

    目录 前言 题目描述 debug版汇编代码 分析 源代码 前言 这次的题目可以练习到循环加结构体数组和ifelse的大量嵌套. 逆向这种东西就是一个经验的积累,做得多了就会有感觉,这次的分析我会详细写一下如何判断哪里是if哪里是while这种逻辑判断. 题目描述 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 . debug版汇编代码 004E3580  push        ebp  004E3581

  • C++相交链表和反转链表详解

    目录 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点.如果两个链表没有交点,返回 null . 思路 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表. 双指针思路 递归 总结 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点.如果两个链表没有交点,返回 null . 思路 简单来说,就是求两个链表交点节点的 指针. 这里同学们要注意,交点不是数值相等,而是指针相等. 为了方便举例,假设节点

  • Java实现单向链表的基本功能详解

    一.前言 最近在回顾数据结构与算法,有部分的算法题用到了栈的思想,说起栈又不得不说链表了.数组和链表都是线性存储结构的基础,栈和队列都是线性存储结构的应用- 本文主要讲解单链表的基础知识点,做一个简单的入门-如果有错的地方请指正 二.回顾与知新 说起链表,我们先提一下数组吧,跟数组比较一下就很理解链表这种存储结构了. 2.1回顾数组 数组我们无论是C.Java都会学过: 数组是一种连续存储线性结构,元素类型相同,大小相等 数组的优点: 存取速度快 数组的缺点: 事先必须知道数组的长度 插入删除元

  • 深入理解链表的各类操作详解

    链表概述链表是一种常见的重要的数据结构.它是动态地进行存储分配的一种结构.它可以根据需要开辟内存单元.链表有一个"头指针"变量,以head表示,它存放一个地址.该地址指向一个元素.链表中每一个元素称为"结点",每个结点都应包括两个部分:一为用户需要用的实际数据,二为下一个结点的地址.因此,head指向第一个元素:第一个元素又指向第二个元素:--,直到最后一个元素,该元素不再指向其它元素,它称为"表尾",它的地址部分放一个"NULL&qu

  • C语言复杂链表的复制实例详解

    目录 一.题目描述 示例1: 示例2: 示例3: 示例4: 二.思路分析 三.整体代码 总结 一.题目描述 请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null. 示例1: 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]] 示例2: 输

  • python环形单链表的约瑟夫问题详解

    题目: 一个环形单链表,从头结点开始向后,指针每移动一个结点,就计数加1,当数到第m个节点时,就把该结点删除,然后继续从下一个节点开始从1计数,循环往复,直到环形单链表中只剩下了一个结点,返回该结点. 这个问题就是著名的约瑟夫问题. 代码: 首先给出环形单链表的数据结构: class Node(object): def __init__(self, value, next=0): self.value = value self.next = next # 指针 class RingLinkedL

随机推荐