【算法刷题之链表篇(1)】

目录

  • 1.leetcode-82. 删除排序链表中的重复元素 II
    • (1)题目描述
    • (2)方法及思路(一次遍历)
    • (3)代码实现
  • 2.leetcode-19. 删除链表的倒数第 N 个结点
    • (1)题目描述
    • (2)方法一:双指针
    • (3)方法二:计算链表长度(最直观)
    • (4)方法三:栈
  • 3.leetcode-83. 删除排序链表中的重复元素
    • (1)题目描述
    • (2)方法及思路(一次遍历)
    • (3)代码实现
  • 4.leetcode-86. 分隔链表
    • (1)题目描述
    • (2)方法及思路(模拟)
    • (3)代码实现
  • 5.leetcode-25. K 个一组翻转链表(较难)
    • (1)题目描述
    • (2)方法及思路(模拟)
    • (3)代码实现

1.leetcode-82. 删除排序链表中的重复元素 II

(1)题目描述

给定一个已排序的链表的头 head , 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
在这里插入图片描述

(2)方法及思路(一次遍历)

1.我们从指针 prev 指向链表的哑节点,随后开始对链表进行遍历。
2.如果当前 cur与 cur.next对应的元素相同,那么我们就需要将 cur 以及所有后面拥有相同元素值的链表节点全部删除。
3.我们记下这个元素值 ,随后不断将 cur从链表中移除
4.如果cur与cur->next对应的元素不相同,则将prev指向cur所在位置,cur继续往下找。
5.当遍历完整个链表之后,我们返回链表的的哑节点的下一个节点 dummy.next即可。
注意:哑节点可以不用考虑head就被删的特殊情况

(3)代码实现

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head==NULL)
        {
            return NULL;
        }
        ListNode* newnode=new ListNode(0);
        ListNode* prev=newnode;
        prev->next=head;
        ListNode* cur=head;
        while(cur!=NULL&&cur->next!=NULL)
        {
            if(cur->val==cur->next->val)
            {
                int val=cur->val;
                while(cur != NULL && cur->val == val){
                    cur = cur->next;
                }
                prev->next=cur;
            }
            else
            {
                prev=cur;
                cur=cur->next;
            }
        }
        return newnode->next;
    }
};

2.leetcode-19. 删除链表的倒数第 N 个结点

(1)题目描述

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
在这里插入图片描述

(2)方法一:双指针

思路
1.先定义一个first指针,由于要删掉倒数第n个节点,所以可以让first指针先走n步。
2.当first走完,在定义一个second指针,此时两指针一起走,当first走到尾部时,second就走到了要删掉的节点的前一位。
3.将second所在节点指向它下一位的下一位,即可删掉
注意点:first和second从哪里开始走?first的终止条件是哪里?
first从head出发,终止条件是走到空停止,
而对于second与第一题中一样,引入哑节点,second从此处开始走

代码实现

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* newnode=new ListNode(0,head);
        ListNode* cur=head;
        while(n>0)
        {
            cur=cur->next;
            n--;
        }
        ListNode* prev=newnode;
        while(cur)
        {
            prev=prev->next;
            cur=cur->next;
        }
        prev->next=prev->next->next;
        return newnode->next;
    }
};

(3)方法二:计算链表长度(最直观)

思路:
一种容易想到的方法是,我们首先从头节点开始对链表进行一次遍历,得到链表的长度 L。随后我们再从头节点开始对链表进行一次遍历,当遍历到第 L−n+1 个节点时,它就是我们需要删除的节点。
代码实现

class Solution {
public:
    int getLength(ListNode* head) {
        int length = 0;
        while (head) {
            ++length;
            head = head->next;
        }
        return length;
    }

    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);
        int length = getLength(head);
        ListNode* cur = dummy;
        for (int i = 1; i < length - n + 1; ++i) {
            cur = cur->next;
        }
        cur->next = cur->next->next;
        ListNode* ans = dummy->next;
        delete dummy;
        return ans;
    }
};

