删除数组中重复元素--哈希表方法和set方法

数组去重技巧
本文介绍两种有效的数组去重方法:一种是创新的相似因子法,通过个位数划分减少重复检查;另一种是利用C++标准库set集合的特性实现。这两种方法均提供了高效的解决方案。

忘了是哪个的面试题,说删除数组中重复元素,给了一组数, [90, 91, 1, 2, 90, 5, 91], 输出 [90, 91, 1, 2, 5],类似这种情况,我给出了两种解决方案。

其实最简单的应该是申请一个等大的数组,去循环遍历,我没有采用。我采用以下两种方法。

一:相似因子法(我自创的)

按照每个数的个位划分,个位一共有0~9十种情况,我将个位相同的放在同一个链地址中,只需申请一个每个成员为结构体,共有10个成员的数组。这在数据较大时查找前面相同元素能提高很大效率的。

代码如下:

#include <iostream>
#include <assert.h>
using namespace std;

const int N = 10;

typedef struct similar_factor{
	int val;
	struct similar_factor* next;
	similar_factor(int v) : val(v), next(NULL) {}
	similar_factor() {}
} similar_factor;

int fill_in(similar_factor* factor, const int value, int index)
{
	similar_factor* new_factor = new similar_factor(value);
	if(factor[index].next == NULL){
		new_factor->next = factor[index].next;
		factor[index].next = new_factor; 
	}
	else{
		similar_factor *tmp = &factor[index];
		
		while(tmp->next != NULL){
			if(tmp->next->val == new_factor->val)
				return -1;
			tmp = tmp->next;
		}
		tmp->next = new_factor;
	}
	return 0;
}

int main()
{
	int array[] = {90, 91, 1, 2, 90, 5, 91};

	similar_factor* factor = new similar_factor[10];
	assert(factor != NULL);
	
	for(int i=0; i<sizeof(array)/sizeof(int); ++i){
		int num = array[i] % 10;
		if(fill_in(factor, array[i], num) == 0)
			cout << array[i] << ' ';
		else
			continue;
	}
	delete []factor;

	return 0;
}

二:set集合方法

我们知道C++的set底层是一颗红黑树,之前有写过红黑树的代码,知道它的机制是插入元素如果碰见相同的元素,直接插入失败,返回false,所以我们可以利用这个机制来做这道题。

代码如下:

#include <iostream>
#include <set>
#include <algorithm>
using namespace std;

int main()
{
	int array[] = {90, 91, 1, 2, 90, 5, 91};

	set<int> sint;
	size_t len = sizeof(array) / sizeof(int);
	for(int i=0; i<len; ++i){
		if(sint.insert(array[i]).second)
			cout << array[i] << ' ';
	}

	return 0;
}

以上代码均经过测试,结果如下:


