“Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。”
一、题目描述:
203. 移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
提示:
列表中的节点数目在范围 [0, 104] 内
1 <= Node.val <= 50
0 <= val <= 50
二、思路分析:
链表与数组
数组:[1,2,3,4]
链表:1 => 2 => 3 => 4
既然有了数组为什么还需要链表解构,这就要说到两种格式的优缺点:
数组
- 数组是占用 连续的储存空间,那根据索引去查找元素,就变得很方便,只要知道数组的 储存地址+索引偏移量,例如 arr[3]。那么随机访问的时间复杂度仅为O(1)。
- 但是增删数据就变得繁琐了,例如 [1,2,3,4,5],想要在2、3中间插一个6,那么3、4、5都要向后移动一个位置。那么他的时间复杂度为O(n)。删除同理,向前移。
链表
- 链表的储存空间可以不连续,每一个节点有 val 和 next(指向下一项) 两个属性。通俗的讲像特务,只与自己的下级联系,其他什么都不知道。
- 链表的查询数据只能从头一项一项来,那么随机访问的时间复杂度为O(n)
- 增删操作就很简单了,时间复杂度仅为O(1)。(在指定节点的前提下) 例如 1 => 2 => 3,想要在1、2中间添加一项4
插入4
4.next = 1.next
1.next = 4
删除4
1.next = 4.next
回到题目,功能应该是 链表的 循环+删除。那么开干
解法1
var removeElements = function(head, val) {
// 因为head首项可能也满足条件,那么就加一个守卫指向head。
let solider = {
next: head
}
let p = solider
while(p.next){ // 最后一项 next 为 null
if(p.next.val === val){
p.next = p.next.next // 删除操作
} else {
p = p.next // 指针后移
}
}
return solider.next
};
结果不错哈哈哈
解法2
一般循环能写,递归也能实现,那么换个实现方法看看。
递归
- 边界条件,找出口不能无限递归
- 递进是参数层层传递,每一项按顺序传递进去
- 回归是return结果值,每一次都是一次返回。
- 逻辑部分,每一层都完整执行。
var removeElements = function(head, val) {
if(head === null){ // 递归出口
return null
}
head.next = removeElements(head.next, val) // 层层递进
return head.val === val?head.next:head // 逻辑部分 + 回归return
};
ok拉,明儿见奥