数组去掉重复项的几种方法

面试前端必须准备的一个问题:怎样去掉Javascript的Array的重复项。据我所知,百度、腾讯、盛大等都在面试里出过这个题目。 这个问题看起来简单,但是其实暗藏杀机。 考的不仅仅是实现这个功能,更能看出你对计算机程序执行的深入理解。

    我总共想出了三种算法来实现这个目的:

  1. Array.prototype.unique1 = function()
    {
    	var n = []; //一个新的临时数组
    	for(var i = 0; i < this.length; i++) //遍历当前数组
    	{
    		//如果当前数组的第i已经保存进了临时数组,那么跳过,
    		//否则把当前项push到临时数组里面
    		if (n.indexOf(this[i]) == -1) n.push(this[i]);
    	}
    	return n;
    }
  2. Array.prototype.unique2 = function()
    {
    	var n = {},r=[]; //n为hash表,r为临时数组
    	for(var i = 0; i < this.length; i++) //遍历当前数组
    	{
    		if (!n[this[i]]) //如果hash表中没有当前项
    		{
    			n[this[i]] = true; //存入hash表
    			r.push(this[i]); //把当前数组的当前项push到临时数组里面
    		}
    	}
    	return r;
    }
  3. Array.prototype.unique3 = function()
    {
    	var n = [this[0]]; //结果数组
    	for(var i = 1; i < this.length; i++) //从第二项开始遍历
    	{
    		//如果当前数组的第i项在当前数组中第一次出现的位置不是i,
    		//那么表示第i项是重复的,忽略掉。否则存入结果数组
    		if (this.indexOf(this[i]) == i) n.push(this[i]);
    	}
    	return n;
    }
    

    其中第1种和第3种方法都用到了数组的indexOf方法。此方法的目的是寻找存入参数在数组中第一次出现的位置。很显然,js引擎在实现这个方法的时候会遍历数组直到找到目标为止。所以此函数会浪费掉很多时间。 而第2中方法用的是hash表。把已经出现过的通过下标的形式存入一个object内。下标的引用要比用indexOf搜索数组快的多。

    为了判断这三种方法的效率如何,我做了一个测试程序,生成一个10000长度的随机数组成的数组,然后分别用几个方法来测试执行时间。 结果表明第二种方法远远快于其他两种方法。 但是内存占用方面应该第二种方法比较多,因为多了一个hash表。这就是所谓的空间换时间。  就是这个测试页面,你也可以去看看。

2010年10月7日更新:

根据hpl大牛的思路,我写了第四种方法:

Array.prototype.unique4 = function()
{
	this.sort();
	var re=[this[0]];
	for(var i = 1; i < this.length; i++)
	{
		if( this[i] !== re[re.length-1])
		{
			re.push(this[i]);
		}
	}
	return re;
}

    这个方法的思路是先把数组排序,然后比较相邻的两个值。 排序的时候用的JS原生的sort方法,JS引擎内部应该是用的快速排序吧。 最终测试的结果是此方法运行时间平均是第二种方法的三倍左右,不过比第一种和第三种方法快了不少。

以上内容为转载。

第一种和第三种方法就是利用indexOf函数,但是如上所说,必须要遍历数组,时间复杂度比较高。

第二种方法用hash表,hash表其实就是一个对象,然后判断array[i]的键值对中的值是否存在,因为对象一开始是空的,所以不存在,取反之后,值为真,注意:对象取值使用[]而不是大括号。

<think>好的,用户的问题是关于如何在Python中去除数组中的重复元素,具体提到了“pythonremove duplicatesfrom array”。首先,我需要根据用户提供的引用内容来找到相关的解决方案。用户提供的引用中有多个关于LeetCode第26题的讨论,这是一个处理有序数组去重的问题,要求原地修改并且空间复杂度为O(1)。这说明用户可能是在处理一个已排序的数组,需要高效的去重方法。首先,我要确认用户的需求。用户的问题可能有两种情况:数组是否已排序。引用中的题目是处理已排序数组的,所以可能需要先询问用户数组是否有序。不过,用户直接提到“remove duplicatesfrom array”,可能希望得到通用的方法,无论数组是否有序。但根据引用内容,最相关的解决方案是针对已排序数组的原地去重,所以需要明确这一点。接下来,我需要整理几种不同的方法。对于已排序数组,LeetCode26题的解法是使用双指针,这在引用4中有详细说明,代码是Java的,但可以转换为Python。对于未排序的数组,可能需要使用其他方法,比如转换为集合再转回列表,或者使用列表推导式来保持顺序。然后,我需要考虑用户可能的场景。如果用户处理的是有序数组,那么双指针方法是最优的,时间复杂度O(n),空间O(1)。如果数组无序,使用集合会影响顺序,这时候可能需要用其他方式,比如遍历并检查是否已存在,但这种方法的时间复杂度较高,O(n^2)。或者使用字典来保持顺序,这在Python3.7+中可行,因为字典保持插入顺序。 另外,用户提供的示例代码中有快速排序的例子,但当前问题与排序无关,除非用户需要先排序再去重。但根据引用内容,用户的问题更可能直接指向去重,尤其是已排序的情况。现在需要将这些方法结构化,分点说明,并给出代码示例。同时,注意用户可能希望得到多种方法,以便根据具体情况选择。例如,如果允许使用额外空间,可以用集合;如果要求原地修改且数组已排序,用双指针;如果无序且需要保持顺序,用字典或列表推导。 还需要注意Python中的实现细节,比如列表是可变对象,如何原地修改。对于LeetCode26题的要求,原地修改意味着必须在原数组上操作,不能创建新列表。因此在Python中,可能需要通过切片或修改列表内容来实现,并返回新长度,后面的元素可以不管。 最后,生成相关问题,帮助用户进一步学习,比如询问不同方法的时间复杂度,如何处理无序数组,或者相关LeetCode题目。</think>在Python中去除数组重复元素的方法取决于数组是否已排序,以及是否需要保持原有顺序。以下是几种常见场景的解决方案: ### 一、针对已排序数组的高效去重(原地修改) 适用于类似LeetCode 26题的有序数组场景,时间复杂度$O(n)$,空间复杂度$O(1)$: ```python def remove_duplicates(nums): if not nums: return 0 index = 1 for i in range(1, len(nums)): if nums[i] != nums[i-1]: nums[index] = nums[i] index += 1 return index # 返回新长度,原数组前index位无重复 ``` 调用示例: ```python arr = [1,1,2,2,3] new_length = remove_duplicates(arr) print(arr[:new_length]) # 输出[1,2,3] ``` 该方法通过双指针跳过重复元素,直接修改原数组[^2][^4]。 ### 二、针对未排序数组的去重方法 1. **保持顺序且允许额外空间**: ```python def remove_duplicates_unordered(arr): seen = set() return [x for x in arr if not (x in seen or seen.add(x))] ``` 2. **不保持顺序的最简方法**: ```python unique_list = list(set(arr)) ``` 3. **使用OrderedDict保持顺序(Python 3.7+)**: ```python from collections import OrderedDict unique_list = list(OrderedDict.fromkeys(arr)) ``` ### 三、性能对比 | 方法 | 时间复杂度 | 空间复杂度 | 保持顺序 | 适用场景 | |--------------------|------------|------------|----------|------------------| | 双指针法 | O(n) | O(1) | ✔️ | 已排序数组 | | 集合转换 | O(n) | O(n) | ❌ | 快速去重 | | 列表推导+集合 | O(n) | O(n) | ✔️ | 未排序数组 | | OrderedDict | O(n) | O(n) | ✔️ | Python 3.7+环境 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值