链表
哑节点与迭代法的常规方式(链表的遍历方式)
在链表中,所谓的迭代法多用于像当前节点与下一节点要进行比较判断,所以我们才进行一个方法的迭代。
迭代法常规模版
function iteration(listNums){
const dummy = new ListNode(0)
dummy.next = listNums
//定义tmp对链表进行操作
let tmp = dummy
while(结束条件){
if(curr 与 next进行比较判断){
...options
// tmp.next = tmp.next.next
}else{
tmp = tmp.next
}
}
return dummy
力扣203.移除链表元素
递归法
链表的定义具有递归的性质,因此链表题目常可以用递归的方法求解。这道题要求删除链表中所有节点值等于特定值的节点,可以用递归实现。
对于给定的链表,首先对除了头节点 head 以外的节点进行删除操作,然后判断 head 的节点值是否等于给定的val。如果 head 的节点值等于val,则 head 需要被删除,因此删除操作后的头节点为head.next;如果 head 的节点值不等于 val,则 head 保留,因此删除操作后的头节点还是 head。上述过程是一个递归的过程。
/**
* 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) return head
head.next = removeElements(head.next,val)
return head.val == val ? head.next : head
};
迭代法
利用哑(脏)节点对next进行迭代
/**
* 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) {
const dummy = new ListNode(0,head)
let temp = dummy
while(temp.next){
if(temp.next.val == val){
temp.next = temp.next.next
}else {
temp = temp.next
}
}
return dummy.next
};
力扣21.合并两个有序链表
递归法
var mergeTwoLists = function(l1, l2) {
if (l1 === null) {
return l2;
} else if (l2 === null) {
return l1;
} else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
};
迭代法
var mergeTwoLists = function(l1, l2) {
let ans = new ListNode(0)
let tmp =ans
while(l1 != null && l2 !=null){
if(l1.val>=l2.val){
tmp.next = l2
l2 = l2.next
}else{
tmp.next = l1
l1 = l1.next
}
tmp = tmp.next
}
tmp.next =l1 == null ? l2 : l1
return ans.next
};
力扣83.删除排序链表中的重复元素
var deleteDuplicates = function(head) {
var cur = head;
//判断头节点和下一节点必须同时存在要不就没有必要了
while(cur && cur.next) {
if(cur.val == cur.next.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head;
};
力扣面试题 02.01. 移除重复节点
//哑节点 + hash表的方式
var removeDuplicateNodes = function(head) {
const directory = {}
const flag = new ListNode(0)
flag.next = head
let tmp = flag
while(tmp.next){
let val = tmp.next.val
if(!directory[val]){
directory[val] = true
tmp = tmp.next
}else{
tmp.next = tmp.next.next
}
}
return flag.next
};
双指针/快慢指针法
206.反转链表
var reverseList = function(head){
let prev = null
let cur = head
while(cur){
let next = cur.next
next = prev
prev = cur
cur = next
}
return prev
}
剑指 Offer 22. 链表中倒数第k个节点
var reverseList = function(head) {
let curr = head
let prev = null
while(curr){
let next = curr.next
curr.next = prev
prev = curr
curr = next
}
return prev
};
876. 链表的中间结点
数组思想
链表的缺点在于不能像数组结构一样存在索引值,所以我们可以引入数组的思想解决一些问题,下面是借鉴的数组思想(leetcode不能通过,因为只会返回当前节点的val值)
var middleNode = function(head) {
const ans = []
while(head){
ans.push(head.val)
head = head.next
}
let mid = parseInt(ans.length / 2)
console.log(ans[mid])
return ans[mid]
};
快慢指针
利用快慢指针可以解决很多问题,只需快指针每次2步,慢指针每次2步即可。
var middleNode = function(head) {
let slow = head
let fast = head
while(fast && fast.next){
slow = slow.next
fast = fast.next.next
}
return slow
};