Java 测试长度为n的未排序整数列表是否表示集合{1,…,n}

Java 测试长度为n的未排序整数列表是否表示集合{1,…,n},java,algorithm,Java,Algorithm,现在我有以下的解决方案,我相信这是相当清楚的 import java.util.Arrays; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; public class ConsecutiveNumbers { public static void main(String[] args) { List<Integer> good = Arrays.asList(2,

现在我有以下的解决方案,我相信这是相当清楚的

import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

public class ConsecutiveNumbers {
  public static void main(String[] args) {
    List<Integer> good = Arrays.asList(2, 1);
    System.out.println(is1ToN(good)); // true

    List<Integer> bad1 = Arrays.asList(3, 1);
    System.out.println(is1ToN(bad1)); // false

    List<Integer> bad2 = Arrays.asList(1, 1, 2);
    System.out.println(is1ToN(bad2)); // false
  }

  public static boolean is1ToN(List<Integer> numbers) {
    SortedSet<Integer> set = new TreeSet<>(numbers);
    return set.isEmpty() || (set.size() == numbers.size() && set.first() == 1
        && set.last() == set.size());
  }
}
导入java.util.array;
导入java.util.List;
导入java.util.SortedSet;
导入java.util.TreeSet;
公共类连续数{
公共静态void main(字符串[]args){
List good=Arrays.asList(2,1);
System.out.println(is1ToN(good));//true
List bad1=Arrays.asList(3,1);
System.out.println(is1ToN(bad1));//false
List bad2=Arrays.asList(1,1,2);
System.out.println(is1ToN(bad2));//false
}
公共静态布尔值为1ton(列表编号){
SortedSet集合=新树集合(编号);
返回set.isEmpty()| |(set.size()==numbers.size()&&set.first()==1
&&set.last()==set.size());
}
}

有更好(更有效或更清晰)的解决方案吗?

根据我的意见,实施方案可能是:

public static boolean is1ToN(List<Integer> numbers) {
  Set<Integer> set = new HashSet<>(numbers);
  if (set.size() != numbers.size()) {
    return false;
  }
  for (int i = 1; i < numbers.size() + 1; i++) {
    if (!set.contains(i)) {
      return false;
    }
  }
  return true;
}
公共静态布尔值为1ton(列表编号){
Set Set=新哈希集(数字);
如果(set.size()!=numbers.size()){
返回false;
}
对于(int i=1;i
根据我的评论,一个实现可能是:

public static boolean is1ToN(List<Integer> numbers) {
  Set<Integer> set = new HashSet<>(numbers);
  if (set.size() != numbers.size()) {
    return false;
  }
  for (int i = 1; i < numbers.size() + 1; i++) {
    if (!set.contains(i)) {
      return false;
    }
  }
  return true;
}
公共静态布尔值为1ton(列表编号){
Set Set=新哈希集(数字);
如果(set.size()!=numbers.size()){
返回false;
}
对于(int i=1;i
创建一个大小为N的布尔数组p。遍历列表,依次考虑列表中每个元素的值v。如果v超出范围1…n,则返回false。如果p[v-1]为真,则有一个重复值,因此答案为假。否则,将p[v-1]设置为true。如果到达列表的末尾,请返回true


使用位集而不是数组可能值得,也可能不值得。这将节省一些内存,尽管所需的额外内存仍然是O(N)。但是它会增加CPU的工作。交易是否值得取决于用例。

创建一个大小为N的布尔数组p。遍历列表,依次考虑列表中每个元素的值v。如果v超出范围1…n,则返回false。如果p[v-1]为真,则有一个重复值,因此答案为假。否则,将p[v-1]设置为true。如果到达列表的末尾,请返回true


使用位集而不是数组可能值得,也可能不值得。这将节省一些内存,尽管所需的额外内存仍然是O(N)。但是它会增加CPU的工作。交易是否值得取决于用例。

构建
TreeSet
需要
O(n log n)
时间。如果您维护一个布尔数组
exists
,并将列表中的元素设置为true,并检查是否在第二遍中设置了每个元素,则会得到
O(n)
。但对于具体的场景,必须评估哪一个更有效。排序集需要o(n*log(n))来创建,因为它必须对事物进行排序。一个较短的解决方案是创建一个简单的集合(o(n)来创建),验证它的大小是否正确,然后验证它是否包含所有元素。由于
contains
在一个集合中是常数时间,这将需要o(n)过度分配您的算法-即您试图做什么以及如何做-将使您的问题更具可读性。构建
TreeSet
需要
o(n log n)
时间。如果您维护一个布尔数组
exists
,并将列表中的元素设置为true,并检查是否在第二遍中设置了每个元素,则会得到
O(n)
。但对于具体的场景,必须评估哪一个更有效。排序集需要o(n*log(n))来创建,因为它必须对事物进行排序。一个较短的解决方案是创建一个简单的集合(o(n)来创建),验证它的大小是否正确,然后验证它是否包含所有元素。由于
contains
在一个集合中是常数时间,这将需要o(n)过度分配您的算法-即您试图做什么以及如何做-将使您的问题更具可读性。好主意。但是,不要创建布尔数组,而是使用位集。好主意。但是,不要创建布尔数组,而是使用位集。