剑指offer(14题):调整数组顺序使数组中的奇数位于偶数前面 java的5种解法

   题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分。

思路1:暴力解法
从头到尾扫描一遍数组,每遇见一个偶数时,就拿出这个数字,并把位于这个数字之后的所有数字往前挪动一位,然后把当前这个偶数放到最后。
这样每次遇到一个偶数就要挪动O(n)个数字,因此总的时间复杂度是O(n2)
但是这种方法不仅暴力而且还需要复杂的挪动工作。

public void reOrderArray(int[] array) {
        if(array == null) {
            return;
        }
        for(int i=0;i<array.length;i++) {
            int j = i;
            if(array[i]%2 == 0) {
                int temp = array[i];
                while(j<array.length-1) {
                    array[j] =array[j+1];
                    j++;
                }
                array[j] = temp;
            }
        }
    }

思路2:冒泡解法
冒泡排序,每次循环前偶后奇就交换。同时我们设立一个标识,来标识数组是否已经符合要求。当再次循环时,发现没有要交换的数据,说明数组已经符合要求。
由于冒泡法比较相邻两个元素,因此奇数或者偶数的相对顺序不变,是稳定的。

public void reOrderArray2(int[] array) {
        if(array == null) {
            return;
        }
        boolean flag = true;
        for(int i=0;i<array.length-1 && flag;i++) {
            flag = false;
            for(int j=0;j<array.length-1-i;j++) {
                if(array[j]%2==0 && array[j+1]%2!=0) {
                    int temp = array[j+1];
                    array[j+1] = array[j];
                    array[j] = temp;
                    flag = true;   //当有数据交换时则 flag 设置为true
                }
            }
        }
    }

思路3:利用一个辅助的数组空间来实现
在原来的数组中遇到偶数就放进新数组中,遇到奇数就将奇数移动到原来数组奇数下标的后面(第一次移动奇数到数组的开头),当整个遍历结束后,最后我们将新的数组追加在原来数组奇数下标的后面即可。

public void reOrderArray3(int[] array) {
        if(array == null) {
            return;
        }
        int[] auxiliaryArray = new int[array.length];
        int auxiliaryIndex = -1;  //辅助数组的下标
        int index = 0;  //原数组的下标,用于控制奇数的位置(偶数插入的下标)
        for(int i=0;i<array.length;i++) {
            if(array[i]%2 == 0) {
                auxiliaryArray[++auxiliaryIndex] = array[i];
                continue;
            }
            array[index ++] = array[i];
        }
        for(int j=index;j<array.length;j++) {
            array[index ++] = auxiliaryArray[auxiliaryIndex--];
        }
    }

思路4:高效的解法,维护2个指针
由于题目中只要求记奇数在偶数之前,那么我们在扫描这个数组的时候,如果发现一个偶数出现在奇数之前就交换他们的位置,这样一趟后就满足要求了。
因此我们 维护两个索引或者指针,一个指向数组的第一个元素,并向后移动,一个指向数组的最后一个元素,并向前移动。
如果第一个指针指向的元素是偶数,而第二个指针指向的元素是奇数,说明偶数在奇数前面,那么就交换这两个数,直到两个指针相遇为止。
这种算法不能保证相同类型数据的相对位置不变,因此不稳定。

public void reOrderArray4(int[] array) {
        if (array == null || array.length == 0) {
            return;
        }

        int left = 0;
        int right = array.length - 1;
        while (left < right) {
            while (left < right && (array[left] &1) != 0) {
                left++;
            }
            while (left < right && (array[right] &1) == 0) {
                right--;
            }

            if (left < right) {
                int temp = array[left];
                array[left] = array[right];
                array[right] = temp;
            }
        }
    }

思路5:考虑可扩展性的解法(即解耦)。
这不仅是解决一个问题的办法,而是解决一系列同类型问题的通用办法。对扩展性的理解,能够给出一个模式,在这个模式下能够很方便地把已有的解决方案扩展到同类型的问题上。
比如(1)把数组中的数按照大小分成两部分,所有负数都在非负数的前面。
(2)把数组中的数分为两部分,能被3整除的数都在不能被3整除的数的前面。

public void reOrderArray5(int[] array) {
        if (array == null || array.length == 0) {
            return;
        }
        int left = 0;
        int right = array.length - 1;
        while (left < right) {
            while (left < right && !isEven(array[left])) {
                left++;
            }
            while (left < right && isEven(array[right])) {
                right--;
            }

            if (left < right) {
                int temp = array[left];
                array[left] = array[right];
                array[right] = temp;
            }
        }
    }
    //even是偶数的意思,odd是奇数的意思
    private boolean isEven(int n) {
        //是奇数的话n & 1为1,返回false
        //偶数的话n & 1为0,返回true
        return (n & 1) == 0;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容