(4)方法三:栈

思路:
我们也可以在遍历链表的同时将所有节点依次入栈。根据栈「先进后出」的原则,我们弹出栈的第 n 个节点就是需要删除的节点,并且目前栈顶的节点就是待删除节点的前驱节点。这样一来,删除操作就变得十分方便了。(也就是只要找到就直接操作)
代码实现

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(0, head);
        stack<ListNode*> stk;
        ListNode* cur = dummy;
        while (cur) {
            stk.push(cur);
            cur = cur->next;
        }
        for (int i = 0; i < n; ++i) {
            stk.pop();
        }
        ListNode* prev = stk.top();
        prev->next = prev->next->next;
        ListNode* ans = dummy->next;
        delete dummy;
        return ans;
    }
};

3.leetcode-83. 删除排序链表中的重复元素

(1)题目描述

给定一个已排序的链表的头 head ,删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
在这里插入图片描述

(2)方法及思路(一次遍历)

思路:具体地,我们从指针 cur\textit{cur}cur 指向链表的头节点,随后开始对链表进行遍历。如果当前 cur 与 cur.next 对应的元素相同,那么我们就将 cur.next 从链表中移除;否则说明链表中已经不存在其它与 cur 对应的元素相同的节点,因此可以将 cur 指向 cur.next。

(3)代码实现

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if (!head) {
            return head;
        }

        ListNode* cur = head;
        while (cur->next) {
            if (cur->val == cur->next->val) {
                cur->next = cur->next->next;
            }
            else {
                cur = cur->next;
            }
        }

        return head;
    }
};

4.leetcode-86. 分隔链表

(1)题目描述

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。
在这里插入图片描述

(2)方法及思路(模拟)

思路
直观来说我们只需维护两个链表 small 和 large 即可,small 链表按顺序存储所有小于 x 的节点,large 链表按顺序存储所有大于等于 x的节点。遍历完原链表后,我们只要将 small 链表尾节点指向 large 链表的头节点即能完成对链表的分隔。
1.先定义两个哨兵位smallHead和largeHead这样做的目的是为了更方便地处理头节点为空的边界条件。
2.遍历链表,找出小的储存进small,大的储存进large
3.合并链表时注意large节点的指向,并注意要删除largeHead

(3)代码实现

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        ListNode* small=new ListNode(0);
        ListNode* smallHead=small;
        ListNode* large=new ListNode(0);
        ListNode* largeHead=large;
        while(head!=NULL)
        {
            if(head->val<x)
            {
                small->next=head;
                small=small->next;
            }
            else
            {
                large->next=head;
                large=large->next;
            }
            head=head->next;
        }
        large->next=NULL;
        small->next=largeHead->next;
        delete largeHead;
        return smallHead->next;
    }
};

5.leetcode-25. K 个一组翻转链表(较难)

(1)题目描述

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
在这里插入图片描述

(2)方法及思路(模拟)

思路
1.首先按照k来进行分组,每k个会重新是一个head。
2.然后对每k个数进行反转链表。
3.反转完链表,要注意头和尾与前后的相连,所以在实现反转链表的函数中还要返回头和尾
4.遍历到最后时,如果个数少于k就直接返回
在这里插入图片描述

(3)代码实现

首先先实现部分链表反转部分

    pair<ListNode*,ListNode*> myReserve(ListNode* head,ListNode* tail)
    {
        ListNode* prev=tail->next;
        ListNode* p=head;
        while(prev!=tail)
        {
            ListNode* nex=p->next;
            p->next=prev;
            prev=p;
            p=nex;
        }
        return {tail,head};
    }

