关于链表的题目—leetcode

2023-10-27

第一题:删除链表中的指定节点

问题描述:

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

示例 1:

输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:

输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

题目接口:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* deleteNode(struct ListNode* head, int val){

}

问题解答思路: 

这道题的意思就是要删除链表中的值等于val的节点,但是这道题需要考虑两种情况。

第一种情况就是删除头节点,第二种情况就是删除不是头节点的情况。这两种情况可是不一样的,假如我们把这两种情况混为一谈这道题是不一定能通过的。所以我们要分两种情况来解决这道题。

解法1:分头节点与一般节点两种情况

struct ListNode* deleteNode(struct ListNode* head, int val){
        while(head!=NULL&&head->val==val){//处理头节点的问题
            struct ListNode*temp = head;
            head = head->next;//移动head删掉头节点
            free(temp);
        }
        struct ListNode*temp = head;
        struct ListNode*cur = head->next;//因为头节点已经处理完了,所以再让cur指向head是没有意义的,所以让cur指向第二个节点
        while(cur){
            if(cur->val==val){
             temp->next = cur->next;//删除值为val的节点
             cur = cur->next;//再次移动cur
            }
            else{
                temp = cur;//记录cur的原来位置
                cur = cur->next;//cur向下一位移动
            }

        }
return head;
}

解法2:加一个节点在头节点前面

思路:既然第一种解法要我们处理两种情况,那我们可不可以把这两种解法换成一种解法呢?当然可以,只要我们人为的创建一个节点就可以将将头节点的情况去掉了。

虚拟头节点法:

struct ListNode* deleteNode(struct ListNode* head, int val){
    struct ListNode* dumy = (struct ListNode*)malloc(sizeof(struct ListNode));//使用malloc搞出来一个虚拟节点。
    struct ListNode* cur = head;
    struct ListNode* temp = dumy;
    dumy->next = head;//将dump连接在head的前面,是dumy成为一个头节点
    while(cur){//第一种方法中的普通节点处理法,这次就要从head开始删除了。
        if(cur->val==val){
            temp->next = cur->next;
            cur = cur->next;
            temp = cur;

        }
        else{
            temp = cur;
            cur = cur->next;
        }

    }
head = dumy->next;//返回值是dumy->next。这一点要注意
free(dumy);//释放掉dumy,防止内存泄漏
return head;//返回头节点。

}

解法三:尾插法

对于愚笨的我来说,这种方法是我最难理解的,那我就在这里重点讲解一下吧。

首先来看一下代码:

尾插法代码:

struct ListNode* deleteNode(struct ListNode* head, int val){
    struct ListNode* cur  = head;
    struct ListNode* tail = NULL;
    struct ListNode* newnode = NULL;
    while(cur){
        if(cur->val!=val){
            if(tail == NULL){
                tail =newnode = cur;
                
            }
            else{
                tail->next = cur;
                tail = tail->next;
               
            }
            cur = cur->next;
            tail->next = NULL;
        }
        else{
            struct ListNode*  del = cur;
            cur = cur->next;
            free(del);
        }
       
         
    }
    return newnode;

}

尾插法解法过程演示:

首先我们要明确的是,不论这道题怎么写这道题都有三种情况要处理。即:删除头节点,删除中间节点,删除尾节点。

1.删除头节点:

假如我们的链表是:-3->5->99,要删除的值是-3,也就是要删除头节点

 现在我们看看代码是如何走的:下面代码是删除头节点时的执行代码

 struct ListNode* cur  = head;
    struct ListNode* tail = NULL;
    struct ListNode* newnode = NULL;
 else{
            struct ListNode*  del = cur;
            cur = cur->next;
            free(del);
        }

这段代码执行以后:

tail,newnode,cur三者与链表的关系就变成这样了:

