hi, 我是小黄瓜没有刺。一枚菜鸟瓜🥒,期待关注➕点赞,共同成长~
接下来会进行链表系列的题目,数量未知😁 ~
前置知识
1. 什么是链表?
链表是一种数据结构,链表中的每个节点至少包含两个部分:数据域和指针域。其中数据域用来存储数据,而指针域用来存储指向下一个数据的地址,如下图所示:
因为js中并没有链表这种数据结构,所以我们用类来实现它:
首先定义一个Node类
class Node{
constructor(val) {
// 数据域
this.val = val
// 指针域
this.next = null
}
}
接下来实现添加和打印功能:
class LinkNodeList{
constructor() {
this.head = null
this.length = 0
}
// 添加节点
append(val) {
// 使用数据创建一个节点node
let node = new Node(val)
let p = this.head
if(this.head) {
// 找到链表的最后一个节点,把这个节点的.next属性赋值为node
while(p.next) {
p = p.next
}
p.next = node
} else {
// 如果没有head节点,则代表链表为空,直接将node设置为头节点
this.head = node
}
this.length++
}
// 打印链表
print() {
if(this.head) {
let p = this.head
let ret = ''
do{
ret += `${p.val} --> `
p = p.next
}while(p.next)
ret += p.val
} else {
console.log('empty')
}
}
}
let linkList = new LinkNodeList()
linkList.append(1)
linkList.append(2)
linkList.append(3)
linkList.append(4)
linkList.print() // 1 --> 2 --> 3 --> 4
console.log(linkList.length) // 4
链表这种结构与数组的区别是啥?
首先数组和链表是两种不同的数据结构,数组访问某个成员可以直接通过Array[index]的方式直接进行访问,而链表需要遍历每个成员的指针域来进行查找。其次链表的插入速度要更快,直接将指针域指向要插入的节点,然后将新节点的指针域指向下一个成员即可,而数组还需要考虑到index下标移动以及length属性的因素。
题目
141. 环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
提示:
- 链表中节点的数目范围是
[0, 104] -105 <= Node.val <= 105pos为 -1 或者链表中的一个 有效索引 。
思路
方式一:
根据题目已知环形链表是肯定会有相交的节点,所以我们可以定义两个快慢指针,快指针比慢指针永远快走一步,如果是环形链表,那么终究会相交,如果不会遍历完整个链表依然没有找到相交节点,说明不是环形链表。
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
// 判断head节点是否为空,为空直接返回false
if(!head) return false
// 定义快慢指针
let pre = head, cur = head
while(cur && cur.next) {
// 快慢指针同时出发,快指针先走一步
pre = pre.next
cur = cur.next.next
// 如果快指针与慢指针相等,说明两者相交
if(pre === cur) {
return true
}
}
return false
};
方式二:
设置一个缓存对象,每次遍历到一个对象就将其缓存起来,如果查找到相同的值,则说明为环形链表。
// 方式二
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
// 设置缓存对象
let cache = new Set()
while(head) {
// 如果节点已存在于cache中,说明为环形链表
if(cache.has(head)) {
return true
} else {
cache.add(head)
}
// 遍历
head = head.next
}
return false
};
写在最后
目前的打算是leetcode系列会一直更新下去,未来可能会更新实现mini-vue3和js基础知识系列,希望能一直坚持下去,期待多多点赞🤗🤗,一起进步!🥳🥳