【经典算法】Leetcode.83删除排序链表中的重复元素(Java/C/Python3/Go实现含注释说明,Easy)

  • 标签:链表

题目描述

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

原题:LeetCode 83

思路及实现

方式一:双指针

思路

使用快慢双指针遍历链表,快指针用于遍历链表,慢指针用于指向不重复元素的最后一个位置。当快指针指向的元素与慢指针指向的元素不同时,将慢指针向后移动一位,并将快指针指向的元素赋值给慢指针指向的位置。这样可以保证慢指针之前的元素都是不重复的。

代码实现

Java版本
// 定义链表节点
class ListNode {int val;ListNode next;ListNode(int x) { val = x; }
}public class Solution {public ListNode deleteDuplicates(ListNode head) {if (head == null || head.next == null) {return head;}ListNode slow = head;ListNode fast = head.next;while (fast != null) {if (slow.val != fast.val) {slow.next = fast;slow = slow.next;}fast = fast.next;}// 最后一个不重复元素后面应该为nullslow.next = null;return head;}
}

说明:
代码中定义了一个链表节点类ListNode,并在Solution类中实现了deleteDuplicates方法。首先判断链表是否为空或只有一个节点,若是则直接返回。然后初始化快慢指针,快指针指向头节点的下一个节点。在循环中,当快慢指针指向的元素不同时,将慢指针的next指向快指针,并将慢指针向后移动一位。最后,将最后一个不重复元素的next置为null,返回头节点。

C语言版本
// 定义链表节点
struct ListNode {int val;struct ListNode *next;
};struct ListNode* deleteDuplicates(struct ListNode* head) {if (head == NULL || head->next == NULL) {return head;}struct ListNode *slow = head;struct ListNode *fast = head->next;while (fast != NULL) {if (slow->val != fast->val) {slow->next = fast;slow = slow->next;}fast = fast->next;}slow->next = NULL;return head;
}

说明:
C语言版本的实现与Java版本类似,只是语法上有所差异。

Python3版本
# 定义链表节点
class ListNode:def __init__(self, val=0, next=None):self.val = valself.next = nextclass Solution:def deleteDuplicates(self, head: ListNode) -> ListNode:if not head or not head.next:return headslow = headfast = head.nextwhile fast:if slow.val != fast.val:slow.next = fastslow = slow.nextfast = fast.nextslow.next = Nonereturn head

说明:
Python版本的实现中,使用了类定义链表节点,并实现了deleteDuplicates方法。与Java和C语言版本的逻辑相同。

Golang版本
package mainimport "fmt"// 定义链表节点
type ListNode struct {Val  intNext *ListNode
}func deleteDuplicates(head *ListNode) *ListNode {if head == nil || head.Next == nil {return head}slow := headfast := head.Nextfor fast != nil {if slow.Val != fast.Val {slow.Next = fastslow = slow.Next}fast = fast.Next}slow.Next = nilreturn head
}func main() {// 示例链表: 1->1->2head:= &ListNode{Val: 1}head.Next = &ListNode{Val: 1}head.Next.Next = &ListNode{Val: 2}result := deleteDuplicates(head)// 打印结果链表for result != nil {fmt.Print(result.Val, " ")result = result.Next}
}

说明:
Golang版本的实现中,首先定义了一个ListNode结构体来表示链表节点。然后在deleteDuplicates函数中实现了删除重复元素的功能。最后,在main函数中创建了一个示例链表,并调用deleteDuplicates函数进行处理,最后遍历结果链表并打印。

方式二(递归)

在处理链表删除重复元素的问题时,通过递归的方式能够简洁地表达算法逻辑。以下是方式二的详细解释和示例代码。

思路

对于递归方法,我们需要定义一个递归函数,该函数接受链表的头节点作为参数,并返回处理后的链表的头节点。递归函数的主要任务是判断当前节点是否与其下一个节点重复,并据此决定是继续递归还是删除下一个节点。

  1. 基本情况:如果链表为空(head == null)或只有一个节点(head.next == null),则没有重复元素可删除,直接返回头节点。

  2. 递归情况

    • 如果当前节点head的值与其下一个节点head.next的值相同,说明有重复元素,我们需要删除下一个节点。递归调用deleteDuplicates函数处理head.next,并返回处理后的头节点,此时原head节点将被忽略(因为重复)。
    • 如果当前节点head的值与其下一个节点head.next的值不同,说明没有重复元素,我们保留head节点,并递归处理head.next。将处理后的head.next赋值给head.next,并返回head

代码实现

以下是使用递归方法删除链表重复元素的示例代码,分别用Java、Python和Golang实现。

Java版本
public class ListNode {int val;ListNode next;ListNode(int x) { val = x; }
}public class Solution {public ListNode deleteDuplicates(ListNode head) {if (head == null || head.next == null) {return head;}if (head.val == head.next.val) {return deleteDuplicates(head.next);} else {head.next = deleteDuplicates(head.next);return head;}}
}
C语言

下面是使用C语言实现删除排序链表中重复元素的递归解法:

#include <stdio.h>
#include <stdlib.h>// 定义链表节点结构体
typedef struct ListNode {int val;struct ListNode *next;
} ListNode;// 创建新节点
ListNode* createNode(int val) {ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));newNode->val = val;newNode->next = NULL;return newNode;
}// 递归删除重复元素
ListNode* deleteDuplicates(ListNode* head) {// 基本情况:空链表或只有一个节点,没有重复元素if (head == NULL || head->next == NULL) {return head;}// 如果头节点和下一个节点值相同,递归删除下一个节点if (head->val == head->next->val) {return deleteDuplicates(head->next);}// 如果头节点和下一个节点值不同,递归处理下一个节点,并更新头节点的next指针else {head->next = deleteDuplicates(head->next);return head;}
}// 打印链表
void printList(ListNode* head) {ListNode* current = head;while (current != NULL) {printf("%d ", current->val);current = current->next;}printf("\n");
}// 释放链表内存
void freeList(ListNode* head) {ListNode* current = head;while (current != NULL) {ListNode* temp = current;current = current->next;free(temp);}
}
}

