面试常考算法题 (二)-- 荷兰国旗问题

本贴最后更新于 2162 天前,其中的信息可能已经东海扬尘

面试常考算法题(二)--荷兰国旗问题

荷兰国旗问题是面试中常考的一个题目,涉及到的思想并不是很复杂.

荷兰国旗问题

题目

给定一个数组 arr,和一个数 num,请把小于 num 的数放在数组的左边,等于 num 的数放在数组的中间,大于 num 的数放在数组的右边。
要求额外空间复杂度 O(1),时间复杂度 O(N)

问题解析

最差解法

这个问题如果不考虑时间复杂度和空间复杂度的话,最简单的解法自然是使用辅助数组,对当前数组数据进行分类以后复制回原数组,代码如下:

   
   public static int[] terriblePartition(int[] arr, int num) {
        if(arr == null || arr.length < 2){
            return arr;
        }
        int[] temp = new int[arr.length];
        int m = -1;
        int n = arr.length ;
        //设置两个指针,分别指向temp数组的最前面和最后面,将小于num的数据放在前部分,大于num的数据放在后部分
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] < num) {
                temp[++m] = arr[i];
            } else if (arr[i] > num){
                temp[--n] = arr[i];
            }
        }
        //等于num的数组数据放在中间
        for (int i = m + 1; i < n; i++) {
            temp[i] = num;
        }
        //复制temp数组数据到arr数组
        copyArr(arr, temp);
		  //返回等于num数据的位置
        return new int[]{m + 1, n - 1};
    }

    private static void copyArr(int[] arr, int[] temp) {
        for (int i = 0; i < temp.length; i++) {
            arr[i] = temp[i];
        }
    }

这个答案除非题目不要求并且时间不足够思考更优秀的算法,不然不建议使用此方法,这种解法一般仅用作 比较器.

优秀一点的解法

那么如何在上述方法上进行优化呢,其实本质所使用的思想和上述代码思想一致.知道读者未必对上面的代码感兴趣,这里我来通过一个实际数组[4, 5, 2, 8, 1, 9, 6, 11]进行图解一下:
imagepng

imagepng

imagepng

imagepng

imagepng

代码

  public static int[] partition(int[] arr, int num) {
        if(arr == null || arr.length < 2){
            return arr;
        }
        int less = -1;
        int more = arr.length;
        int i = 0;
        while (i < more) {
            if (arr[i] < num) {
                swap(arr, ++less, i++);
            } else if (arr[i] > num) {
                swap(arr, --more, i);
            }else {
                i++;
            }
        }
       //返回等于num数据的位置
        return new int[] { less + 1, more - 1 };
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

后记

这篇文章到这里可以说已经结束了,这个问题中的思想在 快速排序 中可以得到应用,可以用荷兰国旗问题来改进快速排序
使其时间复杂度变为 O(N*logN),额外空间复杂度 O(logN),这个问题将在下一篇文章快速排序中讲.必须要注意的一点是,荷兰国旗问题的解法其实是 不稳定的,会 改变原数组本可以不改变顺序的数据的相对顺序.比如[0 9 7 4 4 ]数组最后得到的结果是[0 4 4 7 9 ],数组中的两个 4 实际上交换了位置.

百度百科给出稳定算法的定义如下:

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且 r[i]在 r[j]之前,而在排序后的序列中,r[i]仍在 r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖
  • 面试

    面试造航母,上班拧螺丝。多面试,少加班。

    325 引用 • 1395 回帖
  • 算法
    428 引用 • 254 回帖 • 24 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...