力扣LeetCode,移除链表元素

1、删除链表中等于给定值val的所有节点。

1 示例:
2 
3 输入: 1->2->6->3->4->5->6, val = 6
4 输出: 1->2->3->4->5

首先,结合给定的条件,此类ListNode就是一个实现了一个节点,节点包含存储元素的val变量和指向下一个节点的Node类型的next,然后创建了一个ListNode类型的构造函数,用于将存储元素的x存储到节点中。

 1 package com.leetcode;
 2 
 3 /**
 4  *
 5  */
 6 public class ListNode {
 7 
 8     int val;
 9     ListNode next;
10 
11     ListNode(int x) {
12         val = x;
13     }
14 }

1.1、方案一,不使用虚拟头节点dummyHead的方法,实现删除链表中等于给定值val的所有节点。题目,如下图所示:

  这里,用了一个考虑比较全面的,和上面的图有点区别的进行全部因素考虑。如下所示:

  如果head本身就是val的时候,需要进行特殊处理的。注意,访问 head.val的时候,需要有一个前提,就是链表不为空,即head头部节点不是空的。除了考虑head本身就是val的时候,还需要考虑head的下一个节点是val的时候,所以使用了循环操作。所以循环指向head = head.next;就将头部节点是val元素和head的后面紧跟的也是val元素的进行了删除操作。

  还有,需要注意的是,这个链表中所有节点都是需要被删除的节点。执行完上面的循环,此时,链表已经为空了,那么就不需要继续运行了,使用判断,如果if (head == null),直接返回head即可了。

  接下来,开始处理在中间的部分需要删除的节点。注意,此时的head肯定不是要被删除的节点了,它后面的节点可能是要被删除的节点。

最终效果,如上所示,特别需要注意的是,这种题目,有时候可能很隐含,传入的参数head是一个节点,每次传入一个节点,如果没有被删除就将该节点直接返回了,否则就删除掉了。

 1 package com.leetcode;
 2 
 3 /**
 4  * 删除链表中等于给定值 val 的所有节点。
 5  * <p>
 6  * Definition for singly-linked list.
 7  * <p>
 8  * public class ListNode {
 9  * int val;
10  * ListNode next;
11  * ListNode(int x) { val = x; }
12  * }
13  */
14 public class RemoveLinkedList {
15 
16     /**
17      * 删除链表中等于给定值 val 的所有节点。
18      * 输入: 1->2->6->3->4->5->6, val = 6
19      * 输出: 1->2->3->4->5
20      *
21      * @param head
22      * @param val
23      * @return
24      */
25     public ListNode removeElements(ListNode head, int val) {
26         // 自己实现的链表,删除链表中的某个节点,就要找到这个链表中这个节点之前的那个节点,才方便进行删除操作。
27         // 但是对于头部节点来说,没有之前的那个节点,所以就需要进行特殊处理,或者使用虚拟头节点来统一操作。
28 
29         // 方法一,不涉及头节点的时候,如何操作。
30         // 如果head本身就是val的时候,需要进行特殊处理的。
31         // 访问 head.val的时候,需要有一个前提,就是链表不为空,即head头部节点不是空的。
32 //        if (head != null && head.val == val) {
33 //            // 此时,需要对头部节点进行删除操作,此时有一定的特殊处理的。
34 //            // 删除头部节点。
35 //            ListNode delNode = head;// 将头部待删除结点保存起来。
36 //            // 此时,将头部节点head指向之前的head的下一个节点。即head = head.next。链表绕过待删除的节点。
37 //            head = head.next;
38 //            // 此时将待删除节点置空,jvm回收,此时,待删除节点和链表断开了关系。
39 //            delNode.next = null;
40 //            // 通过以上过程,删除了头部节点。
41 //        }
42 
43 
44         // 如果使用if判断的时候,可能只考虑了head不为空,且头部节点就是待删除元素,
45         // 但是如果第二个元素还是待删除元素呢,那么这里就需要使用while循环了。
46         // 循环解决了在开始部分需要删除的那些节点全部删除掉了。
47         while (head != null && head.val == val) {
48             // 此时,需要对头部节点进行删除操作,此时有一定的特殊处理的。
49             // 删除头部节点。
50             ListNode delNode = head;// 将头部待删除结点保存起来。
51             // 此时,将头部节点head指向之前的head的下一个节点。即head = head.next。链表绕过待删除的节点。
52             head = head.next;
53             // 此时将待删除节点置空,jvm回收,此时,待删除节点和链表断开了关系。
54             delNode.next = null;
55             // 通过以上过程,删除了头部节点。
56         }
57 
58         // 接下来,开始处理在中间的部分需要删除的节点。
59         // 还有,需要注意的是,这个链表中所有节点都是需要被删除的节点。
60         // 如果,此时,链表已经为空了,那么就不需要继续运行了
61         if (head == null) {
62             // 此时return head和return null是一个意思的。
63             return head;
64         }
65 
66         // 那么,接下来,开始删除链表中间的元素。
67         // 需要删除的元素等于val。需要找到待删除节点元素的前一个节点。
68         // 注意,此时的head肯定不是要被删除的节点了,它后面的节点可能是要被删除的节点。
69         ListNode prev = head;
70         // 循环遍历,此时判断,prev的下一个节点不为空,换句话说,我还没有遍历到最后一个节点元素。
71         while (prev.next != null) {
72             // 每次循环,判断下一个节点是不是需要被删除
73             if (prev.next.val == val) {
74                 // 如果prev的下一个节点的值和val相等,那么下一个节点需要被删除。
75                 // 获取到需要被删除的节点。即prev的下一个节点就是需要被删除的节点。
76                 ListNode delNode = prev.next;
77                 // 此时,让prev的下一个节点指向待删除节点元素的下一个节点。
78                 prev.next = delNode.next;
79                 // prev.next = prev.next.next;
80                 // 此时让待删除节点元素的下一个节点置空,让其和链表断开关系即可。
81                 delNode.next = null;
82                 // 经过上述步骤,就将prev.next这个节点删除掉了。
83                 // 此prev.next.val == val判断中需要注意,删除了待删除元素节点,不要将prev向下移动一个节点。
84                 // 因为,删除了prev的下一个节点之后,现在prev的下一个节点就改变了,那么改变的这个节点很可能依然是待删除元素节点。
85                 // 依然,需要走循环,判断是否是需要被删除的节点。
86             } else {
87                 // 否则,prev.next不需要被删除,就向下移动一个位置。
88                 prev = prev.next;
89             }
90         }
91         // 经过上述过程,将链表中所有元素遍历了一遍,判断是否是待删除的节点,如果是就将链表中需要被删除的节点进行删除了。
92 
93         // 最终,返回head即可。即传入的这个节点head。
94         return head;
95     }
96 
97 }

