LeetCode 1207简单哈希表
独一无二的出现次数 图解题解
这道题到底在问什么
给定整数数组 arr。先数出每个不同数字的出现次数;若这些次数互不相同返回 true,否则返回 false。
- 输入
- arr=[1,2,2,1,1,3]
- 输出
- true (次数 3、2、1 互不相同)
- 输入
- arr=[1,1,2,2]
- 输出
- false (1 和 2 都出现 2 次)
最优解:一步一步想明白
- 3记住「先数次数(值→次数),再把次数塞进集合查重,撞车就 false」,下面每帧都在套它。
- 4第一段:从左到右扫数组,每遇到一个数字,就在「值 → 出现次数」表里给它加一。
- 5扫到第 0 个,是数字 1(绿色是它之前出现过的位置)。给它的出现次数加一。
- 6数字 1 的出现次数更新到 1(高亮行)。继续往后扫。
- 7扫到第 1 个,是数字 1(绿色是它之前出现过的位置)。给它的出现次数加一。
- 8数字 1 的出现次数更新到 2(高亮行)。继续往后扫。
- 9扫到第 2 个,是数字 1(绿色是它之前出现过的位置)。给它的出现次数加一。
- 10数字 1 的出现次数更新到 3(高亮行)。继续往后扫。
- 11扫到第 3 个,是数字 2(绿色是它之前出现过的位置)。给它的出现次数加一。
- 12数字 2 的出现次数更新到 1(高亮行)。继续往后扫。
- 13扫到第 4 个,是数字 2(绿色是它之前出现过的位置)。给它的出现次数加一。
- 14数字 2 的出现次数更新到 2(高亮行)。继续往后扫。
- 15扫到第 5 个,是数字 3(绿色是它之前出现过的位置)。给它的出现次数加一。
- 16数字 3 的出现次数更新到 1(高亮行)。继续往后扫。
- 17扫到第 6 个,是数字 3(绿色是它之前出现过的位置)。给它的出现次数加一。
- 18数字 3 的出现次数更新到 2(高亮行)。继续往后扫。
- 19扫到第 7 个,是数字 4(绿色是它之前出现过的位置)。给它的出现次数加一。
- 20数字 4 的出现次数更新到 1(高亮行)。继续往后扫。
- 21扫到第 8 个,是数字 5(绿色是它之前出现过的位置)。给它的出现次数加一。
- 22数字 5 的出现次数更新到 1(高亮行)。继续往后扫。
- 23第一段扫完。各数字的出现次数是 1→3,2→2,3→2,4→1,5→1。接下来第二段:把这些次数(3、2、2、1、1)逐个塞进「已见次数」集合查重。
- 24轮到数字 1,出现次数 3。集合里还没有 3,塞进去(高亮行),目前没撞车,继续看下一个数字的次数。
- 25轮到数字 2,出现次数 2。集合里还没有 2,塞进去(高亮行),目前没撞车,继续看下一个数字的次数。
- 26轮到数字 3,它的出现次数是 2。可集合里已经有 2了(高亮行)——说明有两个数字出现次数相同(红色这些就是数字 3 的位置)。立即返回 false。
- 27因为数字 3 的出现次数 2 和前面某个数字撞了车(红色位置),出现次数并非两两不同,答案 false。
⚠️ 容易写错的地方
✗ 错:比较「值」是否互不相同
✓ 对:要比较「出现次数」是否互不相同
题目问的是次数的唯一性,不是值的唯一性
✗ 错:只看相邻次数有没有相等
✓ 对:任意两个次数都不能相等
不相邻的两个值也可能次数相同,必须全局查重(用集合)
✗ 错:空数组返回 false
✓ 对:空数组没有任何次数,视为 true
没有「两个相同次数」这回事,默认满足
完整代码(Python / C++ / Java)
Python
from typing import List
from collections import Counter
class Solution:
def uniqueOccurrences(self, arr: List[int]) -> bool:
vals = list(Counter(arr).values())
return len(vals) == len(set(vals))C++
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
class Solution {
public:
bool uniqueOccurrences(vector<int>& arr) {
unordered_map<int,int> count;
for (int x : arr) count[x]++;
unordered_set<int> seen;
for (auto &p : count) if (!seen.insert(p.second).second) return false;
return true;
}
};Java
import java.util.*;
class Solution {
public boolean uniqueOccurrences(int[] arr) {
Map<Integer,Integer> count = new HashMap<>();
for (int x : arr) count.put(x, count.getOrDefault(x, 0) + 1);
Set<Integer> seen = new HashSet<>();
for (int v : count.values()) if (!seen.add(v)) return false;
return true;
}
}复杂度
时间
O(n)
一遍计数 + 一遍查重
空间
O(k)
k 个不同值的计数表与次数集合
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 独一无二的出现次数 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
能不能不用第二个集合?+
可以把次数排序后看相邻是否相等(O(k log k)),或把次数也放进一个计数表看是否有 ≥2。但「插入集合判失败」是最直接的 O(k) 写法。本质都是「检测一组数里有没有重复」。
这题考的核心是什么?+
两层哈希思维:第一层把元素映射到出现次数,第二层把出现次数映射到「是否见过」。识别出「数频率 + 频率查重」这个两段式,很多计数类题都能套。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 独一无二的出现次数 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。