说明
在上面的代码中,createNode 函数用于创建新链表节点,deleteDuplicates 函数是递归删除重复元素的实现,printList 函数用于打印链表,freeList 函数用于释放链表占用的内存。

Python3版本
class ListNode:def __init__(self, val=0, next=None):self.val = valself.next = nextclass Solution:def deleteDuplicates(self, head: ListNode) -> ListNode:if not head or not head.next:return headif head.val == head.next.val:return self.deleteDuplicates(head.next)else:head.next = self.deleteDuplicates(head.next)return head
Golang版本
type ListNode struct {Val  intNext *ListNode
}func deleteDuplicates(head *ListNode) *ListNode {if head == nil || head.Next == nil {return head}if head.Val == head.Next.Val {return deleteDuplicates(head.Next)} else {head.Next = deleteDuplicates(head.Next)return head}
}

复杂度分析

对于递归解法,复杂度分析需要考虑递归调用的次数和递归过程中使用的额外空间。

  • 时间复杂度:O(n),其中n是链表的长度。每个节点最多被访问一次,因此时间复杂度是线性的。
  • 空间复杂度:O(n),其中n是链表的长度。在最坏情况下,当链表中所有节点都重复时,递归的深度将达到n,因此需要额外的栈空间来存储递归调用信息。

总结

以下是针对删除排序链表中重复元素问题的不同方式的对比总结:

方式优点缺点时间复杂度空间复杂度
方式一(双指针迭代)不使用递归,内存占用稳定代码相对复杂,需要处理边界情况O(n)O(1)
方式二(递归)代码简洁,逻辑清晰递归深度可能导致栈溢出,内存占用不稳定O(n)O(n)

相似题目

以下是一些与删除排序链表中重复元素问题相似的题目:

相似题目难度链接
删除排序数组中的重复项简单力扣:26. 删除排序数组中的重复项
删除排序数组中的重复项 II中等力扣:80. 删除排序数组中的重复项 II
删除链表中的节点容易力扣:237. 删除链表中的节点
移除链表元素简单力扣:203. 移除链表元素
合并两个有序链表简单力扣:21. 合并两个有序链表
链表中倒数第k个节点中等力扣:19. 链表中倒数第k个节点

