目前,在我正在工作的应用程序中,我得到了一系列数字,其中数字可能丢失和重复,但以升序排列。有两个问题。1.如果没有重复的数字,使用提及问题的公认答案中建议的方法,找到缺失的数字是相当容易的。1.但是,如果有重复的,这种方法就不再有效了。我该如何解决这个问题呢?似乎没有逻辑可以解决。而且即使可以(使用循环),也不会有效率。
czq61nw11#
据我所知,除了循环遍历之外,没有任何方法可以检测列表中缺失的数字。如果您的数组已排序,则它应如下所示:
[1,2,3,3,4,6]
因此,这段代码应该完成以下工作:
int getMissingNumber(int[] numbers){ for (int i=0; i<numbers.length -1; i++){ int current = numbers[i]; int next = numbers[i+1]; if(next - current > 1){ return current + 1; } } return -1; }
除此之外,还可以选择将Array更改为Set,然后再更改回Array,然后使用前面的方法。请确保使用LinkedHashSet以保持插入顺序。但我不知道是否会更快。
Array
Set
LinkedHashSet
h6my8fg22#
我只是想看看是否可以尽可能多地分解任务,使用Fork Join作为一个有趣的练习来更好地了解库,并将其与简单的for循环进行对比。
public class misc { public void getMissingNumbers(int[] numbers){ for (int i=0; i<numbers.length -1; i++){ int current = numbers[i]; int next = numbers[i+1]; if(current+1 != next){ System.out.println("Problem! - "+current+" "+next); } } } public static void main(String []args){ int[] range = IntStream.rangeClosed(1, 50_000_000).toArray(); int index = 50000; range[index] = range[index-1]; //duplicate index = 390; range[index] = range[index-1]; index = 500390; range[index] = range[index-1]; index = 2500390; range[index] = range[index-1]; ZonedDateTime now = ZonedDateTime.now(); misc m = new misc(); m.getMissingNumbers(range); System.out.printf("%s exec time: %dms\n", m.getClass().getSimpleName(), ChronoUnit.MILLIS.between(now, ZonedDateTime.now())); now = ZonedDateTime.now(); ForkJoinPool forkJoinPool = ForkJoinPool.commonPool(); breakDownRecursively bdr = new breakDownRecursively(range); forkJoinPool.invoke(bdr); System.out.printf("%s exec time: %dms\n", bdr.getClass().getSimpleName(), ChronoUnit.MILLIS.between(now, ZonedDateTime.now())); } } class breakDownRecursively extends RecursiveAction { private final int[] arr; private final ArrayList<Integer> arrlst = new ArrayList<>(); public breakDownRecursively(int[] arr) { this.arr = arr; } public void compute() { int n = arr.length; if (arr.length < 2) return; int mid = arr.length / 2; int[] left = new int[mid]; System.arraycopy(arr, 0, left, 0, mid); int[] right = new int[arr.length - mid]; System.arraycopy(arr, mid, right, 0, arr.length - mid); invokeAll(new breakDownRecursively(left), new breakDownRecursively(right)); compare(left, right); } private void compare(int[] left, int[] right) { if (left.length == 1 && right.length == 1) { if (left[0]+1 != right[0]) { //System.out.println("Problem! - "+left[0]+" "+right[0]); } }else if (left.length <= 2 && right.length <=2) { int size = left.length-1; if (left[size]+1 != right[0]) { System.out.println("Problem! - "+left[size]+" "+right[0]); } }else { return; } } }
输出:
Problem! - 50000 50002 Problem! - 500390 500390 Problem! - 500390 500392 Problem! - 2500390 2500390 Problem! - 2500390 2500392 misc exec time: 59ms Problem! - 390 390 Problem! - 50000 50002 Problem! - 500390 500390 Problem! - 2500390 2500390 breakDownRecursively exec time: 2320ms
我想我可能在实现fork join的过程中犯了一个错误,但是至少你应该看到for循环并没有那么糟糕。
2条答案
按热度按时间czq61nw11#
据我所知,除了循环遍历之外,没有任何方法可以检测列表中缺失的数字。
如果您的数组已排序,则它应如下所示:
因此,这段代码应该完成以下工作:
除此之外,还可以选择将
Array
更改为Set
,然后再更改回Array
,然后使用前面的方法。请确保使用LinkedHashSet
以保持插入顺序。但我不知道是否会更快。h6my8fg22#
我只是想看看是否可以尽可能多地分解任务,使用Fork Join作为一个有趣的练习来更好地了解库,并将其与简单的for循环进行对比。
输出:
我想我可能在实现fork join的过程中犯了一个错误,但是至少你应该看到for循环并没有那么糟糕。