查找第二次出现索引最低的第一个重复元素

Posted

技术标签:

【中文标题】查找第二次出现索引最低的第一个重复元素【英文标题】:Find first duplicate element with lowest second occurrence index 【发布时间】:2017-08-14 03:28:23 【问题描述】:

我正在尝试解决 CodeFights 上名为 firstDuplicate 的问题 -

给定一个数组 a 只包含从 1 到 a.length,找到第二个重复的数字 出现具有最小索引。换句话说,如果有更多 超过 1 个重复的数字,返回第二个的数字 出现的索引小于另一个的第二次出现 号码可以。如果没有这样的元素,则返回 -1。

例子

对于a = [2, 3, 3, 1, 5, 2],输出应该是firstDuplicate(a) = 3.

有 2 个重复项:数字 2 和 3。第二次出现 3 具有比第二次出现的 2 小的索引,因此 答案是 3。

对于 a = [2, 4, 3, 5, 1],输出应该是 firstDuplicate(a) = -1。

我的解决方案 -

public class FirstDuplicate 
    private static HashMap<Integer, Integer> counts = new HashMap<>();

    private static void findSecondIndexFrom(int[] num, int n, int i) 
    // given an array, a starting index and a number, find second occurrence of that number beginning from next index
        for(int x = i; x < num.length; x++) 
            if(num[x] == n) 
              // second occurrence found - place in map and terminate
                counts.put(n, x);
                return;
            
        


    

    private static int firstDuplicate(int[] a) 
        // for each element in loop, if it's not already in hashmap
        // find it's second occurrence in array and place number and index in map

        for(int i = 0; i < a.length; i++) 
            if(!counts.containsKey(a[i])) 
                findSecondIndexFrom(a, a[i], i+1);
            
        

        System.out.println(counts);
        // if map is empty - no duplicate elements, return -1
        if(counts.size() == 0) 
            return -1;
        
        // else - get array of values from map, sort it, find lowest value and return corresponding key

        ArrayList<Integer> values = new ArrayList<>(counts.values());
        Collections.sort(values);
        int lowest = values.get(0);
        //System.out.println(lowest);
        for(Map.Entry<Integer, Integer> entries: counts.entrySet()) 
            if(entries.getValue() == lowest) 
                return entries.getKey();
            
        
     return -1;
    

    public static void main(String[] args) 
         // int[] a = new int[]2, 3, 3, 1, 5, 2;
         //int[] a = new int[]2, 4, 3, 5, 1;
         //int[] a = new int[]8, 4, 6, 2, 6, 4, 7, 9, 5, 8;
        //int[] a = new int[]1, 1, 2, 2, 1;

        int[] a = new int[]10, 6, 8, 4, 9, 1, 7, 2, 5, 3;
        System.out.println(firstDuplicate(a));
    



该解决方案仅在 CodeFights 上的 11 个测试用例中的大约 4 个通过。但是,我在 IDE 中手动执行了每个测试用例,每个测试用例都产生了正确的结果。

我不明白为什么这在 CodeFights 中不起作用。和使用静态HashMap有关系吗?

【问题讨论】:

可能是,尝试在firstDuplicate()的开头添加counts.clear()... 关于如何在不使用额外空间的情况下解决此问题的任何想法(此处为地图) 为什么需要地图?,跟踪最小索引就够了 @IshaAgarwal 我尝试了另一种不使用任何额外存储(地图或集合)的方法。此方法使用两个int 变量来检查/跟踪当前最低的第二索引和具有最低第二索引值的元素,并仅在满足条件时在后续迭代中设置这些变量。代码在这个Github Gist 上。虽然所有示例测试都通过了,但似乎有 2 个自定义测试失败,所以我需要进一步完善它。但很确定这是O(1) space comp 的方式。 【参考方案1】:

已编辑:由于添加和检查 Set 中是否存在元素可以一步完成,因此代码可以简化为:

public static int findDuplicateWithLowestIndex(int... a)
Set<Integer> set = new HashSet<>();
   for(int num : a)
     if(!set.add(num))
        return num;
       
    
return -1; 

你完全正确,帕特里克。

【讨论】:

更高效:if (!set.add(num)) return num; @Snusifer 我的评论正在改进以前版本的答案。点击“已编辑”链接查看帖子历史记录以了解更改内容。【参考方案2】:

使用这个解决方案:这里的 duplicateIndex 应该是非常大的数字。

    package sample;

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    public class Duplicate 

public static Integer secondIndex(Integer[] arr) 
    List<Integer> arrlist = new ArrayList<>(Arrays.asList(arr));
    int duplicateIndex = 999;
    int ele = 0;

    for (int i = 0; i < arrlist.size(); i++) 
        int secondIndex = getSecondIndex(arrlist, arrlist.get(i));

        if (secondIndex >= 0 && duplicateIndex > secondIndex) 
            duplicateIndex = secondIndex;
            ele = arrlist.get(i);
        
    

    return duplicateIndex == 999 ? -1 : ele;


public static int getSecondIndex(List<Integer> arr, int ele) 
    List<Integer> var0 = new ArrayList<>(arr);
    var0.set(var0.indexOf(ele), -1);
    return var0.indexOf(ele);


public static void main(String[] str) 
    // Integer[] arr = new Integer[]  2, 3, 3, 1, 5, 2 ;
    // Integer[] arr = new Integer[]  2, 4, 3, 5, 1 ;
    // Integer[] arr = new Integer[]  8, 4, 6, 2, 6, 4, 7, 9, 5, 8 ;
    // Integer[] arr = new Integer[]1, 1, 2, 2, 1;
    Integer[] arr = new Integer[]  10, 6, 8, 4, 9, 1, 7, 2, 5, 3 ;
    System.out.println(secondIndex(arr));


【讨论】:

以上是关于查找第二次出现索引最低的第一个重复元素的主要内容,如果未能解决你的问题,请参考以下文章

查找重复行的索引 [重复]

查找重复行的索引 [重复]

根据数组中的重复模式更改 SwiftUI 列表中文本字段的第二次出现

数组442. 数组中重复的数据

在Java中的字符串中查找第二次出现的子字符串

仅替换模式中的第二次出现