Problem: 217. 存在重复元素
思路
要查找是否有重复的元素,有四种方法:
-
暴力法,通过一一对比,查找是否有重复元素。
-
排序法,如果元素是有序的,只需要一轮循环,将后一个元素与前一个元素对比即可。
-
哈希表,遍历列表,在哈希表里面查找是否有当前元素,如果有,说明重复,反之,没有重复元素。
-
使用 Set 的长度,利用 Set 中的元素是唯一的特点,将 Set 的元素与数组中的长度比较,如果长度一样,说明没有重复元素,如果数组的元素比 Set 中的元素多,说明有重复的元素。
方法一: 暴力法
步骤
- 使用两层嵌套循环遍历数组中的所有元素。
- 对于每个元素,检查它是否与数组中的其他元素重复。
- 如果找到重复元素,则返回
true。 - 如果遍历完整个数组都没有找到重复元素,则返回
false。
流程图
代码实现
/**
* @param {number[]} nums
* @return {boolean}
*/
var containsDuplicate = function(nums) {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] === nums[j]) {
return true;
}
}
}
return false;
};
function containsDuplicate(nums: number[]): boolean {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] === nums[j]) {
return true;
}
}
}
return false;
}
class Solution {
public boolean containsDuplicate(int[] nums) {
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] == nums[j]) {
return true;
}
}
}
return false;
}
}
bool containsDuplicate(int* nums, int numsSize) {
for(int i = 0; i < numsSize; i++) {
for(int j = i + 1; j < numsSize; j++) {
if (nums[i] == nums[j]) {
return true;
}
}
}
return false;
}
复杂度
- 时间复杂度:O(n^2),其中 n 是数组的长度。使用两层嵌套循环遍历数组中的所有元素。
- 空间复杂度:O(1),因为没有使用额外的数据结构。
方法二:排序法
步骤
- 对数组进行排序,可以使用快速排序或其他排序算法。
- 遍历排序后的数组,检查相邻元素是否相等。
- 如果存在相等的相邻元素,返回
true,表示存在重复元素。 - 如果所有相邻元素都不相等,返回
false,表示没有重复元素。
流程图
代码实现
function containsDuplicate(nums) {
nums.sort();
for (let i = 1; i < nums.length; i++) {
if (nums[i] === nums[i - 1]) {
return true;
}
}
return false;
}
function containsDuplicate(nums: number[]): boolean {
nums.sort();
for (let i = 1; i < nums.length; i++) {
if (nums[i] === nums[i - 1]) {
return true;
}
}
return false;
}
public class Solution {
public boolean containsDuplicate(int[] nums) {
Arrays.sort(nums);
for (int i = 1; i < nums.length; i++) {
if (nums[i] == nums[i - 1]) {
return true;
}
}
return false;
}
}
int cmp(const void* _a, const void* _b) {
int a = *(int*)_a, b = *(int*)_b; // 将 void 指针转换为 int 指针并引用
return a - b; // 返回两个整数的差值,用于排序
}
bool containsDuplicate(int* nums, int numsSize) {
qsort(nums, numsSize, sizeof(int), cmp); // qsort 是 C 语言标准库中用于排序数组的函数。它实现了快速排序算法,能够对任意类型的数组进行排序。
for(int i = 0; i < numsSize - 1; i++) {
if (nums[i] == nums[i + 1]) {
return true;
}
}
return false;
}
复杂度分析
- 时间复杂度:
O(NlogN),使用了排序,N为数组的长度。 - 空间复杂度:
O(logN)
方法三:哈希表
步骤
- 创建一个空的哈希表
visited。 - 遍历数组中的每个元素:
- 如果当前元素已经存在于
visited哈希表中,返回true,表示存在重复元素。 - 如果当前元素不存在于
visited哈希表中,则将当前元素添加到visited哈希表中。
- 遍历完数组后,返回
false,表示没有重复元素。
流程图
代码实现
function containsDuplicate(nums) {
const visited = new Set();
for (let num of nums) {
if (visited.has(num)) {
return true;
}
visited.add(num);
}
return false;
}
function containsDuplicate(nums: number[]): boolean {
const visited: Set<number> = new Set();
for (let num of nums) {
if (visited.has(num)) {
return true;
}
visited.add(num);
}
return false;
}
public class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> visited = new HashSet<>();
for (int num : nums) {
if (!visited.add(num)) {
return true;
}
}
return false;
}
}
// `visited.add()` 方法用于将元素添加到集合中,它会返回一个 boolean 值来表示添加元素是否成功:
// 如果元素已经存在于集合中,添加失败,返回 `false`。
// 如果元素不存在于集合中,添加成功,返回 `true`。
struct hashTable {
int key; // 存储键值
UT_hash_handle hh; // uthash 提供的句柄,用于哈希表管理
};
bool containsDuplicate(int* nums, int numsSize) {
struct hashTable* set = NULL; // 初始化哈希表
for (int i = 0; i < numsSize; i++) {
struct hashTable* tmp;
HASH_FIND_INT(set, nums + i, tmp); // 查找当前数字是否存在于哈希表中
if (tmp == NULL) {
tmp = malloc(sizeof(struct hashTable));
tmp->key = nums[i];
HASH_ADD_INT(set, key, tmp); // 将新元素添加到哈希表中
} else {
return true;
}
}
return false;
}
复杂度分析
- 时间复杂度:
O(N),N为数组的长度。 - 空间复杂度:
O(N)
方法四:Set 长度
步骤
- 创建一个新的
Set对象,Set是一种数据结构,它只存储唯一的值。 - 将
nums数组传递给Set,这会自动去除数组中的重复元素。 - 检查大小
Set的size属性返回集合中元素的数量。- 比较 Set 的大小与原数组的长度。
- 如果集合的大小小于数组的长度,说明数组中存在重复元素,返回
true;否则返回false。
流程图
复杂度分析
- 时间复杂度:
O(N),N为数组的长度。 - 空间复杂度:
O(N)
代码实现
var containsDuplicate = function(nums) {
return new Set(nums).size < nums.length;
};
class Solution {
public boolean containsDuplicate(int[] nums) {
return Arrays.stream(nums).distinct().count() < nums.length;
}
}
敲黑板
使用暴力法,本题会超出时间限制。复杂度方面,排序法时间复杂度是 O(NlogN),空间复杂度是 O(1),而使用哈希表的方法,时间复杂度是 O(1),空间复杂度是 O(N),因此,两者比较,排序法的空间复杂度更优,而哈希表的时间复杂度更优。