图解 LeetCode 算法汇总——链表
本文首发公众号:小码A梦
一般数据主要存储的形式主要有两种,一种是数组,一种是链表。数组是用来存储固定大小的同类型元素,存储在内存中是一片连续的空间。而链表就不同于数组。链表中的元素不是存储在内存中可以是不连续的空间。
链表主要有两个元素:结点和指针。结点是存储数据,指针是指向下一个结点数据。
链表的有几个特点:
- 不必按顺序存储数据,使用指针关联各个结点的数据。
- 插入数据时间复杂度O(1)。
- 单链表查询时间复杂度为O(n)。
JDK 链表源码
JDK 很多地方用到了链表,这里举例两个:HashMap 和 LinkedList。
HashMap
HashMap 基于数组 + 链表/红黑树的数据结构,其中链表用 Node 表示。主要存储数据和指向下一个结点的指针,源码如下所示。
//HashMap Node 部分源码
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
}
以上蓝色的 Node 结点表示一个链表结点。
LinkedList
LinkedList 本身就是一个双链表,有前置指针和后置指针。
//LinkedList 部分源码
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
LeetCode 题解
LeetCode 有很多链表的题目,选取了几种比较典型的链表,面试的时候也经常会问到。
206.反转链表(简单)
题目描述
解法
链表结点不变,将指针方向反转。如果只是在一个链表的上操作,每次都需要遍历结点,比较繁琐。所以添加一个空链表 pre。pre 表示将指针向后,改成向前。比如 1 -> 2 变成 2 -> 1,先将 1 放在新的链表上,然后再将 2 放入新的链表,并指向 1。如下图所示:
总结一下解决步骤:
- 设置一个空链表pre
- 遍历链表,每次先将链表的next,赋值给一个新的链表。
- 链表的next指向pre。
- 当前链表赋值给pre。
- 继续遍历next链表
整理好解题思路后,根据解题写出以下代码:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode pre = null;
while(cur != null) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
19.删除链表的倒数第 N 个结点(中等)
题目描述
解法
类似链表删除结点,都是修改指针指向的结点,比如删除 4 结点,就需要将 4 节点之前的结点的指针,指向 4 的下一个结点。
解题的关键点就是找到结点的位置,并修改指针的指向,使用 node.next = node.next.next
即可修改指针的指向。找到结点的位置需要找到链表的长度,然后遍历链表,找到对应结点并修改指针。如果移除的是首结点,就找不到上一个结点,所以需要设置一个伪结点。总结一下解题思路:
- 创建伪结点,next 指向链表。首结点就是一个为伪结点。
- 遍历链表获取链表长度。
- 获取结点位置就是 L-n+1。
- 遍历链表,找到前一个结点的位置,也就是 L-n的结点的 next 指向 next.next.返回伪结点的 next 结点。
有了思路,写代码就快了:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode cur = head;
int length = 0;
while(cur != null) {
cur = cur.next;
length++;
}
int index = 1;
int sub = length - n + 1;
ListNode dummy = new ListNode(1,head);
cur = dummy;
while(cur != null) {
if(index == sub) {
cur.next = cur.next.next;
break;
}
cur = cur.next;
index++;
}
return dummy.next;
}
}
141.环形链表(简单)
题目描述
解法
环形链表表示链表的某个结点可以通过连续 next 指针再次被遍历到。所以需要做个查重的功能,如果存在重复的结点,就说明链表是一个环形链表。而查重使用 hash 表即可,汇总一下解题思路:
- 遍历结点,将结点添加到 hash 表中。
- 如果在添加数据时发现结点已存在,说明链表是环形链表。
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null) {
if (!set.add(head)) {
return true;
}
head = head.next;
}
return false;
}
}
set 的 add 的方法判断是否存在相同的元素,其实是使用 HashMap 的 put 方法,返回之前的数据,如果之前数据不存在就返回 null。
21.合并两个有序链表(简单)
题目描述
解法
单链表查找结点是需要一个一个往后指针找结点,合并链表的,如果在原来的基础上添加结点就需要不断的遍历结点,合并的链表使用一个新的链表存储。首先找到最小的数据,然后结点存储到新链表,同时断开结点的 next。如下图所示。
先找到最小的结点,然后新链表(蓝色部分)指向小的结点,然后断开 next 指针。之后的重复类似的步骤。
需要考虑到如果某个链表遍历结束了,但是其他链表还有值,就需要遍历非空链表的数据了,最终总结题解的步骤:
- 定义一个新的链表 node,存储合并的链表。
- 找到最小的结点,新的链表的next 指向新的结点,并将找到的链表的 next 断开。
- 重复遍历链表,找到最小的节点,直到某个链表为空。
- 一个链表为空,另外不为空,就将链表直接赋值个新链表。
代码如下:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode node = new ListNode(0);
ListNode last = node;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
last.next = l1;
l1 = l1.next;
} else {
last.next = l2;
l2 = l2.next;
}
last = last.next;
}
if (l1 != null) {
last.next = l1;
}
if (l2 != null) {
last.next = l2;
}
return node.next;
}
}
总结
链表相对数组来说,在定义的时候不需要确定好内存大小,因为链表的通过指针可以存储非连续空间的数据。链表的查询需要通过指针一个个找到对应的结点,而不能像数组一样通过索引直接找到对应的数据。在 JDK 中也会使用双链表,双链表更占内存,因为多了一个指针,带来的好处是查询数据可以从前往后查,也可以从后往前查,用空间换时间。
主要介绍了几种常见的链表算法:
- 反转链表
- 反转指针方向,结点数据不会改变。 拆分一下数据,1—>2,先将 1 取出来,将 1 作为新链表的头结点,然后再将 2 取出,作为头结点,并指向新的 1,此时就完成 2 -> 1 的过程,后续结点以此类推。
- 删除链表的倒数第 N 个结点
- 关键点事要找到要删除的位置,倒数第 N 的节点,也就是链表长度 L-n+1,再修改指针,将自己上一个结点的指针指向自己节点的下一个结点。
- 环形链表
- 环形链表表示存在相同的链表结点,遍历链表,存储在 hash 表,如果存在相同的结点就是环形链表。
- 合并两个有序链表
- 先找到两个链表最小的结点,新的链表指向最小结点,对应的链表去掉指向的结点,以此类推,直到遍历完某个链表。此时如果别的链表不为空,直接指向该链表。
图解 LeetCode 算法汇总——链表的更多相关文章
- 图解堆算法、链表、栈与队列(Mark)
原文地址: 图解堆算法.链表.栈与队列(多图预警) 堆(heap),是一类特殊的数据结构的统称.它通常被看作一棵树的数组对象.在队列中,调度程序反复提取队列中的第一个作业并运行,因为实际情况中某些时间 ...
- LeetCode算法题-链表类
1.将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. (可以参照第2的merge2List实现) 示例: 输入:1->2->4, 1->3 ...
- LeetCode算法题目解答汇总(转自四火的唠叨)
LeetCode算法题目解答汇总 本文转自<四火的唠叨> 只要不是特别忙或者特别不方便,最近一直保持着每天做几道算法题的规律,到后来随着难度的增加,每天做的题目越来越少.我的初衷就是练习, ...
- Leetcode算法【114. 二叉树展开为链表】
上周通过一位小伙伴,加入了一个氛围很好的小群,人不多,但是大家保持着对知识的渴望,让我很感动. 我自己也有一个群,人数也不多,但是能真正互动起来一起学习,一起进步的,还是太少.所以,现在也在学习如何让 ...
- Leetcode算法系列(链表)之删除链表倒数第N个节点
Leetcode算法系列(链表)之删除链表倒数第N个节点 难度:中等给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点.示例:给定一个链表: 1->2->3->4-&g ...
- Leetcode算法系列(链表)之两数相加
Leetcode算法系列(链表)之两数相加 难度:中等给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字.如果,我们将 ...
- ACM金牌选手讲解LeetCode算法《栈和队列的高级应用》
大家好,我是编程熊,双非逆袭选手,字节跳动.旷视科技前员工,ACM金牌,保研985,<ACM金牌选手讲解LeetCode算法系列>作者. 上一篇文章讲解了<线性表>中的数组.链 ...
- LeetCode算法题-Design LinkedList(Java实现)
这是悦乐书的第300次更新,第319篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第168题(顺位题号是707).设计链表的实现.您可以选择使用单链表或双链表.单链表中的 ...
- LeetCode算法题-Design HashMap(Java实现)
这是悦乐书的第299次更新,第318篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第167题(顺位题号是706).在不使用任何内置哈希表库的情况下设计HashMap.具体 ...
- LeetCode算法扫题系列19
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9104677.html LeetCode算法第19题(难度:中等) 题目:给定一个链表,删 ...
随机推荐
- 混合编程python与C++
上个版本: 只是用到ctypes进行传输, 这次将python服务端更改为C++服务端,方便后续维护. 本文实现功能: python传输图片给C++, C++接受图片后对图片进行处理,并将结果返回给p ...
- 尚医通day09-【用户平台搭建详细步骤】(内附源码)
页面预览 首页 医院详情 第01章-服务器端渲染和客户端渲染 1.搜索引擎优化 1.1.什么是搜索引擎优化 SEO 是网站为了获得更多的流量,对网站的结构及内容进行调整和优化,以便搜索引擎 (百度,g ...
- String和new String的那点事
String a= "test"; 此语句含义是:在常量池中创建test字符串对象,变量aa是对常量池中此对象的引用 String aa = new String("te ...
- MyBatis体系笔记
MyBatis 什么是MyBatis MyBatis是优秀的持久层框架 MyBatis使用XML将SQL与程序解耦,便于维护 MyBatis学习简单,执行高效,是JDBC的延伸 1.MyBatis开发 ...
- AI室内设计:提升效率、消除沟通障碍,满足客户需求
前言 免费AI绘图工具:https://www.topgpt.one 随着人工智能(AI)技术的不断发展,室内设计行业也开始受益于这一技术的应用.其中,AI绘画工具在室内设计中的应用正日益受到关注.这 ...
- C++面试八股文:如何实现一个strncpy函数?
某日二师兄参加XXX科技公司的C++工程师开发岗位第31面: 面试官:strcpy函数使用过吧? 二师兄:用过. 面试官:这个函数有什么作用? 二师兄:主要用做字符串复制,将于字符从一个位置复制到另一 ...
- Django ORM:最全面的数据库处理指南
深度探讨Django ORM的概念.基础使用.进阶操作以及详细解析在实际使用中如何处理数据库操作.同时,我们还讨论了模型深入理解,如何进行CRUD操作,并且深化理解到数据库迁移等高级主题.为了全面解读 ...
- Vue学习之认识ref
ref相当于一个dom节点,值为string 通俗将类似于原生js的document.querySelector('xxx'):但是不同的是vue是操纵虚拟dom,在渲染初期并没有这个属性,而是在创建 ...
- Spring Cloud 之OpenFeign
Spring Cloud 之OpenFeign 一:简介 Feign是一个声明式(对比RestTemplate编程式)的服务客户端,即通过@FeignClient注解即可声明一个接口(interf ...
- 二分查找非递归Algorithm(java)
二分查找的适用条件 二分查找只适用于有序的数列中进行查找(比如数字和字母等),将数列排序后再进行查找 二分查找的运行时间为对数时间O(LONG2 N) 二分查找非递归的实现 /** * @param ...