这些题目涉及到了链表、数组的基本操作,包括删除重复项、合并、查找特定节点等,对于理解链表和数组的基本数据结构以及操作非常有帮助。通过解决这些相似题目,可以加深对链表和数组操作的理解,并提升编程技能。

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

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

相关文章

PY32F040单片机产品介绍,LQFP封装,带LCD 驱动器

PY32F040单片机搭载了 Arm Cortex-M0内核&#xff0c;最高主频可达72 MHz&#xff0c;专为高性价比、高可靠性的系统而设计&#xff0c;符合消费市场的基本设计需求。可广泛应用于电机控制、手持设备、PC 外设、以及复杂的数字控制应用等领域。 PY32F040片内集成 UART、I2C、S…

手机空号过滤,提高工作效率

手机空号过滤在多个方面都具有重要的作用。 首先&#xff0c;它对于短信群发商和电话营销商来说至关重要。通过空号过滤&#xff0c;他们可以确保手机号码数据库的准确性和有效性。由于每天都有大量人群因各种原因更换手机号码&#xff0c;导致每个号段中的空号率和手机状态都…

Debian 系统设置SSH 连接时长

问题现象&#xff1a; 通过finalshell工具连接Debian系统远程操作时&#xff0c;总是一下断开一下断开&#xff0c;要反复重新连接 &#xff0c;烦人&#xff01; 解决办法&#xff1a; 找到ssh安装目录下的配置文件&#xff1a;sshd_config vi sshd_config &#xff1a; 找到…

【喜报】科大睿智为武汉博睿英特科技高质量通过CMMI3级评估咨询工作

武汉博睿英特科技有限公司是信息通信技术产品、建筑智慧工程服务提供商。其拥有专注于航空、政府、教育、金融等多行业领域的资深团队&#xff0c;及时掌握最新信息通信应用技术&#xff0c;深刻理解行业业务流程&#xff0c;擅于整合市场优质资源&#xff0c;积极保持与高校产…

STM32 SPI通信

一、SPI总线简介 1.1 SPI总线 串口外设接口&#xff08;Serial Peripheral Interface&#xff0c;SPI&#xff09;总线是一种同步串行外设接口&#xff0c;允许MCU与各种外围设备进行全双工、同步串行通信 SPI总线有四根通信线&#xff1a; ①SCK&#xff08;Serial Clock&a…

并发编程中的各类锁

引言 在并发编程中&#xff0c;锁是一种关键的同步机制&#xff0c;用于控制多个线程对共享资源的访问。不同类型的锁在不同的场景下有着不同的适用性和性能特点。本文将探讨几种常见的锁&#xff0c;包括互斥锁、自旋锁、读写锁、悲观锁和乐观锁&#xff0c;并对它们进行详细总…

On evaluating adversarial robustness of large vision language models - 论文翻译

论文链接&#xff1a;https://arxiv.org/pdf/2305.16934 项目代码&#xff1a;https://github.com/yunqing-me/AttackVLM On evaluating adversarial robustness of large vision language models Abstract1 Introduction2 Related work3 Methodology3.1 Preliminary3.2 Transf…

linux的压缩与备份

一、打包 格式&#xff1a;tar -参数 <打包文件名> <打包的目标> 作用&#xff1a;将文件或者目录打包 重要参数&#xff1a;-f 使用归档文件&#xff0c;一定要加上这个参数 -c 新建打包文件 -x 解包文件 -t 可以不用解包就能查看包文件内容 -v 打包和解包时显…

JVM的垃圾回收机制(GC机制)

在Java代码运行的过程中&#xff0c;JVM发现 某些资源不需要再使用的时候&#xff0c;就会自动把资源所占的内存给回收掉&#xff0c;就不需要程序员自行操作了。“自动回收资源”就是JVM的“垃圾回收机制”&#xff0c;“垃圾回收机制”也称"GC机制"。 对于Java代码…

Redux(类似vue中的vuex和pina)

什么是Redux Redux 是React最常用的集中状态管理工具&#xff0c;类似于Vue中的Pinia&#xff08;Vuex&#xff09;&#xff0c;可以独立于框架运行 作用&#xff1a;通过集中管理的方式管理应用的状态 为什么要使用Redux&#xff1f; 独立于组件&#xff0c;无视组件之间的层…

