【问题标题】:Why can't I remove occurrences in the linked list?为什么我不能删除链表中的匹配项?
【发布时间】:2017-03-15 15:37:43
【问题描述】:

问题:给定一个值,从链表中删除该值的所有实例。 更多信息如下: JAVA

    /**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode n = head; //1, 2, 6, 3, 4, 5, 6
        while(n.next == null){
            if(n.next.val == val){
                n.next = n.next.next;
            }
            n = n.next;
            if(n == null){break;}
        }
        return head;
    }
}

既然它是通过引用传递的,它应该更新不应该吗?

我试过了:

removeElements([1,2,6,3,4,5,6], 6)

但它没有删除任何东西。那么我做错了什么?

【问题讨论】:

  • 因为它应该是 while(n.next != null),所以你也不检查头部是否包含你的值。您为此缺少很多检查语句。
  • while(n.next == null){ 如果您将长度为 1 的列表传递给 removeElements 会做一些非常丑陋的事情,如果列表更长,则不会。

标签: java algorithm data-structures linked-list


【解决方案1】:

有几个问题:

  • 你想循环直到一个节点为空,直到不为空(即while( ... != null)
  • 您可能希望循环直到n 为空,直到n.next 为空,否则您将跳过最后一个元素
  • 您要检查 n.val == val 而不是 n.next.val == val,否则您会跳过第一个元素
  • 如果您检查n,您希望跟踪前一个节点,以防您需要删除n,即prev.next = n.next
  • 如果要删除第一个元素(头部),则需要替换头部,即返回第二个元素(这可以通过检查prev == null 来完成,这意味着n 是当前头部)。

【讨论】:

    【解决方案2】:

    正如 Thomas 在他的第一点中提到的,您错误地编写了 while 循环。此外,因为您有一个单链表,所以您需要跟踪前一个节点(Thomas 也提到过)。

    public static ListNode removeElements(ListNode head, int val)
    {
        ListNode n = head;
        ListNode prev = null; //the previous node.
        while (n != null)
        {
            if (n.value == val)
            {
                //if prev is null it means that we have to delete the head
                //and therefore we need to advance the head
                if (prev == null)
                {
                    head = n.next;
                    prev = null;//remains at null because there's nothing before head
                    n = head;//new head, let's start from here
                } else
                {
                    prev.next = n.next; //let's skip the element to delete
                    n = n.next;//let's advance to the next node
                }
            } else
            {
                //nothing to delete, let's advance to the next node and make 
                //the current node the previous node in the next iteration
                prev = n;
                n = n.next;
            }
    
        }
        return head;
    }
    

    【讨论】:

      【解决方案3】:

      使用适当的测试用例解决这些问题始终是一个好习惯。设计可能的测试用例,包括角落用例。然后按照你的算法,看看它是否解决了测试用例的问题。编写代码并试运行它,这将对代码和逻辑进行完整性检查。

      以下是该问题必须编写测试用例的案例。

      1. 空列表,
      2. 一个元素且值等于要删除的值的列表
      3. 一个元素且值不等于要删除的值的列表
      4. 具有两个元素且第一个节点值等于要删除的值的列表
      5. 具有两个元素且最后一个节点值等于要删除的值的列表
      6. 具有三个元素且第一个节点值等于要删除的值的列表
      7. 具有三个元素且第二个节点值等于要删除的值的列表
      8. 具有三个元素且最后一个节点值等于要删除的值的列表

      下面是删除链表中给定值节点问题的代码

      public ListNode removeElements(ListNode head, int val) {
              while(head != null && head.val == val){
                  head = head.next;
              }
              if(head == null){
                  return null;
              }
              ListNode node = head;
              while(node.next != null){
                  if(node.next.val == val){
                      node.next = node.next.next;
                  }else{
                      node = node.next;
                  }
              }
              return head;
      }
      

      【讨论】:

      • 对于前两行while(head != null && head.val == val){ head = head.next; },在这个循环完成后,节点减少了很多不是吗?假设我有1->2->3->1->null 和所需的val = 1 然后循环完成时head = null?
      • 否,因为循环检查 head 处的值是否等于所需值,然后仅修改 head 作为下一个节点,否则第一个循环停止。在您的情况下,头将在第一个循环后位于值为 2 的节点处。
      猜你喜欢
      • 1970-01-01
      • 2016-05-08
      • 2021-06-29
      • 1970-01-01
      • 2012-02-06
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2023-03-10
      相关资源
      最近更新 更多