Java 以下代码的复杂性

Java 以下代码的复杂性,java,algorithm,performance,Java,Algorithm,Performance,我被赋予以下任务: 给定-2个列表。第一个列表的大小为N1,第二个列表的大小为N2。每个列表的元素并不相同。 编写一段代码,用第一个和第二个列表中的元素创建一个新列表。此列表也不应包含相同的元素。 还要估计代码的复杂性 我编写以下代码: public class Lists { static ArrayList<Integer> getNewList(ArrayList<Integer> list1,

我被赋予以下任务:

给定-2个列表。第一个列表的大小为N1,第二个列表的大小为N2。每个列表的元素并不相同。 编写一段代码,用第一个和第二个列表中的元素创建一个新列表。此列表也不应包含相同的元素。 还要估计代码的复杂性

我编写以下代码:

public class Lists {    
    static ArrayList<Integer> getNewList(ArrayList<Integer> list1, 
                                         ArrayList<Integer> list2) {
        ArrayList<Integer> tmp = new ArrayList<>();
        for (Integer i : list1) {
            tmp.add(i);
        }
        for (Integer i : list2) {
            if (!list1.contains(i)) 
                tmp.add(i);
        }
        return tmp;
    }

    public static void main(String[] args) { 
        Integer[] arr1 = {1, 2, 3, 14, 15, 16};        
        Integer[] arr2 = {3, 6, 7, 8, 14};
        ArrayList<Integer> list1 = new ArrayList<>(Arrays.asList(arr1));
        ArrayList<Integer> list2 = new ArrayList<>(Arrays.asList(arr2));
        for (Integer i : getNewList(list1, list2)) {
            System.out.print(i + " ");
        }
    }
}
公共类列表{
静态ArrayList getNewList(ArrayList list1,
ArrayList(列表2){
ArrayList tmp=新的ArrayList();
for(整数i:list1){
tmp.add(i);
}
for(整数i:list2){
如果(!list1.contains(i))
tmp.add(i);
}
返回tmp;
}
公共静态void main(字符串[]args){
整数[]arr1={1,2,3,14,15,16};
整数[]arr2={3,6,7,8,14};
ArrayList list1=新的ArrayList(Arrays.asList(arr1));
ArrayList list2=新的ArrayList(Arrays.asList(arr2));
for(整数i:getNewList(列表1、列表2)){
系统输出打印(i+“”);
}
}
}
假设getNewList方法的执行时间与N1*N2成正比。作为回复,我收到了以下没有任何解释的信息——“你错了,这段代码的复杂性不是N1*N2”


有人能说出正确答案吗?并解释复杂性是如何确定的?

您的代码的复杂性是
O(N1*N2)
,但使用
哈希集来确定两个列表中出现的数字,您可以做得更好:

static ArrayList<Integer> getNewList(ArrayList<Integer> list1, 
                                     ArrayList<Integer> list2) {
    ArrayList<Integer> tmp = new ArrayList<>();
    HashSet<Integer> dups = new HashSet<>();
    tmp.addAll(list1);
    dups.addAll(list1);
    for (Integer i : list2) {
        if (!dups.contains(i)) 
            tmp.add(i);
    }
    return tmp;
}
静态ArrayList getNewList(ArrayList list1,
ArrayList(列表2){
ArrayList tmp=新的ArrayList();
HashSet dups=新HashSet();
tmp.addAll(列表1);
dups.addAll(列表1);
for(整数i:list2){
如果(!dups.包含(i))
tmp.add(i);
}
返回tmp;
}

这将为您提供
O(N1+N2)
运行时间,因为插入和查找需要
O(1)
时间在
HashSet
中。代码的复杂性是
O(N1*N2)
,但您可以使用
HashSet
来确定两个列表中出现的数字:

static ArrayList<Integer> getNewList(ArrayList<Integer> list1, 
                                     ArrayList<Integer> list2) {
    ArrayList<Integer> tmp = new ArrayList<>();
    HashSet<Integer> dups = new HashSet<>();
    tmp.addAll(list1);
    dups.addAll(list1);
    for (Integer i : list2) {
        if (!dups.contains(i)) 
            tmp.add(i);
    }
    return tmp;
}
静态ArrayList getNewList(ArrayList list1,
ArrayList(列表2){
ArrayList tmp=新的ArrayList();
HashSet dups=新HashSet();
tmp.addAll(列表1);
dups.addAll(列表1);
for(整数i:list2){
如果(!dups.包含(i))
tmp.add(i);
}
返回tmp;
}

这将给您
O(N1+N2)
运行时间,因为插入和查找需要
O(1)
时间在
HashSet

感谢@Slanec的解释,我重新检查了JDK中
contains(objectobj)
的实现,发现如下所示

public boolean contains(Object obj) {
    return indexOf(obj) >= 0;
}

public int indexOf(Object obj) {
    if (obj == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i] == null)
                return i;

    } else {
        for (int j = 0; j < size; j++)
            if (obj.equals(elementData[j]))
                return j;

    }
    return -1;
}
公共布尔包含(对象obj){
返回索引of(obj)>=0;
}
public int indexOf(对象对象对象){
if(obj==null){
对于(int i=0;i
显然,
contains(objectobj)
的时间复杂度是O(n)。(起初我以为是O(1)


因此代码的时间复杂度应该是O(N1*N2),而不是O(n

感谢@Slanec的解释,我重新检查了JDK中
contains(objectobj)
的实现,发现如下所示

public boolean contains(Object obj) {
    return indexOf(obj) >= 0;
}

public int indexOf(Object obj) {
    if (obj == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i] == null)
                return i;

    } else {
        for (int j = 0; j < size; j++)
            if (obj.equals(elementData[j]))
                return j;

    }
    return -1;
}
公共布尔包含(对象obj){
返回索引of(obj)>=0;
}
public int indexOf(对象对象对象){
if(obj==null){
对于(int i=0;i
显然,
contains(objectobj)
的时间复杂度是O(n)。(起初我以为是O(1)


因此代码的时间复杂度应该是O(N1*N2),而不是O(n

我肯定也看到了
O(N1*N2)
的复杂性。我猜你的教授忽略了下面的
包含
调用的成本:

for (Integer i : list2) {
    if (!list1.contains(i)) 
        tmp.add(i);
}

包含
在ArrayList上是
O(N)
复杂度。由于您在列表2上的循环也是
O(N)
,因此您最终会遇到
O(N1*N2)
我肯定也看到了
O(N1*N2)
的复杂性。我猜你的教授忽略了下面的
包含
调用的成本:

for (Integer i : list2) {
    if (!list1.contains(i)) 
        tmp.add(i);
}

包含
在ArrayList上是
O(N)
复杂度。由于您在列表2上的循环也是
O(N)
,您最终得到的是
O(N1*N2)

好吧,您的问题的简短答案是:复杂性是N1+(N2*N1)/2+N3(新列表的大小),它应该是O(N1*N2)

细分:

for (Integer i : list1) {
  tmp.add(i);
} 
-> clearly, this is N1


在main中有一个循环,从0到N3(这是新列表的长度)进行迭代


所以,总的来说,你得到的是N1+(N2*N1)/2+N3,应该是O(N1*N2)

你的问题的简单答案是:复杂性是N1+(N2*N1)/2+N3(新列表的大小),应该是O(N1*N2)

细分:

for (Integer i : list1) {
  tmp.add(i);
} 
-> clearly, this is N1


在main中有一个循环,从0到N3(这是新列表的长度)进行迭代


所以,总的来说,你得到的是N1+(N2*N1)/2+N3,应该是O(N1*N2)

除非你能用一个实际的解释来证明我是错的,否则我会说不。第二个循环对
列表2
中的每个元素进行
检查,并对照
列表1
。对列表的
contains()
调用是线性的,O(N1),循环本身是显而易见的