如何在O(n)中找到两个链表之间缺少的元素?

时间:2014-09-29 02:55:22

标签: java linked-list difference

我有两个单一链接的整数列表。其中一个是另一个的子集(数字的顺序不同)。找到第一个列表包含的数字而第二个列表没有的最佳方法(关于性能)是什么?

我的想法是首先对它们进行排序(使用合并排序),然后逐个元素地进行比较。 因此,它需要O(nlogn+mlogm+n),但应该存在更好的O(n)解决方案。

5 个答案:

答案 0 :(得分:2)

这是时间和空间的O(n)解决方案。

<强>逻辑

假设原始链接列表的大小为N ,我们将其称为LL1 ,将第二个链接列表称为LL2

=&gt; 准备一个大小为N的Hasmapkey将是numbersLL1中的value频率为LL2

 HashMap<Integer,Integer> map= new HashMap<Integer,Integer>();

=&gt; 开始遍历LL1并将所有数字的频率设置为0,当迭代LL1中的所有值时,您有HashMap中频率= 0

的所有数字
 map.put(key, 0);

=&gt; 现在开始循环浏览LL2,使用它们作为键选择数字并将值增加1
到所有时候LL2中的值会被迭代,LL1LL1HashMap frequency > 0内的所有公共数字都会 map.put(key, map.get(key) + 1);

hasmap

=&gt; 现在开始遍历value = 0,搜索key,找到后,打印LL1,因为此号码仅出现在{{1}而不是LL2

for (map.Entry<Integer,Integer> entry : map.entrySet())
{
    if(entry.getValue() == 0)
        System.out.println(entry.getKey());//This is a loner
}

2次迭代和O(n)内存,O(n)时间。

答案 1 :(得分:1)

您可以将它们放在不同的地图中,然后进行比较。放入地图应该是2个单独的m&amp; n并查找地图的时间是1。

答案 2 :(得分:0)

HashSet是在这种情况下使用的最佳数据结构。 使用此代码,您可以在O(n)中获得结果。 如果您有更多条件,请告诉我,我可以据此提出建议。

 public class LinkedList {

        private ListNode head;

        public ListNode getHead() {
            return head;
        }
    }

    public class ListNode {

        public int value;
        public ListNode next;

        ListNode(int value) {
            this.value = value;
        }
    }

    public class UtilClass{
       public static int checkLists(LinkedList list1, LinkedList list){
            ListNode head = myList2.getHead();

            HashSet<Integer> hashSet = new HashSet<Integer>();

            while(head!=null){
                hashSet.add(head.value);
                head = head.next;
            }

            head = myList.getHead();

            while(head!=null){
                boolean b = hashSet.add(head.value);
                if(b == true) return head.value;
                head = head.next;
            }
             return -1111;
    }
    }

答案 3 :(得分:0)

您可以使用removeAll方法。您所要做的就是创建一个接受两个列表的方法,一个是原始列表,另一个是子列表,然后返回缺少元素的列表:

List getMissing(List original, List sub){
     original.removeAll(sub);
     return original;
}

虽然这是以二次方式运行的。

如果你真的想强制它以线性时间O(n)运行,那么你必须编写自定义类来包装你的输入,这样对于每个输入,都有一个标志来监视它是否已经存在添加到子列表中。您还可以设计一个类,以便在监视两个列表的内容时促进元素的添加和删除。

答案 4 :(得分:0)

设N = m + n。

  • 添加列表。由于它们是链表,这很便宜O(1)。
  • 对它们进行排序O(N log N) - 也许最好使用ArrayList。
  • 走完列表并且找不到连续的对{x,x},你发现了一个丢失的,O(N), 因为第二个列表是一个子集。

所以 O(N.log N)

由于列表没有订购,任何加速都包括排序和成本等。所以O(N.log N)没问题。

如果您想要 O(N) 可以按照以下方式执行此操作(简化,使用正数):

BitSet present = new BitSet(Integer.MAX_VALUE);
for (int value : sublist)
    present.set(value);
for (int value : list)
    if (!present.isSet(value)) {
        System.out.println("Missing: " + value);
        break;
    }

这会使记忆与时间交换。请注意,这个答案可能不被接受,因为内存 2 MAX_VALUE ,这也是初始化/清算成本时间。

可能的&lt; O(N log N)解决方案

最聪明的答案可能是(准)排序合作两个列表。在排序期间检测缺失的元素。就像挑选一个偶然的“中位数”元素和转移指数以分割列表,分裂和征服一样。

如果列表大小相差1

然后你只需要为每个列表计算总和,差异是缺失值:O(N)。 适用于溢出。