混乱无序的整数数组如何实现左侧全是奇数右侧全是偶数(数字不要求排序)

今天同事估计闲得蛋疼,突然开始回忆以前面试过程中被面到过的一些面试问题,有逻辑的,有算法的,然后来考我思路,标题对应的算法就是他碰到的面试算法题之一。

拿到题目的第一个感觉,就是Linq,被Linq带坏了,这种考算法的题目直接来Linq你都逗谁呢,整理一下思路,恩,题目只要求左侧奇数,右侧偶数,并未要求两侧的整数还要分别排序,那算法思路就这么定下来了,按索引从低向高循环,如果遇到偶数,则在循环内进行反向循环,即从高位向低位循环找奇数来实现两者位置交替,算法实现如下:

static void SetLeftSingleAndRightDoubleOne(int[] arr)
{
    int num = 0;
    var prevIndex = arr.Length - 1;
    for (var i = 0; i <= prevIndex; i++)
    {
        if (arr[i] % 2 == 0)
        {//偶数
            for (var j = prevIndex; j > i; j--)
            {
                num++;
                if (arr[j] % 2 != 0)
                {
                    //奇数
                    var b = arr[i];
                    prevIndex = j - 1;//当前位置已与偶数更换过位置,所以设置值的索引可以减一
                    arr[i] = arr[j];
                    arr[j] = b;
                    break;
                }
            }
        }
        else
        {
            num++;
            //奇数
            continue;
        }
    }
    //Console.WriteLine("ONE RUN NUMS:" + num);
}

咋看算法没问题,时间复杂度应当为f(n)=n-1,但实际一运行,却发现偶尔会出现循环次数高于数组长度的现象,这是为什么呢?因为问题出在反向循环上,如果反向循环到i为止,都未能找到奇数,那也就不会有prevIndex的赋值,那外层的循环也就会继续下去,然后就会出现循环次数高于数组长度的情况,修正代码,增加判断停止标志位:

static void SetLeftSingleAndRightDoubleOne(int[] arr)
{
    int num = 0;
    var prevIndex = arr.Length - 1;
    for (var i = 0; i <= prevIndex; i++)
    {
        if (arr[i] % 2 == 0)
        {//偶数
            bool stop = false;//停止标志位
            for (var j = prevIndex; j > i; j--)
            {
                num++;
                if (arr[j] % 2 != 0)
                {
                    //奇数
                    var b = arr[i];
                    prevIndex = j - 1;//当前位置已与偶数更换过位置,所以设置值的索引可以减一
                    arr[i] = arr[j];
                    arr[j] = b;
                    break;
                }
                stop = j == i + 1;//多了一步赋值
            }
            if (stop)//虽然多了一步判断,但循环次数有减少
            {//因为反向遍历已经遍历到了i的前一位,所以可以停止遍历了
                break;
            }
        }
        else
        {
            num++;
            //奇数
            continue;
        }
    }
    //Console.WriteLine("ONE RUN NUMS:" + num);
}

OK,算法已经实现,然后得到同事的实现,大体思路一致,都是左右遍历交替,具体如下:

static void SetLeftSingleAndRightDoubleTwo(int[] arr)
{
    int left = 0;
    int right = arr.Length - 1;
    int num = 0;
    while (left < right)
    {
        num++;
        bool leftDouble = arr[left] % 2 == 0;//判断左侧是否是偶数
        bool rightSingle = arr[right] % 2 != 0;//判断右侧是不是奇数
        if (!leftDouble)
        {
            left++;
        }
        if (!rightSingle)
        {
            right--;
        }
        if (leftDouble && rightSingle)
        {
            int t = arr[left];
            arr[left] = arr[right];
            arr[right] = t;
            left++;
            right--;
        }
    }
    //Console.WriteLine("TWO RUN NUMS:" + num);
}

与实现一相比,每次循环都会低位高位找两个位置,并判断是否能进行替换,因为每次循环都判断高低两个位置,所以时间复杂度上要低于实现一

最后就是具体的测试代码,为测试结果更为精准,每个实现都执行10次

Stopwatch watch= new Stopwatch();
for (var i = 0; i < 10; i++)
{
    Console.WriteLine("*******************************");
    Console.WriteLine("Run the " + (i + 1) + "st time");
    var tmp = Enumerable.Range(1, 50/*00000*/).OrderBy(_ => Guid.NewGuid()).Skip(30).ToArray();
    //arr = Enumerable.Repeat<int>(1, 50).ToArray();
    //arr = new int[50];
    var arr1 = tmp.ToArray();
    var arr2 = tmp.ToArray();

    watch.Reset();
    watch.Start();
    SetLeftSingleAndRightDoubleOne(arr1);
    watch.Stop();
    Console.WriteLine("ONE MS:" + watch.ElapsedMilliseconds);
    //Console.WriteLine(string.Join(",", arr1));

    watch.Reset();
    watch.Start();
    SetLeftSingleAndRightDoubleTwo(arr2);
    watch.Stop();
    Console.WriteLine("TWO MS:" + watch.ElapsedMilliseconds);
    //Console.WriteLine(string.Join(",", arr2));
}

最后分别按正确性和执行时间截了两张图,正确性方面两者一致,执行时间方面实现二要略优于实现一

正确性截图

执行时间截图

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-25 15:16:43

