题目
- 不改变正负数相对顺序重新排列数组
思路
- 块翻转,如果出现第奇数次”+..+-…-“这种块,则反转变成”-…-+…+”,因为每次扫描只是翻转不相邻的(正正…正负…负负)串,因此所有被翻转的串,从正负数分界处被分为两部分,分别归入前后两个相邻的(正正…正负…负负)串。因此,每趟扫描能消灭一半的(正正…正负…负负)串。最终,总共需要扫描的次数最多为logN。
- 参考:Link
代码
#include<iostream>
#include<vector>
using namespace std;
void reverse(vector<int>& nums, int start, int end)
{
int i=start, j=end;
while(i<j)
{
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
i++;
j--;
}
}
void reverse_block(vector<int>& nums, int start, int mid, int end)
{
reverse(nums, start, mid);
reverse(nums, mid+1, end);
reverse(nums, start, end);
}
int main()
{
int n;
cin>>n;
vector<int> nums(n, 0);
for(int i=0;i<n;i++)
cin>>nums[i];
while(1)
{
int p_and_n = 0; //表示“正...正负...负”这种格式的串的个数
int index = 0;//索引
int p_start = 0;//正数的开始位置
int p_end = 0;//正数的结束位置
int n_end = 0;//负数的结束位置
bool pre_p = false; //表示之前是正
bool r = true; //是否需要反转,第奇数个正负需要翻转
while(index<nums.size())
{
if(nums[index]>0)
{
p_start = index;
while(index+1<nums.size() && nums[index+1]>0)
index++;
p_end = index;
pre_p = true;
}
else if(nums[index]<0)
{
while(index+1<nums.size() && nums[index+1]<0)
index++;
n_end = index;
if(pre_p)
p_and_n++;
if(pre_p && r)//如果前面的为正数,且当前可反转
{
reverse_block(nums, p_start, p_end, n_end);
r = !r;
pre_p = !pre_p;
}
}
index++;
}
if(p_and_n==0)
break;
}
//输出
for(int i=0;i<nums.size();i++)
cout<<nums[i]<<endl;
system("pause");
return 0;
}