1.2、方案二,使用虚拟头节点dummyHead的方法,实现删除链表中等于给定值val的所有节点。题目,如下图所示:

 1 package com.leetcode;
 2 
 3 /**
 4  * 删除链表中等于给定值 val 的所有节点。
 5  * <p>
 6  * Definition for singly-linked list.
 7  * <p>
 8  * public class ListNode {
 9  * int val;
10  * ListNode next;
11  * ListNode(int x) { val = x; }
12  * }
13  */
14 public class RemoveLinkedList2 {
15 
16     /**
17      * 删除链表中等于给定值 val 的所有节点。
18      * 输入: 1->2->6->3->4->5->6, val = 6
19      * 输出: 1->2->3->4->5
20      *
21      * @param head
22      * @param val
23      * @return
24      */
25     public ListNode removeElements(ListNode head, int val) {
26         // 如果使用if判断的时候,可能只考虑了head不为空,且头部节点就是待删除元素,
27         // 但是如果第二个元素还是待删除元素呢,那么这里就需要使用while循环了。
28         // 循环解决了在开始部分需要删除的那些节点全部删除掉了。
29 
30         // 使用虚拟头节点解决该问题。虚拟头节点的值传为-1了,这个值不会去访问,是多少无所谓的。
31         ListNode dummyHead = new ListNode(-1);
32         // 此时,让虚拟头节点的下一个节点执行head节点,此时dummyHead就变成了head再之前的一个节点。
33         dummyHead.next = head;
34         // 此时,这个head指向的链表中所有的节点都有前一个节点了。
35         // 我们就不需要对第一个节点进行特殊化处理了。
36 
37 
38         // 需要删除的元素等于val。需要找到待删除节点元素的前一个节点。
39         // 注意,此时的head肯定不是要被删除的节点了,它后面的节点可能是要被删除的节点。
40         ListNode prev = dummyHead;
41         // 循环遍历,此时判断,prev的下一个节点不为空,换句话说,我还没有遍历到最后一个节点元素。
42         while (prev.next != null) {
43             // 每次循环,判断下一个节点是不是需要被删除
44             if (prev.next.val == val) {
45                 // 如果prev的下一个节点的值和val相等,那么下一个节点需要被删除。
46                 // 获取到需要被删除的节点。即prev的下一个节点就是需要被删除的节点。
47                 ListNode delNode = prev.next;
48                 // 此时,让prev的下一个节点指向待删除节点元素的下一个节点。
49                 prev.next = delNode.next;
50                 // prev.next = prev.next.next;
51                 // 此时让待删除节点元素的下一个节点置空,让其和链表断开关系即可。
52                 delNode.next = null;
53                 // 经过上述步骤,就将prev.next这个节点删除掉了。
54                 // 此prev.next.val == val判断中需要注意,删除了待删除元素节点,不要将prev向下移动一个节点。
55                 // 因为,删除了prev的下一个节点之后,现在prev的下一个节点就改变了,那么改变的这个节点很可能依然是待删除元素节点。
56                 // 依然,需要走循环,判断是否是需要被删除的节点。
57             } else {
58                 // 否则,prev.next不需要被删除,就向下移动一个位置。
59                 prev = prev.next;
60             }
61         }
62         // 经过上述过程,将链表中所有元素遍历了一遍,判断是否是待删除的节点,如果是就将链表中需要被删除的节点进行删除了。
63 
64 
65         // 最终,返回head即可。即传入的这个节点head。
66         return dummyHead.next;
67     }
68 
69 }

猜你喜欢

转载自www.cnblogs.com/biehongli/p/12438826.html