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

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

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

荷兰国旗问题

题目

给定一个数组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]进行图解一下:

代码

  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]之前,则称这种排序算法是稳定的;否则称为不稳定的。

你可能感兴趣的:(Javase,算法)