关于数的问题

问题:给你一个数组 array,以及一个特定值 sum,找出数组中所有和为sum 的两个数对。

 

/*Solution 1
 1.建立一个hash table,把数组中的所有元素映射到hash table中,
 2 遍历array中的每一个元素i,针对对每个元素i,首先删除hash table中的此元素i(避免冗余),
   然后查找 sum-i 是否在hash table中,如果在则找到一对数,否则继续遍历。

  空间复杂度O(n),时间复杂度O(n).
*/

/* Solution 2: 
  1. 排序数组  最好的时间复杂度O(nlogn)
  2. 遍历数组,针对每个元素i,在i元素后面的数列中二分查找 sum-i ;最坏的时间复杂度为 O(nlogn)
  总的时间复杂度:O(nlogn)
*/

/* Solutin 3:
  1. 排序数组  最好的时间复杂度O(nlogn)
  2. 前后遍历数组,过程见函数printPariSums(); O(n);
 */


void printPairSums(int *array,int len,int sum){
	sort(array,array+len); // 升序排列
	cout<<endl;
	int first=0;
	int last=len-1;
	int temp_sum;
	while(first<last){
		temp_sum=array[first]+array[last];
		if(temp_sum==sum){
			cout<<array[first]<<"+"<<array[last]<<endl;
			++first;
			++last;
		}
		else if(temp_sum<sum)
			++first;
		else 
			--last;
	}

}

void main(){
	int array[10]={4,5,12,1,-1,-4,10,11,14,-2};
	printPairSums(array,10,9);
}

 

问题2:随机数问题。给定rand5() (随机生成1-5),怎么构成一个Rand7(),随机生成的数在1-7之间。

/*
随机生成,在于每个数要等概率。
方法1. 多次rand(0,1) { 生成0或1 的函数 }, 组合法,如k=3次运行rand(0,1) ,可有000,001,010,011...111 把个数,
       即有8个范围,区间为[0,2^k)每个数概率相等
方法2. 扩大区间映射

较为详细的讲解可见<http://www.cnblogs.com/dwdxdy/archive/2012/07/28/2613135.html>
这里给出一个实现
*/
int rand7(){
	while(true){
		int sum=5*(rand5()-1)    //产生0,5,10,15,20
			    +(rand5()-1);    //产生0,1,2,3,4, 两者相加使sum正好为0,1,2,...24,每个数的产生概率相等
		if(sum<21)               // 取前21个数(0,1,...20 )
			return sum%7+1;      // 模除+1,正好为1-7.
	}
}

 

问题3:找出两个数中的最大数,不能用if-else 以及任何比较运算符

思考过程:if a>b. return a, else return b;

                  if a-b>0 return a,else return b;

                  if a-b>0 let k=0;else let k=1; return a-k(a-b);

                  let c=a-b; let k 为c的符号位,return a-k*c;

int getMax(int a,int b){
	int c=a-b;
	int k=(c>>(sizeof(int)-1))&0x1;
	return a-k*c;
}


问题4:就地交换两个数,不用任何临时变量

 

void swap(int a,int b){
	cout<<a<<endl;
	cout<<b<<endl;
	a=a^b;
	b=a^b;
	a=a^b;
	cout<<a<<endl;
	cout<<b<<endl;
}


问题5:统计n!中末尾0的个数。

/* 5*2=10,所以5会贡献一个0,5的倍数都会贡献一个0;25=5*5 会贡献2个0,同理125会贡献3个0...
所以要统计5的倍数的个数,25倍数的个数,125倍数的个数...
*/
int numbersOfZeros(int num){
	int count=0;
	int i=0;
	if(num<0){
		cout<<"no zero"<<endl;
		return -1;
	}
	for(i=5;num/i>0;i*=5){
		count+=num/i;
	}
	return count;
}

int main(){
	int num=17;
	int64_t sum=1;
	int i=1;
	for(i=1;i<=num;i++)
		sum*=i;
	cout<<"sum="<<sum<<endl;
	cout<<"0 nums="<<numbersOfZeros(num)<<endl;
	return 0;
}


问题6 统计数字x的二进制中1的个数有多少个

int main(){
	int x;
	cin>>x;
	while(x){
		// 统计x的二进制中1的个数有多少个?
		int count=0;
		cout<<"x 的16进制是:"<<hex<<x<<endl;
		while(x){
			count++;
			x=x&(x-1);
		}
		cout<<"x 中1的个数为"<<count<<endl;
	
		cin>>x;
	}
	return 0;
}

当然,也可以用移位法。

问题7: 计算两数之和,不用+ 及其他算数操作符。
// 思考:计算机加法是如何实现的?异或 表示的是什么?与 & 表示的又是什么?

 

int add_no_arithmetic(int a,int b){
	if(b==0) return a;
	int sum=a^b;           //^ 计算两者之和,不考虑进位
	int carry=(a & b)<<1; // & 计算出进位,左移一位
	add_no_arithmetic(sum,carry);
}


问题8:从n个数中,随机选出m个数

// 需要注意的问题或者需要问清楚面试官:这m个数可以有相同的吗?实际上不应当相同,也就是我们要解决一个数可能被选择两次的问题

int* PickRandom(int array[],int n,int m){
	int *mp=new int[m];
	for(int i=0;i<m;i++){
		int index=rand()%(n-i)+i;// 范围的控制,避免选择前面的"dead"元素
		mp[i]=array[index];
		array[index]=array[i]; //把已经选择的元素(称为"dead"元素)交换到数组的前面,array[i] 作为"dead" 元素,不会被搜寻
	}
	return mp;
}

int main(){
	int a[10]={3,23,1,-56,8,23,45,233,0,1234};
	int *p=PickRandom(a,10,5);
	for(int i=0;i<5;i++)
		cout<<p[i]<<" ";
	cout<<endl;
}


 问题9:在 0~n (包括n) 这些数字中有多少个2呢?

int count2(int n){
	if(n==0) return 0;
	int power=1;
	while(power*10<n)
		power*=10;
	int first=n/power;
	int remainder=n%power;
	int nTwosFirst=0;
	if(first>2)
		nTwosFirst+=power;

	else if(first==2)
		nTwosFirst+=remainder+1;
	int nTwosOther=first*count2(power-1)+count2(remainder);

	return nTwosFirst+nTwosOther;
	
}

void main(){
	int n;
	cin>>n;
	while(n){
		cout<<"0-"<<n<<" 中2的个数是:"<<count2(n)<<endl;
		cin>>n;
	}
}


 

问题10,计算1-100的和,不可使用while,if else ,三目运算法  等语句 (类似的题有 输出1,2,3,。。。。100 序列)


2013-9-27 记:::

首先想到递归,其次用 &&   ||  来结束递归操作

int sum (int n){

    int sum=0;

    int x=n && (sum=f(n-1));  

    return sum+n;

}

 

// 输出1到n, (假定 && 会返回1)

int  f(int n){
 
 cout<<( n && f(n-1) )*n+1<<endl;
 return 1;
}

调用 f(n-1)
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值