zoukankan      html  css  js  c++  java
  • 面试题:有限制几个全阵列

    给定一个数组,例如
    [45,54,2,99,1]
    给定一个长度l,比如100

    能够对数组中相邻的两个数交换,前提必须满足两个数的和不大于l

    求通过这样的交换所可以产生的全排列有多少种?对于同样的数,也默认它们不同。


    这是某外企的电面题,感觉要找到比較好的算法还是挺难的。眼下想到的是一种循环暴力搜索加暴力剪枝并回溯的,从測试数据来看。效果还凑合。

    思路是

    暴力搜索:查看不论什么一个数,看能否够交换到第一位。假设能够。则规模就能够减少而且递归,复杂度为O(n^3+n!)

    int orderCount(int *a, int n, int l){
    	if(n <= 1)return 1;
    	int ans = 0;
    	for(int i = 0;i < n;i ++){
    		int j;
    		for(j = i-1;j >= 0;j --)
    			if(a[i]+a[j] > l)
    				break;
    		if(j >= 0)continue;
    		int t = a[i];
    		for(j = i-1;j >= 0;j --)
    			a[j+1] = a[j];
    		ans += orderCount(a+1,n-1,l);
    		for(j = 0;j < i;j ++)
    			a[j] = a[j+1];
    		a[i] = t;
    	}
    	return ans;
    }

    剪枝:

    1. 假设一个数能够和所以其它的都交换,这个数将相当于剩下的数的全排列然后这个数随意插入,即问题就变成n*f(n-1)

    2. 假设一个数不能和不论什么其它的数交换,它将时问题变成左右的全排列相乘,及f(i)*f(n-i-1)

    //some additional optimization
    //If one number could not exchange with any other, it would divide the problem into two subproblem
    //If one number could exchange with any other, n multiply the left exchange solutions
    int order(int *a, int n, int l){
    	int exn = 0;
    	int *exp = new int[n];
    	for(int i = 0;i < n;i ++){
    		int ex = 0;
    		int unex = 0;
    		for(int j = 0;j < n;j ++){
    			if(i == j)continue;
    			if(a[i] + a[j] <= l)
    				ex ++;
    			else
    				unex ++;
    		}
    		if(unex == n-1)
    			return orderCount(a,i,l)*orderCount(a+i+1,n-i-1,l);
    		if(ex == n-1){
    			int t = a[i];
    			for(int j = i-1;j >= exn;j --)
    				a[j+1] = a[j];
    			exp[exn] = i;
    			a[exn ++] = t;
    		}
    	}
    	int x = 1;
    	for(int i = 0;i < exn;i ++)
    		x *= n-i;
    	return x*orderCount(a+exn,n-exn,l);
    }
    

    回溯:

    上面的剪枝,我们仅仅是对最開始的数据进行了剪枝,后来的搜索就不再处理剪枝了,所以效率并不高。那我们就要考虑是否可以每个递归都来做剪枝。而这里由于数组的位置变化会影响终于的结果。所以无论是搜索剪枝的过程,完毕之后一定要恢复原来的数组。这样才不会影响其它接下来过程的结果。于是就得到终于的每一步都剪枝的循环方法。

    经过測试,这样的方法对于測试数据可以高速得到结果,明显优于上面的单纯暴力方法。

    int order(int *a, int n, int l);
    //The code modified in the interview
    int orderCount(int *a, int n, int l){
    	if(n <= 1)return 1;
    	int ans = 0;
    	for(int i = 0;i < n;i ++){
    		int j;
    		for(j = i-1;j >= 0;j --)
    			if(a[i]+a[j] > l)
    				break;
    		if(j >= 0)continue;
    		int t = a[i];
    		for(j = i-1;j >= 0;j --)
    			a[j+1] = a[j];
    		//ans += orderCount(a+1,n-1,l);
    		ans += order(a+1,n-1,l);
    		for(j = 0;j < i;j ++)
    			a[j] = a[j+1];
    		a[i] = t;
    	}
    	return ans;
    }
    //some additional optimization
    //If one number could not exchange with any other, it would divide the problem into two subproblem
    //If one number could exchange with any other, n multiply the left exchange solutions
    int order(int *a, int n, int l){
    	int exn = 0;
    	int *exp = new int[n];
    	for(int i = 0;i < n;i ++){
    		int ex = 0;
    		int unex = 0;
    		for(int j = 0;j < n;j ++){
    			if(i == j)continue;
    			if(a[i] + a[j] <= l)
    				ex ++;
    			else
    				unex ++;
    		}
    		if(unex == n-1)
    			return orderCount(a,i,l)*orderCount(a+i+1,n-i-1,l);
    		if(ex == n-1){
    			int t = a[i];
    			for(int j = i-1;j >= exn;j --)
    				a[j+1] = a[j];
    			exp[exn] = i;
    			a[exn ++] = t;
    		}
    	}
    	int x = 1;
    	for(int i = 0;i < exn;i ++)
    		x *= n-i;
    	int ans = x*orderCount(a+exn,n-exn,l);
    	while(exn){
    		exn --;
    		int t = a[exn];
    		for(int j = exn;j < exp[exn];j ++)
    			a[j] = a[j+1];
    		a[exp[exn]] = t;
    	}
    	return ans;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int b[] = {45,54,2,80,3,69,2,65,94,74,80,23,8,5,9,3,18,67,99};
    	clock_t t1,t2,t3;
    	t1 = clock();
    	cout<<orderCount(b,19,100)<<endl;
    	t2 = clock();
    	cout<<order(b,19,100)<<endl;
    	t3 = clock();
    	cout<<t2-t1<<" vs "<<t3-t2<<endl;
    	char ch;
    	cin>>ch;
    	return 0;
    }
    


    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    转移虚拟机后ubuntu network available SIOCSIFADDR: No such device
    模板中国剩余定理
    数论 CF27E Number With The Given Amount Of Divisors
    模板 输入输出优化
    模板 欧拉定理
    洛谷P1141 01迷宫
    图论拓扑排序
    归并排序 分治
    HZNUACM寒假集训Day12小结 数论入门 题解
    组合数学基础
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4673833.html
Copyright © 2011-2022 走看看