微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

增强Java中获取数组中元素最高出现次数的方法

如何解决增强Java中获取数组中元素最高出现次数的方法

我在面试时遇到了以下问题。

问题: 您需要找到数组中出现频率最高的元素。该数组由整数组成。例如,如果你有一个这样的整数序列:1,2,9,3,4,1,5,8,2,解将是字符串:

获胜者是第 3 名,其出现频率为 6

这个问题的答案在面试过程中得到了改进。

以下是源代码

import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;

public class RepeatedElement {

public static void main(String[] args) {
    int[] arr = {1,2};
    
    Arrays.sort(arr);
    
    int len = arr.length;
    
    int count = 1;
    
    Map<Integer,Integer> map = new TreeMap<>();
    
    int i=0;
    while(i < len) {
        for(int j=i+1;j<len;j++) {
            if(arr[i]==arr[j]) {
                count++;
                i++;
            }else {
                break;
            }
        }
        map.put(arr[i],count);
        count = 1;
        i++;
    }
    
        
    int max = 0;
    int key = 0;
    for(int k:map.keySet()) {
        int temp = map.get(k);
        
        if(temp>max) {
            max = temp;
            key = k;
        }
    }
    
    System.out.println("Winner is: "+key+" and it's occurrences: "+max);
}
}

我也在 stackoverflow 中搜索了其他类似的问题。我只是想了解这是否是解决此问题的好方法。我相信代码可以更好地解释我尝试过的方法。同时,我很想知道将提供更大输入的时间和空间复杂性。伙计们,如果它有一些缺陷,请提供您的想法来改进此代码。提前致谢。

解决方法

您可以使用 Map 中的计算函数将第一个循环简化为如下所示:

    for (int i=0; i < arr.length; i++) {
        map.compute(arr[i],(k,v) -> v == null ? 1 : v+1);
    }

或者,如果您对 3rd 方库开放,则可以使用 Bag 中的 Eclipse Collections 类型,并将整个方法替换为以下内容:

public static void main(String[] args) {
    Integer[] arr = {1,2,9,3,4,1,5,8,2};
    MutableBag<Integer> bag = Bags.mutable.of(arr);
    ObjectIntPair<Integer> top = bag.topOccurrences(1).getFirst();
    System.out.println("Winner is: "+top.getOne()+" and it's occurrences: "+ top.getTwo());
}

甚至还有一个 PrimitiveBag 类型来避免 int 的装箱:

public static void main(String[] args) {
    int[] arr = {1,2};
    MutableIntBag bag = IntBags.mutable.of(arr);
    IntIntPair top = bag.topOccurrences(1).getFirst();
    System.out.println("Winner is: "+top.getOne()+" and it's occurrences: "+ top.getTwo());
}
,

从代码中的这个语句 map.put(arr[i],count); 来看,您似乎没有认识到可以使用现有值更新地图中现有键的事实。这就是为什么您似乎通过遍历所有键来计算元素的原因。 您可以在再次看到密钥时使用 map.put(arr[i],map.get(arr[i]) + 1) 更新密钥的计数。

此外,您不需要再次遍历地图的 keySet 以获得最大频率,您可以在填充地图本身时获得它。

代码将是:

    public static void main(String args[]) {
      int[] arr = {1,2};
      Map<Integer,Integer> map = new HashMap<>();
      int max = 1;
      int maxKey = arr[0];
      for ( int k : arr ) {
          map.put(k,map.getOrDefault(k,0) + 1);
          if ( map.get(k) > max ) {
              max = map.get(k);
              maxKey = k;
          }
      }
      System.out.println("Winner is: "+ maxKey+" and it's occurrences: "+max);
   }
,

你正在做一个排序:不需要引入时间复杂度 >= O(NLogN)

也不需要使用TreeMap。使用 HashMap 来将 get 或 put 操作减少到常量而不是 log(N)。

您可以合并两个循环为一个。

以下解决方案的复杂性

  1. 以下代码的时间复杂度为 O(N)。
  2. 空间复杂度为 O(N)。

使用 map.compute (Java 8+) 增加现有频率计数。这样你就不需要

  1. 首先获取现有值,
  2. 检查它是否存在,如果它确实增加或如果不存在则将其设置为 1。

