php实现有序数组去重算法和无序数组去重算法

294 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

有序数组去重算法

有序数组去重相对来说更简单,因为本身就是有序的,假设从小到大有序,那么给定x元素,一定满足 left <= x <= right,也就是x元素的左边或者右边,要么小于/大于x,要么相等,如果相等,我们就可以认为x重复。同理,如果假设从大到小有序,那么给定x元素,一定满足 left >= x >= right,也就是x元素的左边或者右边,要么大于/小于x,要么相等。

算法实现

因为是有序数组,为了提高去重效率,取一个元素往后一直比对,也就是上面说的,如果相邻的相等表示是重复的,继续往后,直到不相等,也就是遇到一个不重复的为止,将这个不重复的元素移动到该元素的下一个,然后用这个不重复的元素为起始,重复上述操作。直到最后。

因为只循环一遍,有序数组去重算法的复杂度是O(n)。

代码如下,只进行一次循环,复杂度O(n)

完整代码在github上面,只需要clone下来执行composer install然后执行 php artisan test:sortDeduplicate 就可以看到结果了

    /**
     * 因为是有序数组,为了提高去重效率,取一个元素往后一直比对,如果相邻的相等表示是重复的
     * 继续往后,直到不相等,也就是遇到一个不重复的为止,将这个不重复的元素移动到该元素的下一个
     * 然后用这个不重复的元素为起始,重复上述操作。直到最后
     * 删除最后一个不重复元素后面所有的元素
     * 因为只循环一遍,复杂度O(n)
     *
     * @return mixed
     */
    public function handle()
    {
        $a = [3,4,4,4,5,6,6,8,10,10,34];
        dump($a);
        //分别代表第一个数据,和要比对的数据
        $i = 0;$j=0;
        $len = count($a);
        dump("长度:".$len);
        while ((++$j) < $len) { //循环全部数据
            //从$i往后寻找,如果相邻的相等表示是重复的,继续往后,直到不相等,也就是遇到一个不重复的为止,将这个不重复的元素移动到该元素的下一个
            if($a[$i] != $a[$j]) {
                $a[++$i] = $a[$j];
            }
        }
        //截取前面去重过的数据
        $a = array_slice($a, 0, ++$i);
        dd($a);
    }

无序数组去重算法

无序数组处理起来就很麻烦了,因为你不知道重复的那个元素在哪里,必须整个遍历完才能把所有重复的元素去掉,所以是两层循环,在第一层循环里面找到给定x元素,在第二层循环里面找到x的重复元素并删除。即完成去重。这么来看,去重之前先进行排序,可以有效提升去重的效率。

算法实现

无序数组去重算法的复杂度是O(n2)。

代码如下,首先进行外层循环,复杂度O(n),然后查找这个元素之前的元素中有没有重复的,复杂度O(n),如果有就删除,复杂度O(1),没有就下一个元素,复杂度O(1)。加起来复杂度O(n2)。

完整代码在github上面,只需要clone下来执行composer install然后执行 php artisan test:unsortDeduplicate 就可以看到结果了

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $a = [4,5,4,3,8,6,6,10,34,10,4];
        dump($a);
        $i = 1;
        $len = count($a);
        dump("长度:".$len);
        while ($i < $len) { //循环全部数据
            //在整个数组中寻找这个值,如果找到了就删除他,如果没找到就下一个
            $preIndex = $this->find($i, $a);
            if ($preIndex!==false) {unset($a[$preIndex]);}
            else $i++;
        }
        dd($a);
    }

    private function find($i, array $a) {
        $index = 0;
        //循环从0到这个下标
        while ($index < $i) {
            //不存在说明被删除了
            if (!array_key_exists($index, $a)) {$index++;continue;}
            //如果找到了返回下标
            if ($a[$i] == $a[$index]) return $index;
            else $index++;
        }
        return false;
    }