总体部分实现
1.在每次实现完注意要有个prev在head前,一开始就是哨兵位,prev用来与反转完的部分进行连接。prev更新的位置即使在tail处(新head前)
2.还要定义一个next在反转链表之前,也就是在找到新tail时定义在他的后面,用于反转部分尾部的连接

ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* hair=new ListNode(0);
        hair->next=head;
        ListNode* pre=hair;
        while(head)
        {
            ListNode* tail=pre;
               for (int i = 0; i < k; ++i) {
                tail = tail->next;
                if (!tail) {
                    return hair->next;
                }
            }
            ListNode* next=tail->next;
            pair<ListNode*,ListNode*> result=myReserve(head,tail);
            head=result.first;
            tail=result.second; 
            pre->next=head;
            tail->next=next;
            pre=tail;
            head=tail->next;
        }
        return hair->next;
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rabbitmq容器启动后修改连接密码

1、进入容器 docker exec -it rabbitmq bash 2、查看当前用户列表 rabbitmqctl list_users 3、修改密码 rabbitmqctl change_password [username] ‘[NewPassword]’ 4、修改后退出容器 ctrlpq 5、退出容器后即可生效&#xff0c;不需要重启容器

C++新经典07--auto、头文件防卫、引用与常量

auto的使用 严格来讲&#xff0c;在C语言中&#xff0c;如果某个函数中需要用到一些局部变量&#xff0c;那么局部变量都会集中定义在函数开头&#xff0c;而在C中不必遵循这样的规则&#xff0c;随时用随时定义即可。当然&#xff0c;作用域一般就是从定义的地方开始到该函数…

免费开源的vue+express搭建的后台管理系统

此项目已开源 前端git地址&#xff1a;exp后台管理系统前端: exp后台管理系统前端 后端git地址&#xff1a;express后台管理系统: express后台管理系统 安装运行 npm i yarn i 前端: npm run dev | yarn dev 后端: npm run start | yarn start 主要技术栈 前端后端名称版本名…

循环神经网络RNN完全解析:从基础理论到PyTorch实战

目录 一、循环神经网络全解1.1 什么是循环神经网络网络结构工作原理数学模型RNN的优缺点总结 1.2 循环神经网络的工作原理RNN的时间展开数学表述信息流动实现示例梯度问题&#xff1a;梯度消失和爆炸总结 1.3 循环神经网络的应用场景文本分析与生成1.3.1 自然语言处理1.3.2 机器…

Flutter实战·第二版-第三章 基础组件笔记

第三章&#xff1a;基础组件 3.1文本及样式 3.1.1 Text Text("Hello world",textAlign: TextAlign.left, );Text("Hello world! Im Jack. "*4,maxLines: 1,overflow: TextOverflow.ellipsis, );Text("Hello world",textScaleFactor: 1.5, );3.1…

WebDriver API及对象识别技术

html页面的iframe的切换 定位到客户管理 新增客户 会无法定位到新增客户&#xff0c;因为在另外一个iframe框架之中。 iframe是html中的框架标签&#xff0c;表示文档中可以嵌入文档&#xff0c;或者说是浮动的框架。在selenium中iframe同样如此&#xff0c;如果驱动器对…

TCP定制协议,序列化和反序列化

目录 前言 1.理解协议 2.网络版本计算器 2.1设计思路 2.2接口设计 2.3代码实现&#xff1a; 2.4编译测试 总结 前言 在之前的文章中&#xff0c;我们说TCP是面向字节流的&#xff0c;但是可能对于面向字节流这个概念&#xff0c;其实并不理解的&#xff0c;今天我们要介…

【C# 基础精讲】LINQ to Objects查询

LINQ to Objects是LINQ技术在C#中的一种应用&#xff0c;它专门用于对内存中的对象集合进行查询和操作。通过使用LINQ to Objects&#xff0c;您可以使用统一的语法来查询、过滤、排序、分组等操作各种.NET对象。本文将详细介绍LINQ to Objects的基本概念、常见的操作和示例&am…

代码随想录算法训练营第四十一天 | 343. 整数拆分,96.不同的二叉搜索树

代码随想录算法训练营第四十一天 | 343. 整数拆分&#xff0c;96.不同的二叉搜索树 343. 整数拆分动态规划贪心 96.不同的二叉搜索树 343. 整数拆分 题目链接 视频讲解 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff…