<think> 我们使用Python给数组去重有多种方法,下面介绍几种常见的方法: 1. 使用set:将列表转换为集合集合的特性是元素唯一,然后再转回列表。但这种方法会打乱原有顺序。 2. 使用字典:利用字典键的唯一性,可以保持顺序(Python3.7及以上字典保持插入顺序)。 3. 使用循环:遍历列表,将不重复的元素添加到新列表中,保持顺序。 4. 使用collections.OrderedDict:在较老版本中(Python3.7以下)可以使用OrderedDict来保持顺序。 5. 使用列表推导式:结合使用if not in,但这种方法效率较低,适合小列表。 下面我们分别给出代码示例: 方法1:使用set(不保持顺序) ```python def remove_duplicates_set(lst): return list(set(lst)) ``` 方法2:使用字典(保持顺序,Python3.7+) ```python def remove_duplicates_dict(lst): return list(dict.fromkeys(lst)) ``` 方法3:使用循环(保持顺序) ```python def remove_duplicates_loop(lst): unique_list = [] for item in lst: if item not in unique_list: unique_list.append(item) return unique_list ``` 方法4:使用OrderedDict(保持顺序,适用于Python3.7以下) ```python from collections import OrderedDict def remove_duplicates_ordered_dict(lst): return list(OrderedDict.fromkeys(lst)) ``` 方法5:使用列表推导式(保持顺序,但效率较低) ```python def remove_duplicates_list_comp(lst): unique_list = [] [unique_list.append(item) for item in lst if item not in unique_list] return unique_list ``` 注意:方法3方法5在效率上对于大列表来说可能较慢,因为每次都要检查元素是否在列表中(O(n^2))。对于大列表,推荐使用字典(方法2或方法4)来去重,因为字典的查找操作更快。 下面我们测试一下方法2(字典方法): ```python # 测试数据 arr = [3, 5, 2, 3, 8, 5, 6, 8, 2] print(remove_duplicates_dict(arr)) # 输出: [3, 5, 2, 8, 6] ``` 解释: - 在`remove_duplicates_dict`函数中,我们首先通过`dict.fromkeys(lst)`创建一个字典,字典的键是列表中的元素,由于字典的键是唯一的,所以重复的元素被去掉了。然后我们将其转换成列表。在Python3.7及以上版本中,字典会保持插入顺序,因此顺序得以保持。 如果是在较老的Python版本(如3.6及以下)并且需要保持顺序,我们可以使用方法4(OrderedDict)。 另外,如果列表中的元素是可变类型(如列表、字典等),则不能作为字典的键,这时我们需要根据具体情况处理(例如使用元组代替,或者使用其他方法)。但一般情况下,去重操作常用于不可变元素。 下面我们给出一个综合的解决方案,根据需求选择是否保持顺序Python版本: ```python # 综合方案:自动选择合适的方法,默认保持顺序 def remove_duplicates(lst, keep_order=True): if not keep_order: return list(set(lst)) else: # 对于Python3.7及以上版本,使用dict.fromkeys # 对于更早版本,我们可以使用OrderedDict try: # 尝试使用dict.fromkeys(在Python3.7+中保持顺序) return list(dict.fromkeys(lst)) except AttributeError: # 如果出现AttributeError(实际上不太可能出现,因为dict.fromkeys是内置的) # 或者为了兼容,我们可以使用OrderedDict from collections import OrderedDict return list(OrderedDict.fromkeys(lst)) ``` 但实际上,在Python3.7以上,字典保持顺序是语言特性,所以我们可以直接使用字典方法。如果确定环境是Python3.7+,我们可以简化。 最后,根据需求选择一种合适的方法即可。 §§相关问题§§: 1. 如果数组中的元素是字典类型,该如何去重? 2. 在去重时如何同时保持元素顺序原列表中的相对位置? 3. 使用numpy库如何对数组去重? 4. 对于大规模数据,哪种去重方法效率最高? </think> ### Python数组去重解决方案 在Python中给数组(列表)去重有多种方法,以下是几种常见且高效的解决方案: #### 方法1:使用set数据结构(不保持顺序) ```python def remove_duplicates_set(arr): return list(set(arr)) # 测试 original = [3, 1, 2, 3, 4, 2, 1, 5] result = remove_duplicates_set(original) print(result) # 输出可能是 [1, 2, 3, 4, 5](顺序不固定) ``` **解释**: - `set(arr)` 将列表转换为集合,自动移除重复元素 - `list()` 将集合转回列表 - ⚠️ **缺点**:不保留原始顺序,结果元素顺序随机 #### 方法2:使用字典保持顺序(Python 3.7+) ```python def remove_duplicates_ordered(arr): return list(dict.fromkeys(arr)) # 测试 original = [3, 1, 2, 3, 4, 2, 1, 5] result = remove_duplicates_ordered(original) print(result) # 输出 [3, 1, 2, 4, 5] ``` **解释**: - `dict.fromkeys(arr)` 创建字典(键自动去重) - Python 3.7+ 保证字典保持插入顺序 - `list()` 提取字典键作为有序列表 - ✅ **优点**:时间复杂度O(n),高效且保持顺序 #### 方法3:使用循环保持顺序 ```python def remove_duplicates_loop(arr): seen = set() unique = [] for item in arr: if item not in seen: seen.add(item) unique.append(item) return unique # 测试 original = [3, 1, 2, 3, 4, 2, 1, 5] result = remove_duplicates_loop(original) print(result) # 输出 [3, 1, 2, 4, 5] ``` **解释**: - 创建一个空集合`seen`跟踪已出现元素 - 遍历列表,只添加未出现过的元素到新列表 - ✅ **优点**:保持顺序,适用于所有Python版本 - ⚠️ **注意**:时间复杂度O(n),但小列表效率略低于字典方法 #### 方法4:使用列表推导式(保持顺序) ```python def remove_duplicates_comprehension(arr): seen = set() return [x for x in arr if not (x in seen or seen.add(x))] # 测试 original = [3, 1, 2, 3, 4, 2, 1, 5] result = remove_duplicates_comprehension(original) print(result) # 输出 [3, 1, 2, 4, 5] ``` **解释**: - 利用`seen.add()`的副作用(始终返回None)实现单行去重 - 等效于循环方法,但更简洁 - ✅ **优点**:代码简洁且保持顺序 #### 方法5:使用pandas库(适合大数据集) ```python import pandas as pd def remove_duplicates_pandas(arr): return pd.Series(arr).drop_duplicates().tolist() # 测试 original = [3, 1, 2, 3, 4, 2, 1, 5] result = remove_duplicates_pandas(original) print(result) # 输出 [3, 1, 2, 4, 5] ``` **解释**: - 将列表转为pandas Series对象 - `drop_duplicates()` 移除重复值(默认保留首次出现) - ✅ **优点**:特别适合处理大型数据集 ### 性能比较 | 方法 | 时间复杂度 | 保持顺序 | 特点 | |------|------------|----------|------| | set | O(n) | ❌ | 最快但无序 | | dict | O(n) | ✅ | Python 3.7+最佳选择 | | 循环 | O(n) | ✅ | 通用性强 | | 列表推导 | O(n) | ✅ | 简洁但可读性稍差 | | pandas | O(n) | ✅ | 适合大数据 | **推荐选择**: - Python 3.7+:首选`dict.fromkeys()` - 兼容旧版本:使用循环或列表推导式 - 处理大型数据 (>10000元素):考虑pandas
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值