【问题标题】:Finding indexes of duplicates in an array查找数组中重复项的索引
【发布时间】:2021-06-21 14:55:39
【问题描述】:

编写一个程序,将用户输入作为一个整数数组,并显示该数组中的重复值及其索引。

规则:

在获取数组值之前,您需要先从用户那里获取数组大小 您的数组大小不能为零。 如果没有重复,您的程序需要显示该消息。

这是我的代码,但是当我用重复的数字填充数组时程序停止。它不会让我一直填满数组。如何解决?

package arraysPractice;
import java.util.*;
import java.util.Arrays;
public class homeworkArrays {
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        System.out.println("Please enter an array size: ");
        Scanner keyboard = new Scanner(System.in);

        int choice = keyboard.nextInt();
        int[] choiceArray = new int[choice];

        System.out.println("Please enter your array values: ");
        for (int i = 0; i <= choice; i++) {
            choiceArray[i] = keyboard.nextInt();
            for (int j = i + 1; j < choiceArray.length; j++) {
                if ((choiceArray[i] == choiceArray[j]) && (i != j)) {
                    System.out.print("Duplicate Element : " + choiceArray[j]);
                }
            }
        }
        System.out.println(Arrays.toString(choiceArray));
    }
}

【问题讨论】:

    标签: java arrays duplicates


    【解决方案1】:

    正如@KevinO 在评论中所说,你肯定有一个IndexOutOfBoundsException

    for (int i = 0; i &lt;= choice; i++); 应该是for (int i = 0; i &lt; choice; i++)

    请试试这个。

    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Scanner;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    
    class Scratch {
        public static void main(String[] args) {
            System.out.println("Please enter an array size:(Press 'enter key' to submit the value) ");
            Scanner keyboard = new Scanner(System.in);
    
            int choice = keyboard.nextInt();
    
            Integer[] choiceArray = new Integer[choice];
    
            System.out.println("Please enter your array digits:(Press 'enter key' to submit the digit) ");
    
            for (int i = 0; i < choice; i++)
                choiceArray[i] = keyboard.nextInt();
    
            List<Integer> list = Arrays.asList(choiceArray);
    
            Map<Integer, List<Integer>> map = IntStream.range(0, list.size()).boxed()
                    .collect(Collectors.groupingBy(list::get));
    
            final boolean[] foundDuplicates = {false};
    
            map.forEach((k, v) -> {
                if (v.size() > 1) {
                    foundDuplicates[0] = true;
                    System.out.println("digit: " + k + " | duplicate indexes: " + v);
                }
            });
    
            if (!foundDuplicates[0])
                System.out.println("No duplicate digits found!");
    
        }
    }
    
    

    【讨论】:

      【解决方案2】:

      使用 Stream API 构建一个值到索引的映射会很方便,然后根据索引列表的大小进行过滤并显示重复项:

      public static Map<Integer, Set<Integer>> getDuplicates(int ... data) {
          Map<Integer, Set<Integer>> duplicates = IntStream.range(0, data.length)
                  .boxed()
                  .collect(Collectors.groupingBy(i -> data[i], LinkedHashMap::new, Collectors.toSet()));
          duplicates.entrySet().removeIf(e -> e.getValue().size() < 2);
      
          return duplicates;
      }
      

      测试:

      getDuplicates(1, 2, 3, 1, 1, 3, 4, 5, 3, 2)
          .forEach((k, v) -> System.out.printf("Duplicate %d at %s%n", k, v));
      

      输出

      Duplicate 1 at [0, 3, 4]
      Duplicate 2 at [1, 9]
      Duplicate 3 at [2, 5, 8]
      

      或者可以改进输出以按照它们在输入中出现的顺序显示重复项:

      getDuplicates(1, 2, 3, 1, 1, 3, 4, 5, 3, 2)
      .entrySet().stream()
      .flatMap(e -> e.getValue().stream().map(ix -> Arrays.asList(e.getKey(), ix)))
      .sorted(Comparator.comparingInt(arr -> arr.get(1)))
      .forEach(arr -> System.out.printf("Duplicate %d at %s%n", arr.get(0), arr.get(1)));
      

      输出

      Duplicate 1 at 0
      Duplicate 2 at 1
      Duplicate 3 at 2
      Duplicate 1 at 3
      Duplicate 1 at 4
      Duplicate 3 at 5
      Duplicate 3 at 8
      Duplicate 2 at 9
      

      另一种不使用流的更简单方法:

      Map<Integer, List<Integer>> dups = new HashMap<>();
      int[] arr = {1, 2, 3, 1, 3, 1, 3, 4, 5, 3, 2};
      int i = 0;
      for (int x : arr) {
          dups.computeIfAbsent(x, (key) -> new ArrayList<>()).add(i++);
          if (dups.get(x).size() > 1) {
              List<Integer> ix = dups.get(x);
              if (ix.size() == 2) {
                  System.out.printf("Duplicate %d at %s%n", x, ix.get(0));
              }
              System.out.printf("Duplicate %d at %s%n", x, ix.get(ix.size() - 1));
          }
      }
      

      输出(不按索引排序)

      Duplicate 1 at 0
      Duplicate 1 at 3
      Duplicate 3 at 2
      Duplicate 3 at 4
      Duplicate 1 at 5
      Duplicate 3 at 6
      Duplicate 3 at 9
      Duplicate 2 at 1
      Duplicate 2 at 10
      

      【讨论】:

        【解决方案3】:

        您可以从此列表中收集重复的地图,如下所示:

        List<String> list = List.of("a", "b", "d", "b", "c", "a");
        
        Map<String, List<Integer>> map = IntStream
                .range(0, list.size())
                .boxed()
                .collect(Collectors.toMap(
                        // key - element of the list
                        list::get,
                        // value - list indices of these elements
                        i -> new ArrayList<>(List.of(i)),
                        // merge two lists
                        (l1, l2) -> {
                            l1.addAll(l2);
                            return l1;
                        },
                        // map with encounter order of elements
                        LinkedHashMap::new));
        
        // output
        map.forEach((k, v) -> System.out.println(k + "=" + v));
        //a=[0, 5]
        //b=[1, 3]
        //d=[2]
        //c=[4]
        

        【讨论】:

          【解决方案4】:

          这是我能想到的最好的方法,第二种方法也许可以即兴发挥:

          public class Util
          {
              public static Set<Integer> findDuplicates(List<Integer> numbers)
              {
                  Set<Integer> result = new HashSet<>();
                  return numbers.stream().filter(number -> !result.add(number)).collect(Collectors.toSet());
              }
          
              public static Map<Integer, Integer> findDuplicatesWithIndices(List<Integer> numbers)
              {
                  Map<Integer, Integer> result = new TreeMap<>();
                  Set<Integer> duplicates = findDuplicates(numbers);
          
                  int pos = 0;
          
                  for (Integer number : numbers)
                  {
                      if (duplicates.contains(number))
                      {
                          result.put(number, pos);
                      }
          
                      pos++;
                  }
          
                  return result;
              }
          
              public static void main(String[] args)
              {
                  List<Integer> numbers = new ArrayList<>(Arrays.asList(3, 4, 5, 6, 7, 8, 9, 3, 7, 7, 9, 4, 1, 2, 0));
                  Map<Integer, Integer> duplicatesWithIndices = findDuplicatesWithIndices(numbers);
                  duplicatesWithIndices.forEach((k, v) -> System.out.println("Value " + k + " duplicates at Index " + v));
              }
          }
          

          输出:

          Value 3 duplicates at Index 7
          Value 4 duplicates at Index 11
          Value 7 duplicates at Index 9
          Value 9 duplicates at Index 10
          

          现在,第一种方法 - findDuplicates 的速度非常快,但无法真正得出索引。我以传统方式使用地图来生成您所说的索引。

          在我声明 List 的 main 方法中,您可以从用户那里获取值并将其放在那里。然后按你喜欢的输出打印。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-29
            • 2017-03-08
            • 1970-01-01
            • 2020-06-17
            • 1970-01-01
            • 1970-01-01
            • 2018-11-22
            • 1970-01-01
            相关资源
            最近更新 更多