混乱无序的整数数组如何实现左侧全是奇数右侧全是偶数(数字不要求排序)的相关文章

在一个N个整数数组里面,有多个奇数和偶数,设计一个排序算法,令所有的奇数都在左边。

//在一个N个整数数组里面,有多个奇数和偶数,设计一个排序算法,令所有的奇数都在左边. // 例如: 当输入a = {8,4,1,6,7,4,9,6,4}, // a = {1,7,9,8,4,6,4,6,4}为一种满足条件的排序结果 using System; namespace SuanFa { class Program { //在一个N个整数数组里面,有多个奇数和偶数,设计一个排序算法,令所有的奇数都在左边. static void Main(string[] args) { int[]

Leetcode 581.最短无序连续子数组

最短无序连续子数组 给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, 6, 4, 8, 10, 9, 15] 输出: 5 解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序. 说明 : 输入的数组长度范围在 [1, 10,000]. 输入的数组可能包含重复元素 ,所以升序的意思是<=. 题目给了我们一个nums array,

软件工程课程作业(四)--返回一个整数数组中最大子数组的和

伙伴链接:http://www.cnblogs.com/haoying1994/ 一.设计思想 本实验要求输入一个正负数混合的整型数组,长度不限,在此数组的所有子数组中找到和最大的数组,并求出相应数组的和,且时间复杂度为O(n).我们在课堂上共同讨论了多种解决方案,这些将在下面可能的解决方案中展示,在听了同学的思路和老师的讲解之后, 我们最终选取了老师课堂上描述的比较简便的思路.如下: 在输入数组的环节,采用for无限循环加if判断截止,直到触发回车键为止,将数组记录到Array中,数组长度记录

结对开发之返回一个二维整数数组中最大联通子数组的和

一.题目要求 输入一个二维整形数组,数组里有正数也有负数.二维数组首尾相接,象个一条首尾相接带子一样.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n)题目:返回一个二维整数数组中最大子数组的和 二.解题思路 先对二维数组进行了重构,形成一个环状二维数组,然后再用求二维数组子矩阵最大和的方法求得最终结果. 三.程序代码 2 #include<iostream.h> 3 int main(int argc, char* argv[]

结对开发——返回整数数组最大子数组和2

返回整数数组最大子数组和2 为了实现“敏捷开发”的目的,老师让我们采取“迭代”的方法进行项目的开发,这不,对于周一的求最大子数组和又有了新的要求,如下: 1.延续上次的要求,这里不再赘余… 2.如果数组A[0]……A[j-1]首尾相连,允许A[i-1],……A[n-1],A[0]……A[j-1]之和最大: 3.同时返回最大子数组的位置: 4.要求程序必须能处理1000 个元素,且每个元素是int32 类型的. 一.实验设计思路 首先实现的是数组首尾相连,先存入数组,再将原数组反向存储形成环形数组

课后实验4--返回一个整数数组中最大子数组的和

伙伴链接:http://www.cnblogs.com/chengqiqin07/ 一.设计思想 本实验要求输入一个正负数混合的整型数组,长度不限,在此数组的所有子数组中找到和最大的数组,并求出相应数组的和,且时间复杂度为O(n).我们在课堂上共同讨论了多种解决方案,这些将在下面可能的解决方案中展示,在听了同学的思路和老师的讲解之后, 我们最终选取了老师课堂上描述的比较简便的思路.如下: 在输入数组的环节,采用for无限循环加if判断截止,直到触发回车键为止,将数组记录到Array中,数组长度记

返回一个二维整数数组中最大联通子数组的和6

1 问题:返回一个二维整数数组中最大联通子数组的和 2 思路:对n*m的二维数组进行分解,分解为n个一维数组,再先求这n个一维数组的最大子数组和,并记下每行最大一维子数组的下标如2-5,这是就会分两种情况第一种是行之间的最大子数组是相连的,如第一行是2-5,第二行是3-6,这是直接相加就行.第二种是不相连的如第一行是2-5,第二行是6-7,这时候就把每行的最大子数组看成一个整体,再使每个最大数组块进行相连,求使其相连的最小代价.最后就可求出最大联通子数组的和. 3 代码 #include<ios

返回一个整数数组中最大子数组的和4

题目:返回一个二维整数数组中最大子数组的和. 要求: 1 输入一个二维整形数组,数组里有正数也有负数. 2 二维数组首尾相接,象个一条首尾相接带子一样. 3 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 4 求所有子数组的和的最大值.要求时间复杂度为O(n). 设计思想 目前的解决方案是最笨的方法,穷举,所以时间复杂度达不到题目的要求,还需要进一步的寻找答案 源代码 题目:返回一个二维整数数组中最大子数组的和. 要求: 1 输入一个二维整形数组,数组里有正数也有负数. 2 二

返回一个首尾相接的二维整数数组中最大子数组的和

一.题目:返回一个二维整数数组中最大子数组的和. 二.要求: (1)输入一个二维整形数组,数组里有正数也有负数. (2)二维数组首尾相接,象个一条首尾相接带子一样. (3)数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. (4)求所有子数组的和的最大值. 三.解题思路: 将两个同样的数组首尾相接合并成一个数组,在用以前求二维数组最大子数组的方法求解 四.源代码: #include<iostream> using namespace std; #include"math