关于使用和了解HashSet | 豆包MarsCode AI刷题

64 阅读3分钟

题目如下:## 游戏排名第三大的分数

问题描述

小M想要通过查看往届游戏比赛的排名来确定自己比赛的目标分数。他希望找到往届比赛中排名第三的分数,作为自己的目标。具体规则如下:

  1. 如果分数中有三个或以上不同的分数,返回其中第三大的分数。
  2. 如果不同的分数只有两个或更少,那么小M将选择最大的分数作为他的目标。

请你帮小M根据给定的分数数组计算目标分数。

import java.util.Set;
import java.util.Arrays;
import java.util.Collections;
public class Main {
    public static int solution(int n, int[] nums) {
        Set<Integer> Scores = new HashSet<>();
        for (int num : nums) {
            Scores.add(num);
        }
        Integer[] scoresArray = Scores.toArray(new Integer[0]);
        Arrays.sort(scoresArray, Collections.reverseOrder());
        if (scoresArray.length < 3) {
            return scoresArray[0];
        } else {
            return scoresArray[2];
        }
    
    }

    public static void main(String[] args) {
        System.out.println(solution(3, new int[] { 3, 2, 1 }) == 1);
        System.out.println(solution(2, new int[] { 1, 2 }) == 2);
        System.out.println(solution(4, new int[] { 2, 2, 3, 1 }) == 1);
    }
}

代码和题目很简单,主要是利用HashSet的去重和基于哈希的快速查找,所以这次的主题主要介绍HashSet.

image.png

由源码可知,HashSet实际是构造了HashMap。 而HashMap是基于哈希表实现,底层由数组+链表+红黑树实现 其特点包括:

1. 基于哈希表

HashMap 在底层使用哈希表来存储数据。哈希表是一种数据结构,它通过哈希函数将键(key)映射到表中的一个位置,以便快速访问。

2. 哈希函数

当你将键值对放入 HashMap 时,它使用键的 hashCode() 方法来计算哈希码,然后通过哈希函数将哈希码转换为数组索引,这个索引就是键值对在哈希表中的存储位置。

3. 处理哈希冲突

由于不同的键可能产生相同的哈希码,这种情况称为哈希冲突。在 HashMap 中,冲突是通过链地址法解决的,即在每个数组位置上维护一个链表。当发生冲突时,新的元素会被添加到链表的头部。

4. 动态扩容

HashMap 会根据需要动态地调整其大小。当HashMap中的元素数量超过负载因子(load factor)与当前容量的乘积时,HashMap会进行扩容,通常是将容量增加一倍,并重新计算所有元素的哈希值以分配到新的位置上。

5. 负载因子

负载因子是一个衡量HashMap中有多“满”的指标。它定义为HashMap中元素数量与桶(bucket)数量的比值。默认的负载因子是0.75(可以自定义),这意味着当HashMap中的元素数量达到75%的桶数量时,HashMap会进行扩容。

6. 线程不安全

HashMap 是非线程安全的。在多线程环境中,如果没有外部同步,多个线程可能会同时修改HashMap,导致数据不一致。如果需要线程安全,可以使用 ConcurrentHashMap 或在使用 HashMap 时进行外部同步。

7. 性能

HashMap 提供了快速的查找、插入和删除操作,平均时间复杂度为 O(1)。但是,在极端情况下(如哈希冲突非常多时),这些操作的时间复杂度可能退化到 O(n)。

go

而在go中,是没有HashSet的,我们可以用自带的map来实现


import (
	"fmt"
)

func main() {
	hashSet := make(map[string]struct{})

	// 添加元素
	hashSet["apple"] = struct{}{}
	hashSet["banana"] = struct{}{}
	hashSet["cherry"] = struct{}{}

	// 删除元素
	delete(hashSet, "apple")

	// 遍历HashSet
	for key := range hashSet {
		fmt.Println(key)
	}
}