C语言指针进阶_字符指针、指针数组、数组指针、函数指针等的介绍

文章目录 前言一、字符指针二、指针数组三、 数组指针1. 数组名和 & 数组名2. 数组指针3. 数组指针解引用 四、数组指针的使用二维数组的传参说明数组指针使用小测验 五、数组传参和指针传参1. 一维数组传参总结2. 二维数组传参总结3. 一级指针传参4. 二级指针传参 六、函数…

MR混合现实实训系统为农学情景实训教学演练

MR混合现实实训系统在农学课堂上的应用具有很大的潜力。它能够为学生提供一种全新的学习方式&#xff0c;使他们能够更直观地了解和理解农业实践。 首先&#xff0c;MR混合现实技术可以模拟真实环境&#xff0c;使学生能够更深入地了解各种农作物生长的过程和环境因素。通过模拟…

java案例-服务端与客户端(传输对象)

需求 代码 SysUser 用户类Operation 操作类Client 客户端Server 服务端ServerReaderThread 服务端线程类 SysUser 用户类 需要实现Serializable 方便序列化&#xff0c;传输对象 public class SysUser implements Serializable {private String username;private String passwo…

kerberos-hive-dbeaver问题总结

一、kerberos安装windows客户端 1、官方下载地址 http://web.mit.edu/kerberos/dist/ 2、环境变量配置 下载msi安装包&#xff0c;无需重启计算机&#xff0c;调整环境变量在jdk的前面&#xff0c;尽量靠前&#xff0c;因为jdk也带了kinit、klist等命令 C:\Program Files\…

攻防演练作为红方:postgresql提权之UDF提权 ,及其好用的工具

在 PostgreSQL 中&#xff0c;用户定义的函数&#xff08;UDF&#xff09;提权是一种常见的提升权限的方法&#xff0c;尤其是当你已经获得了数据库的访问权限但需要更高级别系统权限时。UDF 提权涉及在数据库中创建或使用函数&#xff0c;这些函数可以执行系统级别的命令&…

【Node.js工程师养成计划】之原生node开发web服务器

一、使用node创建http服务器 var http require(http);// 获取到服务器实例对象 var server http.createServer() server.listen(8080, function() {console.log(http://127.0.0.1:8080); })server.on(request, function(req, res){console.log(request);res.write(6666666688…

如何利用 GPT 自我提高写作能力

GPT革命&#xff1a;如何用AI技术重新定义写作 介绍 在我们的数字时代&#xff0c;了解自我提高写作的必要性至关重要。 随着 GPT 的兴起&#xff0c;我们正在见证书写的变革时代。 这篇扩展文章深入探讨了 GPT 如何显着提高写作技能。 拥抱未来&#xff1a; 人工智能时代的写…

Maven介绍 主要包括Maven的基本介绍,作用,以及对应的Maven模型,可以对Maven有一个基本的了解

1、Maven介绍 1.1 什么是Maven Maven是Apache旗下的一个开源项目&#xff0c;是一款用于管理和构建java项目的工具。 官网&#xff1a;https://maven.apache.org/ Apache 软件基金会&#xff0c;成立于1999年7月&#xff0c;是目前世界上最大的最受欢迎的开源软件基金会&…

Elasticsearch实现hotel索引库自动补全、拼音搜索功能

Elasticsearch实现hotel索引库自动补全、拼音搜索功能 在这里边我们有两个字段需要用拼音分词器&#xff0c;一个name字段&#xff0c;一个all字段。 然后我们还需要去实现自动补全&#xff0c;而自动补全对应的字段必须使用completion类型。目前我们酒店里面所有的字段都采用的…

【SpringBoot】00 Maven配置及创建项目

一、Maven配置 1、下载Maven 进入官网下载&#xff1a;Maven – Welcome to Apache MavenMaven – Download Apache Maven 本文以最新版为例&#xff0c;可按需选择版本 Maven – Welcome to Apache Maven 2、解压下载好的安装包 将安装包解压到自己设置的空文件夹中 3、…