负数排在正数前面,

一个未排序整数数组,有正负数,重新排列使负数排在正数前面,并且要求不改变原来的正负数之间相对顺序。

方案一:

最简单的,如果不考虑时间复杂度,最简单的思路是从头扫描这个数组,每碰到一
个正数时,拿出这个数字,并把位于这个数字后面的所有数字往前挪动一位。挪完
之后在数组的末尾有一个空位,这时把该正数放入这个空位。由于碰到一个正,需
要移动O(n)个数字,因此总的时间复杂度是O(n^2)。

方案二:(还未动,待续)

转自:http://qing.blog.sina.com.cn/1570303725/5d98eeed33000hcb.html
思考的过程就略去了,直接说结果吧。我想到的算法,空间复杂度为O(1),时间复杂度为O(N*logN)。

首先,定义这样一个过程为“翻转”:(a1,a2,…,am,b1,b2,…,bn) –> (b1,b2,…,bn,a1,a2,…,am)。其次,对于待处理的未排序整数数组,从头到尾进行扫描,寻找(正正…正负…负负)串;每找到这样一个串,则计数器加1;若计数为奇数,则对当前串做一个“翻转”;反复扫描,直到再也找不到(正正…正负…负负)串。

举例如下

Input : 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7, 8, -8
Step1.1: [1, -1], 2, -2, [3, -3], 4, -4, [5, -5], 6, -6, [7, -7], 8, -8
Step1.2: [-1, 1], 2, -2, [-3, 3], 4, -4, [-5, 5], 6, -6, [-7, 7], 8, -8
Step2.1: -1, [1, 2, -2, -3], 3, 4, -4, -5, [5, 6, -6, -7], 7, 8, -8
Step2.2: -1, [-2, -3, 1, 2], 3, 4, -4, -5, [-6, -7, 5, 6], 7, 8, -8
Step3.1: -1, -2, -3, [1, 2, 3, 4, -4, -5, -6, -7], 5, 6, 7, 8, -8
Step3.2: -1, -2, -3, [-4, -5, -6, -7, 1, 2, 3, 4], 5, 6, 7, 8, -8
Step4.1: -1, -2, -3, -4, -5, -6, -7, [1, 2, 3, 4, 5, 6, 7, 8, -8]
Step4.2: -1, -2, -3, -4, -5, -6, -7, [-8, 1, 2, 3, 4, 5, 6, 7, 8]
Output: -1, -2, -3, -4, -5, -6, -7, -8, 1, 2, 3, 4, 5, 6, 7, 8

证明如下

先计算“翻转”的时间复杂度。

将(a1,a2,…,am,b1,b2,…,bn) 翻转为 (b1,b2,…,bn,a1,a2,…,am),只要三步:
(a1,a2,…,am,b1,b2,…,bn) –>
(bn,…,b2,b1,am,…,a2,a1) –>
(b1,b2,…,bn,am,…,a2,a1) –>
(b1,b2,…,bn,a1,a2,…,am)
总的来说,时间复杂度为O(2m+2n)

对于长度为N的数串来说,任选其中若干个互不重叠的子串进行翻转,总的时间复杂度不会超过O(N)。

接下来的问题,是“扫描”进行了多少次。

因为每次扫描只是翻转不相邻的(正正…正负…负负)串,因此所有被翻转的串,从正负数分界处被分为两部分,分别归入前后两个相邻的(正正…正负…负负)串。因此,每趟扫描能消灭一半的(正正…正负…负负)串。最终,总共需要扫描的次数最多为logN。

综上,时间复杂度为O(N*logN)。

阅读更多
个人分类: 编程艺术、一
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