您的位置:首页 > 其它

不改变正负数之间相对顺序重新排列数组

2012-11-22 00:22 232 查看
不改变正负数之间相对顺序重新排列数组

一个未排序整数数组,有正负数,重新排列使负数排在正数前面,并且要求不改变原来的正负数之间相对顺序。
比如: input: 1,7,-5,9,-12,15 ,ans: -5,-12,1,7,9,15 。且要求时间复杂度O(N),空间O(1)

说一个O(n)时间,O(1)空间的方法。
 
开一个Int[32]数组,可以在O(n)的时间内对原数组进行分块,块的大小为32。例如:
 
-1 -9 1 8 9 4 - 2 3 5 6 7 -8 2 1 -3 -7 -11 -1 3 4
用一个长度为4的数组,分为长度为4的块,归并过程大概是这样的(x表示空着的位置):
x x x x
-1 -9 1 8 9 4 -2 3 5 6 7 -8 2 1 -3 -7 -11 -1 3 4
=>
1 8 9 4
-1 -9 x x x x -2 3 5 6 7 -8 2 1 -3 -7 -11 -1 3 4
=>

-1 -9 x x
1 8 9 4 x x -2 3 5 6 7 -8 2 1 -3 -7 -11 -1 3 4

=>

-1 -9 -2 x

1 8 9 4 3 5 6 7 x x x -8 2 1 -3 -7 -11 -1 3 4

=>

x x x x

1 8 9 4 3 5 6 7 -1 -9 -2 -8 2 1 -3 -7 -11 -1 3 4

=>

-3 -7 -11 -1

1 8 9 4 3 5 6 7 -1 -9 -2 -8 2 1 x x x x 3 4

=>

2 1 x x

1 8 9 4 3 5 6 7 -1 -9 -2 -8 -3 -7 -11 -1 x x 3 4

=>

x x x x

1 8 9 4 3 5 6 7 -1 -9 -2 -8 -3 -7 -11 -1 2 1 3 4
 

每个块里只有正数或负数(除了最后1个或2个块),不存在正负交替的情况。在这个过程中记录一下正负块的个数(上面的例子中,正数3个块,负数2个块)。
 
然后我们发现,既然每个块里不是正数就是负数,那么这32个数其实只需要1个标志来标明是正数还是负数,我们保留这32个数中第一个数的符号,剩下的31个数,每个数可以为我们提供1Bit的信息量,我们还可以用来保留其他信息。在此我们用来存储这个块儿的最终位置信息。有了这部分信息,我们可以利用类似原地归并的方法,在O(n)时间内,完成对块儿的排序。
 
以分好块的1 8 9 4 3 5 6 7 -1 -9 -2 -8 -3 -7 -11 -1 2 1 3 4为例,
 
总共有2个负数块儿,因此1 8 9 4是最终排第3的块,3 5 6 7 第4 | -1 -9 -2 -8第1 |-3 -7 -11 -1 第2| 2 1 3 4第5
 
我们用0 - 4的编号表示第1至第5
 
1 8 9 4 对应2,二进制表示为10,填满3位就是010,把每个块的第1位保持不动,后面用来记录位置,1 8 9 4变为了1 8 -9 4。同理3 5 6 7对应第3个块,3的二进制表示为011,3 5 6 7变为3 5 -6 -7
 
最后再用O(n)的时间处理一下最后的两个块,方法类似于字符串的翻转。这样的话总的时间为O(n),空间主要是那个Int[32]辅助数组,用在最初分块那部分,其实再小一些也可以,那样看起来更像O(1),但逻辑要复杂很多,在这里不细说了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法
相关文章推荐