文章目录
面试题 02.01. 移除重复节点
原题链接:面试题 02.01. 移除重复节点
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var removeDuplicateNodes = function(head) {
};
解题思路:
①哈希表法
- 利用哈希表依次存储结点
- 用set.has()方法判断是否重复,如果重复通过指向进行删除,并后移
- 不重复则通过set.add()存储,并后移
var removeDuplicateNodes = function(head) {
//利用哈希
if(head==null){
return head;
}
var set=new Set();
set.add(head.val);
var prev=head; //head赋给prev
var curr=head.next; //head.next赋给curr
while(curr!=null){
if(set.has(curr.val)){ //如果当前结点重复
prev.next=curr.next; //让prev的next指向curr的next 进行删除
curr=curr.next; //curr后移
}else{
set.add(curr.val); //第一次出现 ,存储到set里
prev=prev.next; //prev和curr均后移
curr=curr.next;
}
}
return head;
};
②利用双指针法
- 声明p、q指针,分别指向head和p
- 将p指针的位置先固定,不断移动q指针进行扫描与p的值比较,相同则删除 ,否则q指向后移
- 一轮循环完后,让p向后移,判断下一个结点
- 时间复杂度较高,执行效率慢
var removeDuplicateNodes = function(head) {
//双指针
var p=head;
while(p!=null){
var q=p; //将p指针赋给q
while(q.next!=null){
if(q.next.val==p.val){ //如果后面的q有和固定的p有重复
q.next=q.next.next; //删除重复
}else{
q=q.next;
}
}
p=p.next; //让p向后移,判断下一个结点
}
return head;
};
83. 删除排序链表中的重复元素
原题链接:83. 删除排序链表中的重复元素
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var deleteDuplicates = function (head) {
};
解题思路:
注意: 与上题的不同点在于,该链表已经按升序排列,所以重复元素一定相邻,比无序排列的链表删除重复元素简单
- 让p指针指向head 并且判断p的val和p.next.val是否相等
- 如果相等则为重复并删除 , 否则,p指针指向下一个元素
var deleteDuplicates = function (head) {
//链表为空
if (head == null) {
return head;
}
//链表不为空
var p =head;
while (p.next != null) {
if (p.val == p.next.val) {
p.next = p.next.next; //删除重复元素
} else {
p = p.next; //指针指向后移
}
}
return head;
};
82. 删除排序链表中的重复元素 II
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var deleteDuplicates = function(head) {
}
与上题不一样的地方是 :返回的链表只保留原始链表没有出现重复的数字,需要将重复的数字包括自己在内也要删掉
因此判断时就需要在提前一位进行比较,方便删除。需要比较curr.next.val和curr.next.next.val,而上题相当于比较 curr.val和curr.next.val
方法一:迭代法
var deleteDuplicates = function(head) {
//可能会删除头节点 因此引入了哑结点
const dummyHead=new ListNode(0);
dummyHead.next=head;
let curr=dummyHead;
while(curr.next&&curr.next.next){
if(curr.next.val===curr.next.next.val){
let num=curr.next.val; //记下curr.next的值
while(curr.next&&curr.next.val===num){ //将等于curr.next的值的所有节点全删除
curr.next=curr.next.next;
}
}else{
curr=curr.next;
}
}
return dummyHead.next;
}
方法二:set方法
var deleteDuplicates = function(head) {
const dummyHead=new ListNode(0);
dummyHead.next=head;
let curr=dummyHead;
let set=new Set();
while(curr.next&&curr.next.next){
if(curr.next.val===curr.next.next.val){
set.add(curr.next.val); //用set记录重复元素
curr.next=curr.next.next;
}else{
curr=curr.next;
}
}
curr=dummyHead;
while(curr.next&&curr.next){
if(set.has(curr.next.val)){
curr.next=curr.next.next;
}else{
curr=curr.next;
}
}
return dummyHead.next
};
203. 移除链表元素
原题链接: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) {
};
方法一:迭代法
需要判断头结点是否为删除的结点
var removeElements = function(head, val) {
//头结点为空
if (head == null) return head;
//头结点为要删除的结点 或者新的头结点也要被删除
while (head != null && head.val == val) {
head = head.next;
}
var curr = head;
//确保当前结点不为空,并且当前结点后还有结点
while (curr != null && curr.next != null) {
if (curr.next.val == val) {
curr.next = curr.next.next;
} else {
curr = curr.next;
}
}
return head;
};
方法二 :(与一类似)
添加一个虚拟头结点
var removeElements = function(head, val) {
//头结点为空
if (head == null) return head;
//创建一个结点null,指向head结点 确保此时的head结点不是头结点
//目的是为了确保head结点不是要删除的结点
var list = new ListNode(null, head);
var curr = list;
while (curr.next != null) {
if (curr.next.val == val) {
curr.next = curr.next.next;
} else {
curr = curr.next;
}
}
return list.next;
};
方法三:递归
终止条件是head为空。 head不为空时递归进行操作
var removeElements = function(head, val) {
if(head==null) return head;
head.next=removeElements(head.next,val);
if(head.val==val){
return head=head.next;
}else{
return head;
}
};
具体动画详解参考:动画演示 迭代法 #203 移除链表元素
剑指 Offer 18. 删除链表的节点
原题链接:剑指 Offer 18. 删除链表的节点
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} val
* @return {ListNode}
*/
var deleteNode = function (head, val) {
};
先判断头结点是否为要删除,然后定义currNode指向头结点,并判断currNode.next的val值
var deleteNode = function (head, val) {
if (head.val === val) //在链表头部删除
return head.next;
var currNode=head;
while (currNode.next.val !== val && currNode !== null) {
currNode = currNode.next;
}
currNode.next = currNode.next.next;
return head;
};
237. 删除链表中的节点 / 面试题 02.03. 删除中间节点
原题链接:删除链表中的节点
原题链接:面试题 02.03. 删除中间节点
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} node
* @return {void} Do not return anything, modify node in-place instead.
*/
var deleteNode = function(node) {
};
题目的坑!!!注意看题!
参数没有头结点 ,所以不能遍历链表找待删除的结点
要删除的结点是链表的一部分而不是结点的val值
var deleteNode = function(node) {
//直接删除当前结点的值,并让下一结点的值取代
node.val=node.next.val
node.next=node.next.next
};
19. 删除链表的倒数第 N 个结点 / 剑指 Offer II 021. 删除链表的倒数第 n 个结点
原题链接: 19. 删除链表的倒数第 N 个结点
/**
* 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} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
};
方法一:定义快慢指针
让快指针先移动n步 ,同时移动快慢指针
当快指针到尾部时 ,慢指针为第倒数第n个结点
var removeNthFromEnd = function(head, n) {
var pre=new ListNode();
pre.next=head; //设预先指针下一个结点指向head
var start=pre,end=pre;
while(n!=0){
start=start.next;
n--;
}
while(start.next!=null){
start=start.next; //快慢指针同时向前移动
end=end.next;
}
end.next=end.next.next;
return pre.next //不返回head 因为head有可能是被删除的结点
};
方法二:将倒数思路转换为正数思路
删除倒数第n个结点可以转换为删除第m个结点
var removeNthFromEnd = function(head, n) {
var p=head;
var count=0;
//先计算长度
while(p){
count++;
p=p.next;
}
if(count==n){ //倒数第n个等于长度 即删除的是正数第一个结点
return head.next;
}
p=head;
var m=count-n+1; //m为要正数删除的结点
for(var i=1;i<m-1;i++){ //确保找到第m个结点的前一个结点
p=p.next;
}
p.next=p.next.next;
return head;
}
剑指 Offer 22. 链表中倒数第k个节点
原题链接: 剑指 Offer 22. 链表中倒数第k个节点
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @param {number} k
* @return {ListNode}
*/
var getKthFromEnd = function(head, k) {
}
解题方法:双指针
var getKthFromEnd = function(head, k) {
//双指针 即快慢指针 均指向头部
var fast=head;
var slow=head;
//让快指针先走k步
for(var i=0;i<k;i++){
//如果给的k值和链表长度不合理 返回null
if(fast==null){
return null;
}
//每次循环向前一步
fast=fast.next;
}
while(fast!=null){
// 让快指针和慢指针每次向前走一步,直到快指针走到头 此时慢指针恰好达到所需要的位置
fast=fast.next;
slow=slow.next;
}
return slow;
}