刚刚看到July博客里关于一道题目的解法,原文链接:http://blog.csdn.net/v_july_v/article/details/7329314#cpp
重新排列使负数排在正数前面
原题是这样的:
一个未排序整数数组,有正负数,重新排列使负数排在正数前面,并且要求不改变原来的正负数之间相对顺序。比如: input: 1,7,-5,9,-12,15 ,ans: -5,-12,1,7,9,15 。且要求时间复杂度O(N),空间O(1) 。
真抱歉,原题理解错误了,审慎理解之后发现是要求数组存储的,而转用链表则空间变成了O(n),造成误解,很抱歉!!
现提供我想到的想法,还没有代码实现。但时空复杂度应该是满足要求的。
因为牵扯到交换、遍历,所以不经意的时空就超标了。但如果使用链表的话,插入、保存原来的顺序这两点还是很容易做到的。
其原来的顺序有两点,一个是正数的顺序,一个是负数的顺序。所以需要两个指针指向这两个顺序链表的起始位置,negPt和posPt。
假设数据:
1 , 2, -1, -2, 3, 4, -3, 5
则有这样的链表:
H->(1)->(2)->(-1)->(-2)->(3)->(4)->(-3)->(5)
所以第一步是获得第一个正数的位置。在这之前,先定义这样一个结构:
1 typedef struct tEleDistgPosAndNeg
2 {
3 int ele;
4 tEleDistgPosAndNeg * next;
5 } tEleDistgPosAndNeg;
6
7 tEleDistgPosAndNeg * getFirstPostiveEle(tEleDistgPosAndNeg * header)
8 {
9 while (header != NULL)
10 {
11 // 把 0 归为正数中考虑
12 if (header->ele >= 0)
13 break;
14 header = header->next;
15 }
16 return header;
17 }
到这里, 时间复杂度最大为O(n), 如果是O(n),那也就结束了,因为到了最后一个字符才是正数。
另外,定义一个指向当前元素的指针,用于遍历整个链表;和另外一个当前元素的前一个元素,用于链接出正数链表,其总是指向当前位置中的最后一个正数。
1 tEleDistgPosAndNeg * curPt = H->next; // 总是指向当前遍历的元素
2 tEleDistgPosAndNeg * posPt = getFirstPostive(); // 第一个正数, O(n);
3 tEleDistgPosAndNeg * adPt = H; // 总是指向当前遍历的元素中最后一个正数
4 tEleDistgPosAndNeg * negPt = H; //当前遍历的元素中最后一个附属
5
6 while (curPt != NULL)
7 {
8 if (*curPt < 0)
9 {
10 adPt->next = curPt->next;
11
12 // 如果当前元素为负,则将negPt指向当前元素
13 negPt->next=curPt;
14 negPt = negPt->next;
15 }
16 else
17 {
18 // 当前为正数, 将adPt指向当前元素
19 adPt = curPt;
20 }
21
22 curPt = curPt->next;
23 }
24 curPt = posPt;
到这里的渐进时间复杂度是线性的:O(n) + O(n) = O(n)
空间复杂度是:四个指针,常数级,为O(1)。
另外, 如果考虑 0 的情况, 则需要在遍历的过程中记录 0 的位置,并且插在 curPt 和 posPt 之间。只是多了一个判断操作和三个指针操作而已。
我认为这个方法不难理解,而且满足要求,自我感觉还是不错的。