本文已参与[新人创作礼]活动,一起开启掘金创作之路。
写在前面
很少会在公共平台记录,因为总是怕“错”,怕暴露弱点,不过现在发现,其实也没什么,因为自己又没有“流量”,哈哈哈。。欢迎偶然看到的朋友留言指正。
所以呢,开始多写文章,多总结,总结的过程可以加深印象,而写好的文章也方便自己检索。
现在开始刷算法,看看可以坚持多少天!Fighting!
链表和数组基本概念
数组的随机访问(查):
根据数组下标来找到某个元素叫随机访问,因为数组是有序的,无论长度是一百还是一万,想找到某个元素都是等价的,跟长度无关。所以查找时间复杂度是O(1)。
数组的增删改:
比如插入某个元素,那么该位置后的数据都要改变index,所以复杂度是O(n)
链表都是指向关系:
链表的随机访问:
1=>2=>3=>4=>5
需要一个一个的向下传,找到某个值的位置,所以是O(n)
而增删的话,比如2和3之间增加一个10,直接改变2的指向即可,所以是O(1)
适用情况:
有序数据的存储,对随机访问有要求时,要优先使用数组,如任务队列
对删除插入需求多,随机访问少,则适合用链表
数组+链表可以拼接组成其他的数据结构
如何手写一个链表结构
写了几遍就发现,这个在理解含义的基础上,背一下吧。。就固定这么写
// 链表的构成就是 值+指针
class NodeList {
constructor(val) {
this.val = val
this.next = null
}
}
class LinkNodeList {
constructor() {
this.head = null
}
append(val) {
let node = new NodeList(val)
let p = this.head
if (this.head) {
// 找到链表最后一个节点,把这个节点.next赋值为node
while(p.next) {
p = p.next
}
p.next = node
console.log(this.head)
} else {
// 头节点是null时候,链表是空的,把第一个node值赋值给head
this.head = node
}
}
}
let linkList = new LinkNodeList()
linkList.append(1)
linkList.append(2)
linkList.append(3)
linkList.append(4)
linkList.append(5)
打印结果
力扣203-移除链表元素
普通方法-采用递归
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var removeElements = function(head, val) {
if(head === null) {
return head
}
head.next = removeElements(head.next, val)
return head.val === val ? head.next : head
};
哨兵方法
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var removeElements = function(head, val) {
// 定义一个哨兵元素:哨兵=>1=>2=>3
// 来减少对于head为空时候的判断
let ele = {
next: head
}
let p = ele
while(p.next) {
if (p.next.val === val) {
// 多跳一步
p.next = p.next.next
} else {
p = p.next
}
}
return ele.next
};
调试
刚开始刷,很多地方不理解,但是又没有办法直接在力扣上console,所以自己写了一个链表的类。
采用普通方法-递归的调试:
class NodeList {
constructor(val) {
this.val = val
this.next = null
}
}
class LinkNodeList {
constructor() {
this.head = null
}
append(val) {
let node = new NodeList(val)
let p = this.head
if (this.head) {
while(p.next) {
p = p.next
}
p.next = node
} else {
this.head = node
}
return this.head
}
}
let linkList = new LinkNodeList()
linkList.append(1)
linkList.append(2)
linkList.append(6)
linkList.append(4)
var removeElements = function(head, val) {
console.log('head-s', head)
if (head === null) {
return head
}
head.next = removeElements(head.next, val)
console.log('head-e',head)
return head.val === val ? head.next : head
};
console.log(removeElements(linkList.append(5),6))
打印结果:
错误写法
var removeElements = function(head, val) {
let p = head;
if (head === null) {
return head
}
while(p.next) {
if (p.next.val === val) {
p.next = p.next.next
console.log(p)
}
else {
p = p.next
}
}
return head
};
用例3不通过,重复元素会返回一个元素值,修改方法?
力扣141-环形链表
常规解法
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
let cache = new Set()
while(head) {
if (cache.has(head)) {
return true
} else {
cache.add(head)
}
head = head.next
}
return false
};
双指针法
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var hasCycle = function(head) {
// 双指针法
let fast = head
let slow = head
while (fast && fast.next) {
fast = fast.next.next
slow = slow.next
if (fast == slow) {
return true
}
}
return false
};