Java 降低这两种方法的时间复杂度?

Java 降低这两种方法的时间复杂度?,java,algorithm,Java,Algorithm,在上面的代码中,使用str1.containsAllstr2会破坏我的时间复杂性,因为我相信在本例中它是在^2上。我的问题是,如果不在^2上使用,如何比较两个数组/数组列表的内容。我所能想到的就是嵌套for循环,当然是在^2上 /* * Returns true if this and other are rankings of the same * set of strings; otherwise, returns false. Throws a * NullPointerExcept

在上面的代码中,使用str1.containsAllstr2会破坏我的时间复杂性,因为我相信在本例中它是在^2上。我的问题是,如果不在^2上使用,如何比较两个数组/数组列表的内容。我所能想到的就是嵌套for循环,当然是在^2上

/*
 * Returns true if this and other are rankings of the same
 * set of strings; otherwise, returns false. Throws a
 * NullPointerException if other is null. Must run in O(n)
 * time, where n is the number of elements in this (or other).
 */
public boolean sameNames(Ranking other)
{
    ArrayList<String> str1 = new ArrayList<String>();
    ArrayList<String> str2 = new ArrayList<String>();

    for(int i = 0; i < this.getNumItems(); i++){
        str1.add(this.getStringOfRank(i));
    }
    for(int i = 0; i < other.getNumItems(); i++){
        str2.add(other.getStringOfRank(i));
    }
    Collections.sort(str1);
    Collections.sort(str2);
    if(str1.size() == str2.size())
        return str1.containsAll(str2);
    else
        return false;
}
而这一个,这一定是Olog n。所以我使用了二进制搜索,但是它只对排序的数组起作用,所以我必须调用arrays.sort,但是我不能搞乱实际数组的顺序,所以我必须使用System.arraycopy复制数组。这很可能发生在+n log n+log n上,而不是log n。我不知道还有什么其他方法可以搜索某些内容,似乎logn是最好的,但这是二进制搜索,会迫使我首先对数组排序,这只会增加时间

另外,我不允许使用地图或集合…:

任何帮助都会很棒

抱歉,排名对象包含一个可以调用的城市名称数组,以及一个可以调用的每个城市的排名数组。sameNames只是测试两个排名对象拥有相同的城市,GetRankOffString输入了一个集合名称,然后检查该名称是否在排名对象中,如果是,则返回其相应的排名。希望一切都会好起来


是的,不能使用哈希值。我们基本上只限于处理数组和数组列表之类的东西。

让我们计算每个字符串的出现次数。这有点像

使用散列函数f创建一个t,其中键是字符串,值最初是0。 遍历第一个字符串,对于每个字符串,不要[fstring]++。 遍历第二个字符串,对于每个字符串,不要[fstring]++。 迭代t中的非零值,如果所有值都是偶数-返回true。否则-错误。
线性时间复杂度。

第一种方法的复杂度至少在^2上,由日志n+On^2上的2*On*fn+2*给出。On log n由Collections.sort调用给出,这也会“破坏”您所说的On复杂性

由于两个数组列表都已排序,并且在尝试containsAll时长度相等,因此该调用与某种类型的equals等效。一个列表中的第一个元素应与第二个列表中的第一个元素相等,以此类推。您可以轻松地手动比较两个列表,但无法想到任何内置函数可以做到这一点

因此,如果您可以将getStringOfRank的复杂度保持在Olog n下,但该函数没有显示在您的帖子中,那么第一段代码的总体复杂度可以降低到log n上

第二个函数与第一段代码无关,它的复杂性在logn上,正如您的计算所指出的。如果您已经复制了city数组,然后对其进行排序,那么二进制搜索是没有意义的。不要复制,不要排序,只需比较数组中的每个城市,将此函数的整个复杂性都放在上面。或者,只需保留city数组的排序副本,并对其使用二进制搜索

无论哪种方法,创建数组的副本,为每个函数调用对该副本进行排序都是非常无效的-如果要在循环内调用此函数,如上面使用的getStringOfRank,请在循环之前构造排序副本并将其用作参数:

/*
 * Returns the rank of name. Throws an IllegalArgumentException
 * if name is not present in the ranking. Must run in O(log n)
 * time, where n = this.getNumItems().
 */
public int getRankOfString(String name)
{       
    Cities[] nameTest = new Cities[city.length];
    int min = 0;
    int max = city.length;
    System.arraycopy(city, 0, nameTest, 0, city.length);
    Arrays.sort(nameTest, Cities.BY_NAME);
    while(max >= min){
        int mid = (min + max)/2;
        if(nameTest[mid].getName().equals(name))
            return nameTest[mid].getRank();
        else if(nameTest[mid].getName().compareTo(name) < 0)
            min = mid + 1;
        else
            max = mid-1;
    }
    throw new IllegalArgumentException();
}
离题:


基于第二个函数,在代码的某个地方声明了类似Cities[]city的内容。如果要遵循约定,它应该更像City[]cities类名单数,数组名应该是使用复数的,所以第一个只需要比较两个名称是否完全相同而没有其他名称

这个怎么样

private boolean getRankOfString(String name, Cities[] sortedCities) {
    // only binary search code needed here
}

理论上,我想您可能会遇到哈希冲突。

您没有说明函数应该做什么。有一些评论,但它们并不是很有帮助,因为它们引用了字符串排名的概念,但没有解释。实际上getStringofRank是O1倍。但是我复制了数组并在getRankofString中对其进行排序,因为我需要对城市名称进行排序,但实际上无法对真正的名称数组进行排序,因此需要一个副本。它们本来是未分类的,必须保持这种状态。而且我需要有getRankOfString的log n time,所以会太高,因此我使用了二进制搜索,而不是简单的搜索。无法使用任何与哈希相关的内容。。。但我所做的是在构造函数中创建一个复制的数组,然后对复制的数组进行排序,以便在不同的方法中使用。我的构造函数在日志n上,然后副本是+在日志n上,然后排序是另一个+在日志n上,所以最后我的构造函数应该仍然在日志n上,它必须是…:但这允许我利用OLOGN二进制搜索以及sameName测试。
public static boolean compare(List<String> l1, List<String> l2) {
  if (l1.size() != l2.size()) return false;
  long hash1 = 0;
  long hash2 = 0;
  for (int i = 0 ; i < l1.size() ; i++) {
    hash1 += l1.get(i).hashCode();
    hash2 += l2.get(i).hashCode();
  }
  return hash1 == hash2;
}