【问题标题】:Remove Duplicates from Linked List从链接列表中删除重复项
【发布时间】:2018-05-12 16:58:37
【问题描述】:

所以我有一个链接列表,我正在尝试从中删除重复项。

我想出的基本算法几乎是使用跑步者技术。我保留两个指针来比较相邻元素。如果它们相同,我将 p1 的指针更改为指向 p1.next.next,否则我继续遍历列表。但是,我在输入的解决方案中不断收到空指针异常。

Node RemoveDuplicates(Node head) {
  // This is a "method-only" submission. 
  // You only need to complete this method. 
    if (head == null){
        return null;
    } 

        Node current = head;
    Node runner = head;



    while(current != null && runner != null && runner.next != null){
    runner = runner.next;
    if(runner.data == current.data){
        if(current.next != null){
                    current = current.next.next; 

        }
    }else{
        current = current.next;
    }
}



    return current;
}

在我退出 while 循环时,电流为空。我认为这是问题所在。我将如何返回更改列表的头部。

【问题讨论】:

  • 为什么不直接使用Set 来禁止重复?是否有必要在将项目插入您的收藏时保持它们的顺序?
  • 这是我最初的想法,使用一个集合,但已经排序了
  • 并且输出看起来仍然是排序顺序
  • 我通常在未排序的时候使用集合..但也许没关系
  • LinkedHashSet 给您带来SetList 的好处怎么样?见LinkedHashSet in Oracle JDK 8 API

标签: java


【解决方案1】:

好的,尽管您已经接受了答案,但这里有一些示例代码使用递归根据您在 cmets 中的请求从有序列表中删除 dups。 (如果您的清单没有订购,请订购 :))

public Node removeDups(Node root) {
    if (root.next == null)
        return root;
    root.next = removeDups(root.next);
    if (root.data == root.next.data)
        return root.next;
    return  root;
} // call as root = removeDups(root);

正如您所提到的,这里实际上并不需要递归,但您使用的是递归定义的基于节点的链表。因此,当它有意义时,解决方案的优雅有其好处。

我喜欢它的地方在于,您无需执行任何 node.next.next 或需要检查 null 案例。一旦堆栈开始展开,您就可以开始检查重复了。那么只需比较root.dataroot.next.data即可;你已经知道两者都存在。

【讨论】:

    【解决方案2】:

    您可以使用 2 个指针进行单次遍历。此代码也适用于单个 while 循环。

    public Node deleteDuplicates(Node head) {
            Node current=head;
                if (head == null)
                    return null;
                else
                {
                 Node runner=head.next;
                   while(head.next!=null && runner!=null)
                    {
                        if(head.val == runner.val)
                           prev=runner.next;
                        else
                        {
                          head.next=runner;
                          head=head.next;
                          prev=runner.next;
                        }
                    }
                    head.next=runner;
                }
                return current; 
        }
    

    【讨论】:

      【解决方案3】:

      首先,您需要在最后返回 head,以便返回列表,而不仅仅是最后一个元素。 第二件事,您需要修改 .next 引用,而不是在某些情况下分配它们。

      请注意,如果列表未排序,这将不起作用。

      之前:1 1 3 3
      之后:1 3

      这段代码有效(我已经测试过了)

      static Node RemoveDuplicates(Node head) {
          if (head == null) return null;
      
          Node current = head;
          Node runner = head;
      
          while (current != null && current.next != null) {
              runner = current.next;
              while (runner != null && runner.data == current.data) {
                  current.next = runner.next; // skip the repeat
                  runner = runner.next;
              }
              current = current.next;
          }
          return head;
      }
      

      【讨论】:

      • 好的,它可以工作。但是有没有办法在没有两个 while 循环的情况下做到这一点?
      • 我不这么认为,因为你需要继续推进跑步者,直到它看不到重复
      • 啊,好的,谢谢,我真的很想对所有这些指针魔法有一个深刻的理解
      • geeksforgeeks.org/?p=5075 这个链接在一个while循环中完成
      • @BoJackson 我最初的假设是 Zach 给出的上述代码适用于未排序的链表,而该链接中提供的代码仅适用于排序的链表。很多时候,对一个迭代进行排序会降低对该迭代的操作的复杂性。
      【解决方案4】:

      您可以在一次遍历中完成此操作。只需保持两个指针 temp 和 next_of_next。对每个节点进行temp迭代,当temp和next节点的数据相等时,将next_of_next指向temp后的alternate节点,删除temp后的节点。

      Node removeDuplicates(Node head)
      {
          Node temp = head;
          Node next_of_next;
          if (head == null)    
              return;
          while (temp.next != null) 
          {
              if (temp.data == temp.next.data) 
              {
                  next_of_next = temp.next.next;
                  temp.next = null;
                  temp.next = next_of_next;
              }
              else 
                 temp = temp.next;
          }
      return head ;
      }
      

      【讨论】:

      【解决方案5】:

      这里是使用HashSet 的无递归解决方案:

      public void RemoveDuplicates()
      {
          if (head != null)
          {
              var hm = new HashSet<T>();
              Node current = head;
              Node prev = null;
      
              while (current != null)
              {
                  if (!hm.Contains(current.Value))
                  {
                      hm.Add(current.Value);
                      prev = current;
                      current = current.Next;
                  }
                  else
                  {
                      prev.Next = current.Next;
                      current = prev.Next;
                  }
              }
          }
          return head;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-30
        • 2011-01-13
        相关资源
        最近更新 更多