算法系列--去除排序数组中的重复元素

来源:互联网 发布:git ssh 非22端口 编辑:程序博客网 时间:2024/06/11 04:12

继续算法系列。今天来说说数组去重的问题。照例,先从最简单的问题说起。

问题描述

给定一个排好序的数组,去除数组中重复的元素使之仅出现一次,返回新的数组长度。要求不需要额外的空间开销。例如,给定数组 A={1,1,2},你写的函数应该返回2,去重之后A={1,2}。

思路分析

排好序的数组中的重复元素一定具备连续排列的特征,这点毋庸置疑。但是根据问题描述,至少有三个问题需要思考:

第一,如何判断相邻的数组元素之间是否相等。很显然,我们至少需要两个游标pointer,i来完成判断。i用来遍历数组当中的元素,而pointer游标应该从第二个位置开始,负责标记A[i]的之后的一个元素,比较A[i]和A[pointer]是否相等,如果不相等,pointer应自增,i自增,如果不等,pointer应保持不变,i自增,继续比较下一个位置。

第二,如何不使用额外的空间来达到去重目的。不使用额外的空间,意味着我们只能使用原来的数组,通过赋值的方式来改变数组中的原有值。根据第一步的分析,我们可以在A[i],A[pointer]不相等的情况下,将A[i]的值赋给A[pointer-1],其实相当于重复元素被挤消失了(这句描述看起来有点诡异,同学们自己在纸上画画就可以知道是啥意思了)。

第三,如何返回去重后的数组长度。在上述分析的基础上,我们可以发现,pointer游标指示的元素都将会是不重复的元素,在循环结束之时,pointer游标应该处于最末一个不重复元素的位置之后。所以pointer就应该是我们想要的结果。

实现代码

思路分析有了,于是我们可以很快写出代码

public class Main {public static void main(String[] args) {int[] array = { 1, 1, 2 };int result = uniqueArray(array);System.out.println(result);}/* * 去除排序数组中的重复元素 */public static int uniqueArray1(int[] array) {        if (array.length <= 1)            return array.length;        int pointer = 1;        for (int i = 0; i < array.length; i++) {            if (array[i] != array[pointer - 1]) {                array[pointer++] = array[i];            }        }        return pointer;    }}
输出结果:2,符合预期。

以上算法时间复杂度O(n),空间复杂度O(1),符合要求。

问题变形

如果给定次数要求,允许排序数组中的元素出现两次呢,或者既定的n次呢?算法应该如何写?

先考虑允许排序数组中元素出现两次的情况,例如,给定数组A={1,1,1,2,2,3},你写的函数应该返回长度5,去重后A应该是{1,1,2,2,3}.

思路分析

从对上面简单去重问题的分析,可以知道,必定需要一个游标i来遍历数组元素,而游标pointer此时指向的不应该是A[i]的后一个元素,而应该是A[i]之后的第二个元素A[i+2],其余步骤其实和简单去重问题保持一致。扩展开来,假如说指定排序数组中重复元素最多出现count次,我们这个时候应该很容易推而广之,pointer此时应该指向A[i+count],其余步骤也是完全一致的。

由此,我们便将排序数组中的元素去重问题推向一般化。泛化的排序数组去重问题,可以这样描述

给定排序数组A,要求不使用额外的辅助空间,使A中的元素最多出现count(1,2,3,......)次,写出你的算法。

根据以上描述,我们可以写出以下代码:

/* * 去除排序数组中的重复元素,只允许最多出现两次 */public static int uniqueArray2(int[] array) {if (array.length <= 2)return array.length;int pointer = 2;for (int i = 0; i < array.length; i++) {if (array[i] != array[pointer - 2]) {array[pointer++] = array[i];}}return pointer;}/* * 去除排序中重复元素,允许出现指定次数count次 */public static int uniqueArray3(int[] array, int count) {if (array.length <= count)return array.length;int pointer = count;for (int i = 0; i < array.length; i++) {if (array[i] != array[pointer - count]) {array[pointer++] = array[i];}}return pointer;}

上述算法时间复杂度都是O(n),空间复杂度都是O(1),暂时也没有更高效的算法,测试结果不再给出,同学们可以自行测试。

特别说明:作者也是小学生哈,如果错误和疏漏之处,欢迎大家拍砖和批评指正。



0 0