目录
第一题:删除链表中的节点(leetcode第237题)(简单)
第二题:删除链表中重复的元素 I(leetcode第82题)(简单)
第三题:删除链表中的重复元素II(leetcode第82题)(中等)
第四题:删除链表中倒数第N个节点(leetcode第19题)(中等)
第一题:删除链表中的节点(leetcode第237题)(简单)
思路分析
1:因为题目中只给定了要删除的节点,并没有给出链表的头结点,所以无法通过遍历查询到待删除节点的上一个节点,然后执行删除操作
2:对此,我们利用给定的待删除节点的信息,将待删除节点的下一个节点的值付给待删除的节点,这样就可以将待删除节点的next指针域指向下一个节点的下一个,从而实现删除操作
class Solution {
public void deleteNode(ListNode node) {
if(node==null){
return;
}
node.val=node.next.val;
node.next=node.next.next;
}
}
第二题:删除链表中重复的元素 I(leetcode第82题)(简单)
思路分析:
1:由于给定的链表是排好序的,因此重复的元素在链表中出现的位置是连续的,因此我们只需要对链表进行一次遍历,就可以删除重复的元素。定义一个辅助节点temp用于遍历
2:当我们遍历到链表的最后一个节点时temp.next 为空节点,如果不加以判断,访问 temp.next 对应的元素会产生运行错误。
3: 当遍历到两个节点值相同时,执行删除操作,注意此处要用else将节点后移
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head==null){
return null;
}
ListNode temp=head;
while(temp!=null&&temp.next!=null){
if(temp.val==temp.next.val){
temp.next=temp.next.next;
}else{
temp=temp.next;
}
}
return head;
}
}
第三题:删除链表中的重复元素II(leetcode第82题)(中等)
思路分析:
1:这道题的重点在于要删除所有相同的节点,所以我们不仅要有待删除的节点,但删除节点的下一个节点,还要有待删除节点的前一个节点
2:我们要定义一个头结点的前驱结点,让用于遍历链表的指针指向头结点的前驱节点preNode
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return head;
}
ListNode preNode= new ListNode(0, head);
ListNode cur = preNode;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) {
int x = cur.next.val;
while (cur.next != null && cur.next.val == x) {
cur.next = cur.next.next;
}
} else {
cur = cur.next;
}
}
return preNode.next;
}
}
第四题:删除链表中倒数第N个节点(leetcode第19题)(中等)
单链表插入,删除都需要考虑头节点,当寻找前驱节点时由于头节点不存在前驱节点,需要另外考虑,此时引入虚拟头节点,虚拟头节点不存储具体元素,不考虑头结点是否空,头节点一定存在,则所有节点都有前驱节点
思略分析1双指针的解法
1:定义快指针fast,慢指针slow,定义一个头结点的前一个节点preNode,慢指针指向前驱节点preNode,快指针指向头结点head,
2:链表的倒数第N个节点说明要让快指针先移动n次,慢指针不动
3:当快指针移动到第n个节点位置时,让快慢双指针同时移动,当快指针移动到链表尾时,此时慢指正刚好移动到待删除节点的前一个节点,执行删除操作
4: 定义的时候,如果将慢指针快指针都指向头结点,当返回head的时候,输出的结果就是1 2 3 4而不是1 2 3 5
图解如下:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null){
return null;
}
//定义头结点的前驱节点
ListNode preNode=new ListNode(0);
ListNode fast=head;
ListNode slow=preNode;
slow.next=head;
//让快指针先行移动到第n个节点的位置
for(int i=0;i<n;i++){
fast=fast.next;
}
//快慢双指针同时移动
while(fast!=null){
fast=fast.next;
slow=slow.next;
}
//此时慢指针刚好移动到待删除节点的前一个节点
slow.next=slow.next.next;
return preNode.next;
}
}
思路分析2:哈希表的解法
1:定义一个哈希表,将链表中的所有节点信息存入哈希表中map.put()方法
2:取出待删除节点,注意下标从0开始map.get()方法执行,判断待删除的节点是否为空,如果空则返回null
3:如果待删除的节点不为空,就判断待删除的节点是否为头结点,如果是头结点,则直接返回头结点的下一个节点
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head==null){
return null;
}
ListNode temp=head;
int count=0;
HashMap<Integer,ListNode> hashMap=new HashMap<>();
while(temp!=null){
//哈希表的下标从0开始
hashMap.put(count,temp);
count++;
temp=temp.next;
}
//从哈希表中取出要删除的元素
ListNode deleteNode=hashMap.get(count-n);
if(deleteNode!=null){
//如果要删除的节点正好是头结点,则直接返回头结点的下一个节点
if(deleteNode==head){
return head.next;
}else{
//定义要删除节点的前驱节点preNode,小标从0开始所以要减一
ListNode preNode=hashMap.get(count-n-1);
preNode.next=deleteNode.next;
}
}
return head;
}
}
第五题:移除链表元素(leetcode第203题)(简单)
思路分析1(虚拟头结点法):
1:定义一个虚拟头结点,temp,temp指向链表的头结点(即链表的第一个节点)。定义一个指针curNode指向虚拟头结点
2:遍历链表,当指向虚拟头结点的下一个节点为空时退出循环
3:最终返回虚拟头结点的下一个节点
class Solution {
public ListNode removeElements(ListNode head, int val) {
//先判断头结点是否为空
if(head==null){
return null;
}
//定义一个虚拟头结点
ListNode temp=new ListNode(0);
//虚拟头结点指向链表中第一个节点
temp.next=head;
//定义一个当前指针指向虚拟头结点,用于遍历操作
ListNode curNode=temp;
while(curNode.next!=null){
if(curNode.next.val==val){
curNode.next=curNode.next.next;
}
else{
curNode=curNode.next;
}
}
return temp.next;
}
}
思路分析2(递归解法):
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head==null){
return null;
}
if(head.val!=val){
head.next = removeElements(head.next,val);
return head;
}else{
head=removeElements(head.next,val);
return head;
}
}
}