您的位置:首页 > 理论基础 > 数据结构算法

数据结构与算法分析笔记与总结(java实现)--数组3:调整数组顺序使奇数位于偶数前面

2017-02-15 16:40 656 查看
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

思路:这是一个数组的问题,在数据结构与算法的题目中,数组是很常见的题目,数组里面的元素通常都是数字,数组题目虽然用到了数组,但数组仅仅是一个载体,关键还是考察算法的理解和使用。123456à135246,本题与剑指offer中的题目不同,剑指offer中只要求奇数在偶数的前面,而不要求保持奇数、偶数的相对位置,因此只需要使用p1,p2两个指针分别从前面和后面开始遍历数组,当p1是偶数,p2是奇数时进行交换即可,直到p2<=p1,于是时间复杂度为O(n)。但是这里要求分类后奇数、偶数之间保持相对位置不变,于是需要采取不同的方法。

方法1:使用额外的空间复杂度,先遍历得到奇数和偶数的数目,然后建立数组,将奇数和偶数分别放入到两个数组中去,然后将两个奇数数组连接到偶数数组的前面即可。空间复杂度为O(n),时间复杂度为O(n)

public class Solution {

    public voidreOrderArray(int [] array) {

        int[] odd = newint[array.length];

        int[] even =new int[array.length];

        intevenCount=0;

        int oddCount=0;

        for(inti=0;i<array.length;i++){

           if(array[i]%2==0){

               even[evenCount] = array[i];

               evenCount++;

            }else{

               odd[oddCount] = array[i];

               oddCount++;

            }

        }

        for(inti=0;i<oddCount;i++){

            array[i] =odd[i];

        }

        for(inti=0;i<evenCount;i++){

           array[i+oddCount] = even[i];

        }

    }

}

方法2:以空间换时间,从后往前扫描,遇到奇数就保存到temp,遇到偶数就赋值到temp的末尾所在位置(就相当于移动了),直到到达数组开头,最后把temp反序写在开头。

public class Solution {

    public static voidreOrderArray(int[] array) {

 if (array == null ||array.length == 0)

 return;

 int tmp = 0;

 for (int i = 0, j = 0;i < array.length && j < array.length; i++) {

 if (array[i] % 2 != 0){

 tmp = array[i];

 for (int k = i; k >j; k--) {

 array[k] = array[k -1];

 }

 array[j] = tmp;

 j++;

 }

 }

 }

}

方法3:类似于插入排序,不用借助其他的数据结构,所以空间复杂度为O(1),时间复杂度为O(N^2)

虽然时间复杂度较大,但是原理很简单,而且没有额外的空间复杂度,可以作为面试时写代码时的解决方案。从第2个数开始,向下遍历,只关注奇数的数字,如果某个数是奇数,那么就希望将它调整到前面去,即跳过前面的偶数,移动和奇数放在一起,即本奇数array[j]要插入到前面合适的位置(所有偶数的前面),于是从本位置i开始向前遍历,j=i;j--,判断array[j]是否是偶数,如果是偶数就向后移动一位,直到前面的数是奇数时就是target=array[i]应该放的位置。如此对整个数组进行遍历,每遍历一个元素都可能移动n个元素,因此总的时间复杂度是O(n^2);

public void reOrderArray(int [] array) {

        for(inti=1;i<array.length;i++){

            int target= array[i];

            if(array[i]% 2 == 1){

                int j =i;

                while(j>= 1 && array[j-1] % 2 == 0){

                    array[j] = array[j-1];

                   j--;

                }

               array[j] = target;

            }

        }

    }   

方法4:使用归并排序法。要将数组分成两部分,可以使用快速排序的思想,但是快排是不稳定的,不能保证元素相对位置不变,堆排序也是不稳定的,稳定高效的排序算法只有归并排序,归并排序的时间复杂度也较低。时间复杂度O(nlogn),空间复杂度O(1)

public class Solution {

    public voidreOrderArray(int [] array) {

        //注释的部分使用快速排序的算法,很明显快速排序是不稳定的,这里需要用归并排序

        /*

        if(array.length== 0){

            return;

        }

        int high =array.length - 1;

        int low = 0;

        while(low <high){

            while(low< high && array[low] % 2 == 1){

                low ++;

            }

            while(low< high && array[high] % 2 == 0){

                high--;

            }

            int temp =array[low];

            array[low]= array[high];

            array[high]= temp;

        }*/

       

        //用用归并排序的思想,因为归并排序是稳定的

        int length =array.length;

        if(length ==0){

            return;

        }

        int[] des = newint[length];

       MergeMethod(array, des, 0,length - 1);

    }

    public voidMergeMethod(int[] array, int [] des, int start, int end){

        if(start <end){

            int mid =(start + end) / 2;

           MergeMethod(array, des, start, mid);

           MergeMethod(array, des, mid + 1, end);

           Merge(array, des, start, mid, end);

        }

    }

    public voidMerge(int[] array, int[] des, int start, int mid, int end){

        int i = start;

        int j = mid +1;

        int k = start;

        while(i <=mid && array[i] % 2 == 1){

            des[k++] =array[i++];

        }

        while(j <=end && array[j] % 2 == 1){

            des[k++] =array[j++];

        }

        while(i <=mid){

   
4000
         des[k++] =array[i++];

        }

        while(j <=end){

            des[k++] =array[j++];

        }

        for(int m =start; m <= end; m++){

            array[m] =des[m];

        }

    }

}

总结:这道题目的解决方案有很多种,根据要求进行选择,如果要求空间复杂度为O(1),那么使用归并排序可以使得时间复杂度最小O(nlogn),使用类似插入排序法可以使得时间复杂度达到O(n^2);如果要求时间复杂度为O(1),那么必须使用额外的空间复杂度,可以使用两个数组拼接,也可以使用一个半数组temp反转。这里先使用类似插入排序实现,归并排序在学习了排序后再回来做。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