然后我们就不用删除头节点了,剩下的节点的处理方式就是下面代码:

 struct ListNode* cur  = head;
    struct ListNode* tail = NULL;
    struct ListNode* newnode = NULL;
    while(cur){
        if(cur->val!=val){
            if(tail == NULL){
                tail =newnode = cur;
                
            }
            else{
                tail->next = cur;
                tail = tail->next;
               
            }
            cur = cur->next;
            tail->next = NULL;
        }

现在,因为tail节点指向空,cur->val!=val。所以执行第二个if语句。

但是此时tail还是要与cur指向的下一个元素有联系。其实这也可以把tail看作是cur的一个拷贝,既然是拷贝tail指向的下一个节点当然就是cur指向的下一个节点了。

代码

  cur = cur->next;
  tail->next = NULL;

 再来看看这一段代码的示意图:

在这里可以看到在执行了cur=cur->next的操作以后,将tail的next置空的操作。这是要特别注意的一点。因为这样的操作可以避免野指针的问题。当然还有一点需要注意的就是这两个代码执行顺序的问题。如果先执行tail->next = NULL的操作,再执行cur = cur->next的操作将会导致栈溢出的问题。原因很简单,因为tail与cur一开始指向的是同一块空间,假如先置空tail的next,cur将找不到自己的next。 

最后,执行以下代码:

else{
       tail->next = cur;
       tail = tail->next;
            }
            cur = cur->next;
            tail->next = NULL;

 

 最后再返回newnode,就得到我们想要得到的结果了。

return newnode;

其它的情况这个代码也是可以过的,在这里就不啰嗦了。 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于链表的题目—leetcode 的相关文章

  • 使用frp工具实现内网穿透以及配置多个ssh和web服务

    frp简介 FRP 项目地址 https github com fatedier frp blob master README zh md frp 是一个可用于内网穿透的高性能的反向代理应用 支持 tcp udp 协议 为 http 和 h
  • qt中的toUtf8, toLatin1, Local8bit, toUcs4

    1 首先说下字符集 gb18030字符集兼容了gbk字符集 以两个字节表示一个文字 windows系统可能使用的就是这两种的一种 unicode字符集以2个或以上的字节表示一个汉字 通用字符集 Universal Character Set
  • Windows操作系统安全加固基线检测脚本

    一 背景信息 在我们的安全运维工作中经常需要进行安全基线配置和检查 所谓的安全基线配置就是系统的最基础的安全配置 安全基线检查涉及操作系统 中间件 数据库 甚至是交换机等网络基础设备的检查 面对如此繁多的检查项 自动化的脚本可以帮助我们快速

随机推荐

  • 树的遍历(bfs+递归)

    题目描述 一个二叉树 树中每个节点的权值互不相同 现在给出它的后序遍历和中序遍历 请你输出它的层序遍历 输入描述 第一行包含整数 N 表示二叉树的节点数 第二行包含 N 个整数 表示二叉树的后序遍历 第三行包含 N个整数 表示二叉树的中序遍
  • Docker容器占用过多C盘空间问题解决方案

    Docker容器占用过多C盘空间问题解决方案 简介 Docker 是一个开源的容器化平台 它能够将应用程序及其依赖项打包成一个独立的 可移植的容器 然而 在使用 Docker 过程中 有时会遇到C盘空间不足的问题 这是因为默认情况下 Doc
  • cpu cache一致性和内存屏障机制

    1 cache 局部性原理 引入 Cache 的理论基础是程序局部性原理 包括时间局部性和空间局部性 即最近被CPU访问的数据 短期内CPU 还要访问 时间 被 CPU 访问的数据附近的数据 CPU 短期内还要访问 空间 因此如果将刚刚访问
  • Spring采用properties配置多个数据库

    在一个项目中有这样的需求 上海和武汉采用不同的系统 每个系统都有自己的数据库 但是在上海的系统需要访问武汉的数据库 这就要在项目中配置两个数据源 下面是我给的SSH采用properties配置数据源的方法 1 要有两个properties文
  • Faster R-CNN网络架构详解和TensorFlow Hub实现(附源码)

    文章目录 一 RPN网络 1 RPN网络简介 2 backbone网络简介 二 Faster R CNN网络架构 1 Faster R CNN网络简介 2 基于TensorFlow Hub实现Faster R CNN 前言 Faster R
  • 1089 狼人杀-简单版 (20 分)

    题目 题目链接 题解 思维 首先我们要明确这类问题不用计算机 我们会怎么去做 显然是推矛盾吧 就是假设哪些是狼人 哪些说了假话等等 根据每个人说的话推出矛盾就说明假设不合理 反之正确 既然要推出矛盾就需要找到一些条件 如果推的过程中发现与条
  • 使用UncaughtExceptionHandler捕获运行时异常

    前面我们知道Exceptions分为可检查异常 checked exceptions 和运行时异常 runtime exception 具体参照文章Java异常处理手册和最佳实践 对于可检查异常 我们必须对它进行处理 要么捕获要么在方法上使
  • 【Grub & Grub2】万能优盘启动盘 (WinPE、LinuxPE)-- 方法1 U盘三分区法(不推荐,供参考)

    由于工作需要 经常使用Windows和Linux双系统 系统使用过程中 个人涉及到的开发软件过多 光基于Eclipse的IDE就有好几个 经常过度安装软件 有时会越来越庞大 越来越不稳定 定期要重新安装配置 但是又不想重头安装 基本软件最好
  • Redis基础

    导航 黑马Java笔记 踩坑汇总 JavaSE JavaWeb SSM SpringBoot 瑞吉外卖 SpringCloud SpringCloudAlibaba 黑马旅游 谷粒商城 目录 1 简介 1 1 环境准备 1 1 1 Redi
  • 使用nssm工具将ES、Kibana、Logstash或者其他.bat文件部署为Windows后台服务的方法

    使用NSSM工具安装bat文件为Windows服务 nssm是一个可以把bat批处理文件部署为Windows服务的小工具 例如很多 net项目可能还是在Windows服务器上面跑的 但是很多组件只提供了 bat文件 例如elk三件套 或者后
  • 【王道考研 操作系统】【第二章】进程同步、进程互斥的实现方法 软件&硬件 优点&缺点 信号量机制

    目录 第二章 9 进程同步 进程互斥 9 1 进程同步 9 2 进程互斥 9 2 1 实现过程 9 2 2 实现互斥须遵循的 原则 9 2 3 软件实现方法 9 2 4 硬件实现方法 10 信号量机制 10 1 整型信号量 10 2 记录型
  • 【华为OD统一考试B卷

    在线OJ 已购买本专栏用户 请私信博主开通账号 在线刷题 运行出现 Runtime Error 0Aborted 请忽略 华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一
  • MATLAB R2023a完美激活版(附激活补丁)

    MATLAB R2023a是一款面向科学和工程领域的高级数学计算和数据分析软件 它为Mac用户提供了强大的工具和功能 用于解决各种复杂的数学和科学问题 以下是MATLAB R2023a Mac的一些主要特点和功能 软件下载 MATLAB R
  • 【自用】3.测试框架TestNG

    1 TestNG基本介绍 2 注解 2 1 Test package com course testng import org testng annotations Test public class BasicAnnotation 最基本
  • 为什么GPU训练网络还不如CPU快

    为什么GPU训练网络还不如CPU快 当网络规模较小的时候 GPU是无法体现出计算上的优势的 可能不光没有加速效果 反而还不如CPU训练的快 只要加大网络规模 当网络足够大的时候 GPU才能显示出它的加速效果 Pytorch官网的这篇tuto
  • 在国内怎么使用谷歌Chrome浏览器,为什么我的谷歌浏览器进去就加载失败

    START 你是不是经常听谁谁说 哎呀 你用的什么浏览器 这么laji 好慢哟 哎 我给你推荐个神器谷歌浏览器 用着贼爽 然后 你就想回去马上就下载 这不我也下载了 然后就出事了 下面跟着我的步伐一起看看吧 一 当你如获至宝的在搜索框输入关
  • 根据id进行数组的去重

    一开始用 New set 但是这种方式只对 1 2 2 3 4 这种形式的数组生效 对数组里面全是对象的话就不生效了 所以取数组里面每个对象对应的id值进行filter处理 如下 aaa 二级评论数组去重 const idMap retur
  • Servlet生命周期与工作原理

    Servlet生命周期分为三个阶段 1 初始化阶段 调用init 方法 2 响应客户请求阶段 调用service 方法 3 终止阶段 调用destroy 方法 Servlet初始化阶段 在下列时刻Servlet容器装载Servlet 1 S
  • 时间轮在Netty、Kafka中的应用

    时间轮 概述 时间轮是一个高性能 低消耗的数据结构 它适合用非准实时 延迟的短平快任务 例如心跳检测 在Netty Kafka Zookeeper中都有使用 时间轮可通过时间与任务存储分离的形式 轻松实现百亿级海量任务调度 Netty中的时
  • 关于链表的题目—leetcode

    第一题 删除链表中的指定节点 问题描述 给定单向链表的头指针和一个要删除的节点的值 定义一个函数删除该节点 返回删除后的链表的头节点 示例 1 输入 head 4 5 1 9 val 5 输出 4 1 9 解释 给定你链表中值为 5 的第二