您也可以使用 map.merge (Java 8+) 操作。

mergecompute 的示例在下面的代码中都有说明。

import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;

public class MostFrequentElementInArray {

    public static void main(String[] args) {
    int[] arr = { 1,2 };

    int len = arr.length;


    int mostFreqKey = arr[0];

    Map<Integer,Integer> map = new HashMap<>();

    for (int elem : arr) {
        // you can use any of the 3:
        int newVal = map.compute(elem,(K,oldVal) -> oldVal == null ? 1 : oldVal + 1  );
        // int newVal = map.merge(elem,(oldVal,valWhichIs1) -> oldVal + valWhichIs1);
        // int newVal = map.merge(elem,Integer::sum);
        if (map.get(mostFreqKey) < newVal) {
            // this is the new frequently occurring element
            mostFreqKey = elem;
        }
        
        
    }
    
    
    
    System.out.println("Winner is: " + mostFreqKey + " and it's occurrences: " + map.get(mostFreqKey));
    }
}
,

使用哈希表记录每个整数的计数。空间和时间复杂度都是 O(N)。遍历数组中的每个元素并将其插入到哈希映射中,数组 [i] 作为键,如果不存在则值为 1。当您看到它已经存在时,只需增加该值。然后在此之后的另一个循环获得最大值键。

您的解决方案类似,但请注意,在使用 Map 对象时无需进行排序。当您使用 Map 时,无需从当前索引中查找相似元素。你的解决方案会让面试官觉得你没有完全理解地图​​的概念。还要注意排序会让你的方法变成 O(N logN)。从面试的角度来看,我确信这个问题是为了测试你对哈希表的理解。

这是我的方法:

public static void main(String[] args) {
    int[] arr = {1,2};
 
    Map<Integer,Integer> map = new HashMap<>();
 
    for (int i=0; i < arr.length; i++) {
        if(map.containsKey(arr[i])) {
            map.put(arr[i],map.get(arr[i]) + 1);
        } else {
            map.put(arr[i],1);
        }
    }
 
    int max = 0;
    int key = 0;
    int temp;
    for(int k: map.keySet()) {
        temp = map.get(k);
 
        if(temp > max) {
            max = temp;
            key = k;
        }
    }
 
    System.out.println("Winner is: "+key+" and it's occurrences: "+max);
}
,

以下代码是我能想到的最优化的方式。它不仅大大缩短了代码,而且还以相同的时间复杂度处理信息。复杂性并不重要,使用这种方法,我们只迭代一个数据结构一次。

int[] arr = {1,2};
Map<Integer,Integer> occurrenceMap = new HashMap<>();
int winnerNumber = -1;
int maxOccurrence = 0;
for (int i : arr) {
    if (occurrenceMap.merge(i,Integer::sum) > maxOccurrence) {
        winnerNumber = i; maxOccurrence = occurrenceMap.get(i);
    }
}
System.out.format("The winner is number " + winnerNumber
        + ",its frequency of occurrence is " + maxOccurrence + ".");
,

呈现的代码有点复杂,因为它对输入数组进行排序,然后使用嵌套循环计算排序映射中的频率,然后找到映射中的最大频率。

如果使用地图来计算频率,则预排序是多余的。去掉它就可以删除初始算法中最复杂的部分 O(N log N)

此外,在迭代输入数组时,应立即识别具有最大频率的值。

接下来,由于 Java 8 Map 具有诸如 Map::computeMap::merge 之类的方法来方便修改映射中的值,在这种情况下是增量。

话虽如此,代码可以重构为:

public static void main(String args[]) {
    int[] arr = {1,2};
    
    Map<Integer,Integer> freqMap = new HashMap<>();
    
    Integer mostFrequent = null;
    Integer highestFreq = null;
    
    for (int x : arr) {
        Integer currFreq = freqMap.compute(x,v) -> null == v ? 1 : v + 1);
        // Integer currFreq = freqMap.merge(x,Integer::sum); // merge example
        if (null == mostFrequent || currFreq > highestFreq) {
            mostFrequent = x;
            highestFreq = currFreq;
        }
    }
    System.out.printf("Winner is %d and its occurrences %d%n",mostFrequent,highestFreq);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。