使用Druid解析SQL,获取SQL中所有使用的表

一、sqlParse组成 Druid SQL Parser分三个模块&#xff1a; - Parser - AST - Visitor 1.1 Parser parser是将输入文本转换为ast&#xff08;抽象语法树&#xff09;&#xff0c;parser有包括两个部分&#xff0c;Parser和Lexer&#xff0c;其中Lexer实现词法分析&#x…

uniapp 微信小程序 绘制海报,长按图片分享,保存海报

uView UI 2.0 dcloud 插件市场地址 弹窗海报源码 <template><!-- 推荐商品弹窗 --><u-popup :show"haibaoShow" mode"center" round26rpx z-index10076 bgColortransparent safeAreaInsetTop close"goodsclose"><image …

chatglm2-6b模型在9n-triton中部署并集成至langchain实践 | 京东云技术团队

一.前言 近期&#xff0c; ChatGLM-6B 的第二代版本ChatGLM2-6B已经正式发布&#xff0c;引入了如下新特性&#xff1a; ①. 基座模型升级&#xff0c;性能更强大&#xff0c;在中文C-Eval榜单中&#xff0c;以51.7分位列第6&#xff1b; ②. 支持8K-32k的上下文&#xff1b…

excel条件格式:不同组对应位置对比标记

问题描述 下图中有两组数据&#xff0c;想要对比两个对应位置的数据并标记 条件格式 选中其中一个单元格&#xff0c;条件格式->新建规则 使用公式确定要设置格式的单元格&#xff0c;自定义需求 格式化剩余同样标准的单元格

MySQL | JDBC连接数据库

一、什么是JDBC 概念&#xff1a; JDBC&#xff0c;即Java Database Connectivity&#xff0c;java数据库连接。是一种用于执行SQL语句的Java API&#xff0c;它是Java中的数据库连接规范。这个API由 java.sql.*,javax.sql.* 包中的一些类和接口组成&#xff0c;它为Java开发…

SpringBoot复习:(56)使用@Transactional注解标记的方法的执行流程

首先&#xff0c;如果在某个类或某个方法被标记为Transactional时&#xff0c;Spring boot底层会在创建这个bean时生成代理对象&#xff08;默认使用cglib) 示例&#xff1a; 当调用studentService的addStudent方法时&#xff0c;会直接跳到CglibAopProxy类去执行intercept方…

Edge浏览器免费使用GPT3.5

搜索sider,安装Sidebar插件 注册账号即可每天免费使用30次。 Sider: ChatGPT侧边栏,GPT-4, 联网, 绘图

30.Netty源码服务端启动主要流程

highlight: arduino-light 服务端启动主要流程 •创建 selector •创建 server socket channel •初始化 server socket channel •给 server socket channel 从 boss group 中选择一个 NioEventLoop •将 server socket channel 注册到选择的 NioEventLoop 的 selector •…

机器学习深度学习——transformer(机器翻译的再实现)

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位即将上大四&#xff0c;正专攻机器学习的保研er &#x1f30c;上期文章&#xff1a;机器学习&&深度学习——自注意力和位置编码&#xff08;数学推导代码实现&#xff09; &#x1f4da;订阅专栏&#xff1a;机器…

Flink 数据集成服务在小红书的降本增效实践

摘要&#xff1a;本文整理自实时引擎研发工程师袁奎&#xff0c;在 Flink Forward Asia 2022 数据集成专场的分享。本篇内容主要分为四个部分&#xff1a; 小红书实时服务降本增效背景Flink 与在离线混部实践实践过程中遇到的问题及解决方案未来展望 点击查看原文视频 & 演…

[oneAPI] 手写数字识别-LSTM

[oneAPI] 手写数字识别-LSTM 手写数字识别参数与包加载数据模型训练过程结果 oneAPI 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517 Intel DevCloud for oneAPI&#xff1a;https://devcloud.intel.com/oneapi/get_started/aiAnalyticsToolk…
最新文章