删除特定结点
思路分析:
我们要删除结点通常要找到该删除结点的前驱结点,所以要加入一个虚拟头结点便于我们从头遍历整条链表,找到目标结点只需要使用cur.next = cur.next.next来略过该结点
public static ListNode removeElements(ListNode head, int val) {
//创建虚拟结点
ListNode dummyHead = new ListNode(0);
//接入整条链表
dummyHead.next = head;
ListNode temp = dummyHead;
//辅助指针遍历
while (temp.next != null) {
if (temp.next.val == val) {
temp.next = temp.next.next;
} else {
temp = temp.next;
}
}
return dummyHead.next;
}
删除倒数第n个结点
经典的快慢指针问题
思路分析:
只需要通过快慢指针策略找到倒数第n个结点所在的位置,然后删除即可
public static ListNode removeNthFromEndByTwoPoints(ListNode head, int n) {
ListNode newhead = new ListNode(0);
newhead.next = head;
ListNode fast = newhead;
ListNode slow = newhead;
//辅助指针帮助遍历
ListNode cur = newhead;
if (head == null){
return null;
}
//fast指针先走n步
while (n>0){
fast =fast.next;
n--;
}
//当fast指针走到链表最后的时候,slow指针指向待删除结点的前驱结点
while (fast.next != null){
fast = fast.next;
slow = slow.next;
}
//删除操作
slow.next = slow.next.next;
return newhead.next;
}
删除重复元素
重复元素保留一个
思路分析:
如果当前cur和cur.next对应的值相同,就移除cur.next,然后对移除后cur.next进行重复的操作,直到出现不同说明该元素已删除完毕,进入下一个不同的值判断
public static ListNode deleteDuplicate(ListNode head) {
if (head == null){
return head;
}
ListNode cur = head;
//遍历链表通过前面和后面结点的值进行比较,如果相等就一直删除
while (cur.next != null){
if (cur.val == cur.next.val){
cur.next = cur.next.next;
}else {
cur = cur.next;
}
}
return head;
}
重复元素都不要
思路分析:需要记录一下当前重复的值(便于后续删除时剩下一个结点时仍能进行比较),如果存在相同的值需要继续内循环删除
public static ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return head;
}
//创建虚拟结点便于从头开始遍历
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode cur = dummy;
//凡是需要val的都得先对其进行非空判断,防止空指针异常
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 dummy.next;
}