java把数字排成正负交替_一个数组有正数有负数,调整数组中的数使得正负交替...

一个数组有正数有负数,调整数组中的数使得正负交替

例:[-3, 6, 7, -4] ->[6, -3, 7, -4]

思路:采用两个指针,一个指向偶数位,记为a;一个指向奇数位,记为b;我们规定偶数位只能是正数,奇数位只能是负数;则当a指到负数时停下,b指到正数时停下,然后交换两者的值,在分别向后查找,直到有一个指针超出数组长度。则当原数组一定可以调整为正负交替的前提下,用双指针可以完成调整,时间复杂度为O(N),空间复杂度为O(1)(只需要两个指针,不需要额外空间)

对本题做出一定改动

给一个包含正负整数的数组,要求对这个数组中的数进行重新排列,使得其正负交替出现。首先出现负数,然后是正数,然后是负数。有多余的一方,就放在末尾。

要求:使用O(1)的空间

问1:如果需要保持正数序列和负数序列各自原来的顺序,如何做,时间复杂度是多少?

问2:如果不需要保持正数序列和负数序列各自原来的顺序,如何做,时间复杂度是多少?

思路分析:题目要求只能使用O(1)的空间复杂度,也就是只能借助一个临时变量,想到如下思路,依次遍历数组中的每个元素,如果处在偶数位置的数是负数,处在奇数位置的数是正数就保持不变;如果处在偶数位置的数是正数,就该位置的下一个位置依次向后找到第一个为负数的数(如果没找到说明后面全是正数,此时满足有多余的这一情况,正数全放在末尾),然后移动将找到的负数移动到偶数的位置(借助临时变量,用类似冒泡的方法把目标数字冒上来,这样保持后面的数字相对顺序不变),同理对应处在奇数位置的数负数做类似的处理。

问1和问2的不同地方在于对处在偶数位置的数是正数或处在奇数位置的数是负数处理。

问1因要保持原来的顺序,所以要在将找到的数num[j]放到原数位置num[i]后,从原num[i]开始到num[j-1]依次向后移动一位,而问2不需要保持原来的顺序,所以可以直接交换,这样的时间复杂度为O(N2)。

问题一的一种近似O(NlogN)的解法:

(https://blog.csdn.net/v_july_v/article/details/7329314)

双指针分别指向头和尾,头指针找到的正数同尾指针找到的负数交换,直到2个指针相遇。交换过程中将所有交换元素×-1,也就是正数变负数,负数变正数。此时被换到尾部的正数(×-1后已经变为负数),顺序正好倒过来了,把这部分反转一下。整个过程O(n),把原问题转化为两个规模为n/2的子问题。因此根据主定理,整个过程应当是nlog(n)的,即最坏情况下是n^2的,不过平均情况下也只是nlog(n)的,达不到O(n)。用迭代的方法写,应该可以做到O(1)(用递归,空间复杂度就是log(n)了)

看来这个问题的确有点麻烦,不过我们最终貌似还是找到了另外一种解决办法,正如朋友超越神所说的:从后往前扫描,遇到负数,开始记录负数区间,然后遇到正数,记录前面的正数区间,然后把整个负数区间与前面的正数区间进行交换,交换区间但保序的算法类似(a,bc->bc,a)的字符串原地翻转算法。交换完之后要继续向前一直扫描下去,每次碰到负数区间在正数区间后面,就翻转区间。下面,将详细阐述此思路4。

思路5之区间翻转

其实上述思路5非常简单,既然单个翻转无法解决问题,那么咱们可以区间翻转阿。什么叫区间翻转?不知读者朋友们是否还记得本blog之前曾经整理过这样一道题,微软面试100题系列第10题,如下:

10、翻转句子中单词的顺序。

题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。例如输入“I am a student.”,则输出“student. a am I”。而此题可以在O(N)的时间复杂度内解决:

由于本题需要翻转句子,我们先颠倒句子中的所有字符。这时,不但翻转了句子中单词的顺序,而且单词内字符也被翻转了。我们再颠倒每个单词内的字符。由于单词内的字符被翻转两次,因此顺序仍然和输入时的顺序保持一致。

以上面的输入为例:翻转“I am a student.”中所有字符得到“.tneduts a ma I”,再翻转每个单词中字符的顺序得到“students. a am I”,正是符合要求的输出(编码实现,可以参看此文:http://zhedahht.blog.163.com/blog/static/254111742007289205219/)。

对的,上述思路3就是这个意思,单词翻转便相当于于区间翻转,既如此,咱们来验证下上述思路2中那个测试用例,如下:

1, 7, -5, -6, 9, -12, 15

1 7 -5 -6 -12 9 15

-12 -6 -5 7 1 9 15 (借用单词翻转的方法,先逐个数字翻转,后正负数整体原地翻转)

-5 -6 -12 1 7 9 15

————————————————

版权声明:本文为CSDN博主「v_JULY_v」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/v_july_v/article/details/7329314

问1代码,时间复杂度O(n^2):

void sortA(int arr[], int n)

{

for (int i = 0; i < n; i++)

{

if (i % 2 == 0 && arr[i] < 0)

continue;

if (i % 2 == 1 && arr[i]>0)

continue;

if (i % 2 == 0 && arr[i]>0)

{

int j;

int temp;

for (j = i + 1; j < n && arr[j]>0; j++);

if (j == n) break;

else

{

temp = arr[j];

for (; j > i; j--)

{

arr[j] = arr[j - 1];

}

arr[i] = temp;

}

}

if (i % 2 == 1 && arr[i]<0)

{

int j;

int temp;

for (j = i + 1; j < n && arr[j]<0; j++);

if (j == n) break;

else

{

temp = arr[j];

for (; j > i; j--)

{

arr[j] = arr[j - 1];

}

arr[i] = temp;

}

}

}

}

版权声明:本文为CSDN博主「数据小冰」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/mingyong_blog/article/details/40183157

问2代码,时间复杂度近似O(N2)(如果第一个元素距离很远时,距离不远则近似O(N)):

void sortB(int arr[], int n)

{

for (int i = 0; i < n; i++)

{

if (i % 2 == 0 && arr[i] < 0)

continue;

if (i % 2 == 1 && arr[i]>0)

continue;

if (i % 2 == 0 && arr[i]>0)

{

int j;

int temp;

for (j = i + 1; j < n&&arr[j]>0; j++);

if (j == n) break;

else

{

temp = arr[j];

arr[j] = arr[i];

arr[i] = temp;

}

}

if (i % 2 == 1 && arr[i]<0)

{

int j;

int temp;

for (j = i + 1; j < n && arr[j]<0; j++);

if (j == n) break;

else

{

temp = arr[j];

arr[j] = arr[i];

arr[i] = temp;

}

}

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值