谷歌面试题:数组元素移动交叉

注:刚刚看到本题目更详细的分析http://blog.csdn.net/v_july_v/article/details/10212493 中间部分的“第三十五章、完美洗牌算法的变形

上面博客中的步步前移O(n^2)算法如下(虽然这种方法效率太低,不过对后面算法的思路还是有帮助的,具体分析参考上面博客):

void swap(int& x,int& y)
{
	int tmp;
	tmp=x;
	x=y;
	y=tmp;
}

void SwapArray(int *a,int n)
{
	int i,j,k;
	for (i=n/2;i<n-1;i++)   //i为需要交换的数的下标,实际是b[1]...b[n-1]
	{
		k=i;
		for (j=n-i-1;j>=1;j--) //j控制循环交换的次数,具体怎么确定交换多少次,请参见上面博客中的分析
		{
			
			swap(a[k],a[k-1]);
			k--;
			
		}
	}
}


 

题目:输入数组:{a1,a2,…,an,b1,b2,…,bn}, 在O(n)的时间,O(1)的空间将这个数组的顺序变为{a1,b1,a2,b2,a3,b3,…,an,bn}, 且不需要移动,通过交换完成,只需一个交换空间。

解答:从结果入手,结果数组的中垂线两边分别a数组的一半和b数组的一半的混合,继续将子数组以中垂线划分下去,可以看到类似的规律,因此,可以使用类似的分治算法实现。

注:其实这种方法的复杂度为O(nlgn),达不到O(n)的要求,希望会O(n)算法的童鞋能附一下答案或链接,谢谢大笑

void swap(int *a,int i,int j)
{
	int tmp;
	tmp=a[i];
	a[i]=a[j];
	a[j]=tmp;
}
//下面以arr[10]={a1,a2,a3,a4,a5,b1,b2,b3,b4,b5}说明
void solve(int arr[],int start ,int end)   
{   
    //初始值start=0,end=9
    if( start >= end)   
        return;   
	
    int mid = (start+end)/2;   
	
    //lEndft part: start,...,mid;   
    //right part mid+1,...,end   
    int lStart = start;   
    int lEnd = mid;   
    int rStart = mid+1;   
    int rEnd = end;    
   //这个for循环的意思就是把需要放在左边的元素先调到左边(先不管排序情况),后面附上例子的详细解释
    for(int i=(lEnd+lStart)/2+1,j = rStart ; i <= lEnd; i++,j++)   
        swap(arr,i,j);   
	
    //左边元素或右边元素有奇数个,为什么只判断左边元素是否为奇数呢,因为右边元素数一定等于左边元素数
    //为什么是(lEnd-lStart)%2==0,比如a[0]a[1]a[2]a[3]a[4]一共5个元素,(4-0)%2==0,所以。。
   //至于为什么把左右两边的元素数凑成偶数来计算,我也没看明白,但是如果没有这一步,就得不到结果,整个程序
   //最重要的部分应该就是这个地方的判断了   
   if(lEnd!=lStart && (lEnd-lStart)%2==0)
   {   
        lEnd++;   
        rStart--;   
    }     
	
    solve(arr,lStart,lEnd);   
    solve(arr,rStart,rEnd);   	
}  


void main()  
{  
	const int SIZE=10;
	int a[SIZE]={1,3,5,7,9,2,4,6,8,10};
	//int a[SIZE]={1,3,5,2,4};
	for(int i=0;i<SIZE;i++)
		cout<<a[i]<<" ";
	cout<<endl;

	solve(a,0,SIZE-1);

	for(i=0;i<SIZE;i++)
		cout<<a[i]<<" ";
	cout<<endl;
}  

下面是我写的推导过程,字迹潦草,还请见谅

转自http://s.sousb.com/?p=568

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值