Java 如何在O(n)中的两个链表之间查找缺少的元素?
我有两个单独的整数链表。其中一个是另一个的子集(数字的顺序不同)。查找第一个列表中不包含而第二个列表中不包含的数字的最佳方法(关于性能)是什么 我的想法是首先对它们进行排序(使用合并排序),然后逐个元素进行比较。Java 如何在O(n)中的两个链表之间查找缺少的元素?,java,linked-list,difference,Java,Linked List,Difference,我有两个单独的整数链表。其中一个是另一个的子集(数字的顺序不同)。查找第一个列表中不包含而第二个列表中不包含的数字的最佳方法(关于性能)是什么 我的想法是首先对它们进行排序(使用合并排序),然后逐个元素进行比较。 因此,它需要O(nlogn+mlogm+n),但是应该存在一个更好的O(n)解决方案。您可以将它们放在不同的映射中,然后比较它们。对于m&n循环,放入映射应该是2个单循环,映射的查找时间是1。在这种情况下,哈希集是最好的数据结构。 使用此代码,您可以在O(n)中实现结果。 如果你有更多
因此,它需要
O(nlogn+mlogm+n)
,但是应该存在一个更好的O(n)
解决方案。您可以将它们放在不同的映射中,然后比较它们。对于m&n循环,放入映射应该是2个单循环,映射的查找时间是1。在这种情况下,哈希集是最好的数据结构。
使用此代码,您可以在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;
}
}
公共类链接列表{
私有节点头;
公共ListNode getHead(){
回流头;
}
}
公共类列表节点{
公共价值观;
公共列表节点下一步;
ListNode(int值){
这个值=值;
}
}
公共类UtilClass{
公共静态int检查列表(LinkedList列表1,LinkedList列表){
ListNode head=myList2.getHead();
HashSet HashSet=新的HashSet();
while(head!=null){
hashSet.add(head.value);
head=head.next;
}
head=myList.getHead();
while(head!=null){
布尔b=hashSet.add(head.value);
如果(b==true),则返回head.value;
head=head.next;
}
返回-1111;
}
}
您可以使用removeAll方法。您只需创建一个方法,该方法接受两个列表,一个是原始列表,另一个是子列表,然后返回缺少元素的列表:
List getMissing(List original, List sub){
original.removeAll(sub);
return original;
}
不过,这是以二次时间运行的
如果您真的想强制它在线性时间O(n)中运行,那么您必须编写自定义类来包装您的输入,这样对于每个输入,都有一个标志来监视它是否已添加到子列表中。您还可以设计一个类,在监视两个列表的内容的同时方便添加和删除元素。这在时间和空间上都是O(n)解决方案
逻辑
假设原始链表的大小为N,我们称之为LL1
,第二个链表为LL2
=>准备一个大小为N的Hasmap
,键将是LL1
中的数字,而值将是LL2
中的频率
HashMap<Integer,Integer> map= new HashMap<Integer,Integer>();
for (map.Entry<Integer,Integer> entry : map.entrySet())
{
if(entry.getValue() == 0)
System.out.println(entry.getKey());//This is a loner
}
=>现在开始在LL2
中循环,选择数字作为键,在迭代LL2
中的所有值时,将值增加1
,您在LL1
和LL1
中都有所有公共数字,它们位于HashMap
内部,具有frequency>0
map.put(key, map.get(key) + 1);
=>现在开始遍历hasmap
,搜索值=0
,找到后,打印键
,因为该数字仅出现在LL1
中,而不出现在LL2
HashMap<Integer,Integer> map= new HashMap<Integer,Integer>();
for (map.Entry<Integer,Integer> entry : map.entrySet())
{
if(entry.getValue() == 0)
System.out.println(entry.getKey());//This is a loner
}
for(map.Entry:map.entrySet())
{
if(entry.getValue()==0)
System.out.println(entry.getKey());//这是一个孤独的人
}
2次迭代和O(n)内存以及O(n)时间。设n=m+n
- 添加列表。因为它们是链表,所以这是廉价的O(1)
- 对它们进行排序O(N log N)-最好使用ArrayList
- 沿着列表走一走,如果没有找到一个连续的对{x,x},你就找到了一个缺失的对,O(N),
因为第二个列表是一个子集
所以O(N.logn)
由于列表没有排序,因此任何加速都包括排序之类的内容,这会产生成本。所以O(N.logn)是好的
如果您想要O(N)可以按如下方式操作(简化,使用正数):
这是用记忆和时间来交换的。请注意,这个答案可能不被接受,因为内存是2MAX_值初始化/清除它也需要时间
可能的
最明智的答案可能是(准)协同排序两个列表。并在排序过程中检测缺失的元素。比如选择一个随意的“中位数”元素,移动索引来分割列表,然后分而治之
如果列表大小相差1
然后,您只需要对每个列表求和,差就是缺少的值:O(N)。
用于溢出。只需要一个映射/集:用第一个列表的内容填充它,然后在迭代第二个列表时探测它。请提供一些代码片段。请随意编辑答案。更好的解决方案是不要使用链表来表示集合。使用集合
@Gene OP可能需要保持顺序(因为他/她提到的顺序是不同的),尽管在这里使用集合可能有用。对于两个小列表,O(n*m)暴力可能是“最快的”。。我想这些序列的规模很大,但请记住找到并关注实际的瓶颈。@user2864740那么他应该使用LinkedHashSet
@这可能是另一种可能性。然而,我不知道代码使用了什么(其他)算法,比如一个排序链表。