Java
两种结题方式,使用虚拟头节点或者不使用。
使用虚拟头节点简单易理解,从虚拟头节点开始,一个一个地看下一个元素,是目标元素则改动当前节点next指针跳过一下,并且重新检查下一个节点(存在下两个及以上节点都应该删除的情况),不是目标元素就将下一个节点变为目标节点,直到下一个目标节点为空。最后返回的是虚拟头节点next指向的真实头节点。
不使用头节点要分两种状态考虑,一个是头节点就是要删除的目标节点,另外一个是非头节点是要删除的节点,两种处理方式不一样,首先进来检查头节点,如果是要删除的节点,直接将head指向头节点的下一个节点以跳过来删除,之后再次检查头节点(存在开头两个及以上都应该删除的情况),直到当前头节点不应该被删除或者链表被删空了,然后接下来才检查除开头节点之外的节点是否要删除。在检查之前,因为上次退出循环有两个条件,不知道是哪个条件导致循环退出的,所以需要判断一下链表是不是空了(即头结点为空),是则直接返回空,不是再类似使用虚拟头结点的方式将头结点之后的元素逐一判断或删除。
class Solution { // 使用虚拟头结点解决 public ListNode dummyHead(ListNode head, int val) { // 虚拟头节点 ListNode dummyHead = new ListNode(); dummyHead.next = head; ListNode cur = dummyHead; while (cur.next!=null){ if(cur.next.val == val){ // ListNode delNode = cur.next; // cur.next = cur.next.next; // delNode.next = null; // 内存自动回收,这样解决 cur.next = cur.next.next; }else { cur = cur.next; } } // 返回头结点 return dummyHead.next; } // 使用一般方法解决 public ListNode normal(ListNode head, int val) { // 每次节点不能为空,可能删除一个就空了,下一个判断会空指针异常 while (head != null && head.val == val) { // ListNode delNode = head; // head = delNode.next; // delNode.next = null; // 自动内存处理,直接跳过就好 head = head.next; } // 考虑到所有元素在头结点被删除 if (head == null) { return null; } for (ListNode cur = head; cur.next != null; ) { // 如果指针的下一个节点是要被删除的 if (cur.next.val == val) { // ListNode delNode = cur.next; // cur.next = cur.next.next; // delNode.next = null; // 内存自动回收,直接跳过 cur.next = cur.next.next; } else { // 如果每次执行会跳过连续被删除的节点 cur = cur.next; } } return head; } public ListNode removeElements(ListNode head, int val) { return dummyHead(head,val); } }