简体   繁体   English

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

[英]How to find a missing element between two linked lists in O(n)?

I have two Singly Linked Lists of Integer. 我有两个单一链接的整数列表。 One of them is a subset of another (the order of numbers is different). 其中一个是另一个的子集(数字的顺序不同)。 What is the best way (regarding performance) to find a number which the first list does contain and the second one does not? 找到第一个列表包含的数字而第二个列表没有的最佳方法(关于性能)是什么?

My thought is first to sort them (using merge sort) and then just compare element by element. 我的想法是首先对它们进行排序(使用合并排序),然后逐个元素地进行比较。 So, it takes O(nlogn+mlogm+n) , but a better O(n) soltuion should exist. 因此,它需要O(nlogn+mlogm+n) ,但应该存在更好的O(n)解。

This is O(n) solution both in Time and Space. 这是时间和空间的O(n)解决方案。

Logic 逻辑

Lets say the original Linked List has size N we'll call it LL1 and second Linked List as LL2 . 让我们说原始的链表有大小N 我们称之为LL1第二个链表为LL2

=> Prepare a Hasmap of size N, key would be the numbers in the LL1 and value would be frequency in LL2 =>准备一个大小为N的HasmapkeyLL1numbersvalueLL2频率

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

=> Start traversing LL1 and set the frequency to 0 for all the Numbers =>开始遍历LL1并将所有数字的频率设置为0
By the time all values in LL1 is iterated, you have all the Numbers present in HashMap with frequency = 0 到迭代LL1所有值时, HashMap所有数字都存在频率= 0

 map.put(key, 0);

=> Now start looping through the LL2 , pick the numbers using them as key and increment the value by 1 . =>现在开始循环LL2 ,使用它们作为键选择数字并将值递增1
By the time all values in LL2 is iterated, you have all the common numbers present in both LL1 and LL1 inside HashMap having frequency > 0 LL2所有值都被迭代时, HashMapLL1LL1所有公共数都具有frequency > 0

  map.put(key, map.get(key) + 1);

=> Now start traversing the hasmap , searching for value = 0 , when found, print the key as this number present only in LL1 and not in LL2 =>现在开始遍历hasmap ,搜索value = 0 ,找到后,打印key因为此数字仅出现在LL1而不是LL2

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

2 Iterations and O(n) memory with O(n) time. 2迭代和O(n)内存,O(n)时间。

You can put both of them in different maps and then compare them. 您可以将它们放在不同的地图中,然后进行比较。 Putting in a map should be 2 single for loops of m & n and look up time for map is 1. 放入地图应该是2个单独的m&n循环,地图的查找时间是1。

HashSet is the best data structure to use in this case. HashSet是在这种情况下使用的最佳数据结构。 With this code, you can achieve your results in O(n). 使用此代码,您可以在O(n)中获得结果。 Let me know if you have more conditions, i can suggest something accordingly. 如果您有更多条件,请告诉我,我可以据此提出建议。

 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;
    }
    }

You can use removeAll method. 您可以使用removeAll方法。 All you have to do is create a method that accepts two lists, one is the original and the other is the sublist, then, return a list of missing elements: 您所要做的就是创建一个接受两个列表的方法,一个是原始列表,另一个是子列表,然后返回缺少元素的列表:

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

This runs in quadratic time though. 这虽然在二次时间内运行。

If you really want to force it to run in linear time, O(n), then you have to write custom class that wrap your inputs such that for each input, there is a flag that monitors whether or not it has been added to the sublist. 如果你真的想强制它以线性时间O(n)运行,那么你必须编写自定义类来包装你的输入,这样对于每个输入,都有一个标志来监视它是否已被添加到子表。 You can also design a class that facilitates addition and deletion of elements while monitoring the contents of both lists. 您还可以设计一个类,以便在监视两个列表的内容时促进元素的添加和删除。

Let N = m+n. 设N = m + n。

  • Add the lists. 添加列表。 As they are linked lists, this is cheap O(1). 由于它们是链表,这是便宜的O(1)。
  • Sort them O(N log N) - maybe better have used ArrayList. 对它们进行排序O(N log N) - 也许最好使用ArrayList。
  • Walk the list and on not finding a consecutive pair {x, x} you have found a missing one, O(N), as the second list is a subset. 走列表并且没有找到连续的对{x,x},你找到了一个丢失的对,O(N),因为第二个列表是一个子集。

So O(N . log N) . 所以O(N.log N)

As the lists are not ordered, any speedup consists of something like sorting, and that costs. 由于列表没有订购,任何加速都包括排序和成本等。 So O(N.log N) is fine. 所以O(N.log N)很好。

If you want O(N) you could do it as follows (simplified, using positive numbers): 如果你想要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;
    }

This trades memory against time. 这会使记忆与时间交换。 Mind this answer might not be accepted, as the memory is 2 MAX_VALUE which to initialize/clear costs time too. 请注意,这个答案可能不被接受,因为内存为2 MAX_VALUE ,用于初始化/清除成本时间。

The possible < O(N log N) solutions 可能的<O(N log N)解决方案

The most intelligent answer might be (quasi) sorting cooperatively both lists. 最聪明的答案可能是(准)排序合作两个列表。 And during the sort detect the missing element. 在排序期间检测缺失的元素。 Something like picking a haphazard "median" element and shifting shifting indices to split the lists, and divide and conquer. 有点像挑选一个随意的“中位数”元素并转移转移指数来分割列表,并分而治之。

If the list sizes differ by 1 如果列表大小相差1

Then you would only need to make the sums for every list, the difference being the missing value: O(N). 然后你只需要为每个列表做出总和,差异就是缺失值:O(N)。 Works with overflow. 适用于溢出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM