找到具有最小索引的数组中的第一个重复元素

时间:2018-05-29 10:09:36

标签: java arrays hashset

我有一个包含一些重复元素的数组:

找到第二个匹配项具有最小索引的第一个重复数字。换句话说,如果有多于1个重复的数字,则返回第二次出现的索引小于另一个出现的第二次出现的索引的数量。如果没有这样的元素,则返回-1

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

有两个重复:数字2和3.第二次出现的3的索引小于第二次出现的2,所以答案是3。

我试过了:

int firstDuplicate(int[] a) {
  Set<Integer> set = new HashSet<>();
  Map<Integer, Integer> hm = new HashMap<Integer,Integer>();
  Map.Entry<Integer, Integer> min = null;
  for(int i=0;i<a.length;i++){
       // if(!hm.containsKey(a[i]))
              hm.put(a[i],i);
  }
  for(Map.Entry<Integer,Integer> entry : hm.entrySet()){
        if(min == null || entry.getValue() < min.getValue()){
              min = entry;
        }
  }
  return min == null ? new Integer(-1) : min.getKey();

}

它没有成功,但我在网上得到了另一个解决方案,就像这样:

int firstDuplicate(int[] a) {
  Set<Integer> set = new HashSet<>();
  Map<Integer, Integer> hm = new HashMap<Integer,Integer>();
  Map.Entry<Integer, Integer> min = null;
  for(int i=0;i<a.length;i++){
        if(set.add(a[i])==false && !hm.containsKey(a[i]))
              hm.put(a[i],i);
  }
  for(Map.Entry<Integer,Integer> entry : hm.entrySet()){
        if(min == null || entry.getValue() < min.getValue()){
              min = entry;
        }
  }
  return min == null ? new Integer(-1) : min.getKey();

}

任何人都可以在这里向我解释Hashset的使用,因为它不允许重复,所以如果条件将是可行的。

7 个答案:

答案 0 :(得分:4)

您第一次尝试失败的原因是您将数组元素添加为Map的键,而不检查它们是否已存在,这意味着您无法知道当时是否存在任何重复项你完成填充Map

您找到的替代代码会有所不同。它使用Set来确定当前数组元素是否已经出现在数组的前面,如果是这种情况,它只会将其作为Map的关键字添加到Map中。还没有。这意味着{2, 1, 3, 5, 3, 2}将只包含在数组中出现多次的元素,并且与每个元素关联的索引是第一个副本的出现。即对于数组Map{2=5, 3=4}将包含Map。然后它将返回具有最小值的键(与第一个副本的索引相对应)。

但是,Set是不必要的,因为您只需找到一个副本,而不是所有副本。使用int firstDuplicate(int[] a) { Set<Integer> set = new HashSet<>(); for(int i=0;i<a.length;i++){ if(!set.add(a[i])) { return a[i]; } } return -1; // no duplicates found } 找到第一个副本并将其返回:

set.add()

如果false已包含您要添加的元素,则Set会依赖false返回curl -X POST \ http://docker_host:8080/api/portal/v1/login \ -H 'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \ -d '{ "customerId": "0", "username": "domdorn", "password": "mypass" }' 。一旦它第一次返回curl -X POST \ http://localhost:8080/api/portal/v1/login \ -H 'Cache-Control: no-cache' \ -H 'Content-Type: application/json' \ -d '{ "customerId": "0", "username": "domdorn", "password": "mypass" }' ,您就找到了第一个副本。

答案 1 :(得分:0)

您可以将java 8与lambda和stream一起使用。

以下是一行中的代码:

Set<Integer> allItems = new HashSet<>();
Arrays.stream(a).filter(i -> !allItems.add(i)).findFirst().orElse(-1)

它会返回您期望的内容

答案 2 :(得分:0)

有两种方法可以解决此问题,一种是使用时间复杂度为o(n)的HashSet,另一种是使用嵌套循环o(n2)

for(int i = 0; i < a.length; i++){
    for(int j = i +1; j < a.length; j++){
           if(a[i] == a[j]){
                   System.out.println(a[i]);
                   return;
           }
     }
 }

或者您可以提高时间复杂度O(n)

int index -1;
Set<Integer> hashSet = new HashSet<Integer>();
for(int i = a.length-1; i >= 0; i--){
     if(hashSet.contains(a[i])){
           index = i;
     }else{
           hashSet.add(a[i]);
     }
}
 System.out.println(a[index]);

答案 3 :(得分:0)

我强烈建议您尝试此操作以获得正确的结果

您可以使其效率更高,时间复杂度O(n)

int firstDuplicate(int[] a){
int n = a.length;
for(int i=0; i<n; i++)
{
   if(a[Math.abs(a[i])-1]<0) return Math.abs(a[i]);
   else a[Math.abs(a[i])-1] = - a[Math.abs(a[i])-1];
}
return -1;
}

答案 4 :(得分:0)

int firstDuplicate(int[] a)
    {
        int DupIndex = 0;
        int DupValue = 0;
        for (int i = 0; i < a.Length; i++)
        {
            for (int j = i + 1; j < a.Length; j++)
            {
                if (a[i] == a[j])
               {
                    if (j < DupIndex)
                    {
                        DupIndex = j;
                        DupValue = a[i];
                    }
                    else if (DupIndex == 0)
                    {
                        DupIndex = j;
                        DupValue = a[i];
                    }
                }
            };
        };
        return (DupValue == 0) ? -1 : DupValue;
    }

答案 5 :(得分:0)

public static void main(String[] args){
    int array[]={2, 1, 3, 5, 3, 2};
    int tempArray[]=new int[array.length];
    int index=0;
    while(index< array.length){
        if(++(tempArray[array[index]])==2) 
            break;
        index++;
    }
    if(index> array.length){
        System.out.println("No Duplicate");
    }else {
        System.out.println("First Duplicate " + array[index]);
    }
}

使用计数排序,甜美而简单:)

答案 6 :(得分:0)

int firstDuplicate(int[] a){
int n = a.length;
for(int i=0; i<n; i++)
   {
    if(a[Math.abs(a[i])-1]<0) return Math.abs(a[i]);
    else a[Math.abs(a[i])-1] = - a[Math.abs(a[i])-1];
   }
return -1;
}

我将解释为什么以及如何工作。 重要的是此约束:1 ≤ a[i] ≤ a.length 存在,这意味着在这样的数组中:a = [2,8,2] 这个算法将不起作用,因为 8 是 <在这种情况下,强>大于比a.length3

您还会找到解释 here

哈希图

此解决方案遵循哈希图的思想。另一种结构,您计算 hash[arr[i]-1]++ 数组中任何给定索引 i 的出现次数。示例:

如果您有 arr[2,1,3,5,3,2] 哈希图将以 6 个零数组开始:hashmap[0,0,0,0,0,0] 因为这是 arr 的大小。随着算法的进展,它将在位置 +1 处求和 arr[i]-1。它使用该值作为总和的索引。最后你会得到:arr[1,2,2,0,1,0]

这在时间复杂度上有 O(n),因为它运行完整的 arr,并且 O(n) 及时,因为它至少运行了 1 次数组。

没有Hashmap

上述算法的思想是不需要hashmap的额外结构,而是可以使用相同的数组来计算频率。这可能会导致问题。让 i-th 元素为 a 或 (arr[i]=a) 然后计数应该存储在 arr[arr[i]-1] 或 (arr[a-1]),但是当频率将被存储时元素将丢失。

示例迭代:

  1. a[2,1,3,5,3,2] -> a[2,1,3,5,3,2]
  2. a[2,1,3,5,3,2] -> a[1,1,3,5,3,2]
  3. a[1,1,3,5,3,2] -> a[1,1,1,5,3,2]
  4. a[1,1,1,5,3,2] -> a[1,1,1,5,1,2] 如您所见,我们在阅读时失去了 3 的价值5 因为它将频率存储在 arr[arr[4]-1] 或 (arr[5-1]) 中。

解决缺失问题

为了解决这个问题,我们首先将第 i 个元素替换为 arr[arr[i]-1] 或 (arr[a-1]) 然后将 -1 放在数组 arr[arr[i]-1] 或 ({{1} })。 算法:

  1. 从头到尾遍历数组。
  2. 对于每个元素检查元素是否小于或等于零。如果负数或零跳过元素,因为它是频率。
  3. 如果元素 (arr[a-1]) 为正,则检查 a = arr[i] – 1 是否为正。如果为正,则表示它是数组中第一次出现 arr[a] 并将 a 替换为 arr[i],并分配 arr[a]。如果 arr[a] = -1 为负,则它不是第一次出现,然后将 arr[a] 更新为 arr[a],并将 arr[a]-- 更新为 arr[i]。您使用辅助值来保存将在下一次迭代中使用的 arr[a]。
  4. 再次遍历数组并打印 arr[i] = 0 作为值和 i+1 作为频率。

示例迭代:

  1. arr[i] -> a[2,1,3,5,3,2] -> a[1,1,3,5,3,2]
  2. a[1,-1,3,5,3,2] -> a[1,-1,3,5,3,2] -> a[1,-1,3,5,3,2]
  3. a[1,-1,-1,5,3,2] -> a[1,-1,-1,5,3,2]
  4. a[1,-1,-1,0,3,2] -> a[1,-1,-1,0,3,2] -> a[1,-1,-1,0,-1,2]
  5. a[1,-1,-2,0,-1,2] -> a[1,-1,-2,0,-1,2]
  6. a[1,-1,-2,0,-1,0] -> a[1,-1,-2,0,-1,0]

firstDuplicate

了解这一点后,我们现在可以了解 a[1,-2,-2,0,-1,0] 的工作原理。这个想法不是计算频率,而只是打印频率已经为负的 firstDuplicate。当我们得到负频率时,我们返回。 所以运行我们得到的算法:

  1. 对于 indexif(a[2-1]<0),此比较介于 if(1<0) 或 (arr[arr[0]-1]) 和 arr[1] 之间,因此我们不会返回。 0 -> a[2,1,3,5,3,2]
  2. 对于 a[2,-1,3,5,3,2]if(a[1-1]<0),我们不会返回 if(2<0) -> a[2,-1,3,5,3,2]
  3. 使用 a[-1,-1,3,5,3,2]if(a[3-1]<0) 我们不会返回。 if(3<0) -> a[-1,-1,3,5,3,2]
  4. 使用 a[-2,-1,-3,5,3,2]if(a[5-1]<0) 我们不会返回。 if(3<0) -> a[-2,-1,-3,5,3,2]
  5. 我们返回 a[-2,-1,-3,5,-3,2]if(a[3-1]<0)

所有这些都基于 if(-3<0) 是索引的想法。