一些Google面试题

1.谷歌面试题:给定能随机生成整数 1 到 5 的函数,写出能随机生成整数 1 到 7 的函数。

回答:此题的关键是让生成的 1 到 7 的数出现概率相同。 只要我们可以从 n 个数中随机选出 1 到 n 个数,反复进行这种运算,直到剩下最后一个数 即可。 我们可以调用 n 次给定函数,生成 n 个 1 到 5 之间的随机数,选取最大数所在位置即 可满足以上要求。 例如 初始的 7 个数[1,2,3,4,5,6,7]. 7 个 1 到 5 的随机数[5,3,1,4,2,5,5] 那么我们保留下[1,6,7], 3 个 1 到 5 的随机数[2,4,1] 那么我们保留下[6] 6 就是我们这次生成的随机数。

 

2. 谷歌面试题:判断一个自然数是否是某个数的平方。当然不能使用开方运算。

回答: 假设待判断的数字是 N。

方法 1: 遍历从 1 到 N 的数字,求取平方并和 N 进行比较。 如果平方小于 N,则继续遍历;如果等于 N,则成功退出;如果大于 N,则失败退出。 复杂度为 O(n^0.5)。

方法 2: 使用二分查找法,对 1 到 N 之间的数字进行判断。 复杂度为 O(logn)。

方法 3: 由于 (n+1)^2 =n^2+2n+1, =... =1+(2*1+1)+(2*2+1)+...+(2*n+1) 注意到这些项构成了等差数列(每项之间相差 2) 。 所以我们可以比较 N-1,N-1-3,N-1-3-5...和 0 的关系。 如果大于 0,则继续减;如果等于 0,则成功退出;如果小于 0,则失败退出。 复杂度为 O(n^0.5)。不过方法 3 中利用加减法替换掉了方法 1 中的乘法,所以速度会更 快些。复杂度为 O(n^0.5)。

#define times 100
int calSqrt3(int N)
{
	int k = 1;
	int x = 0;
	while(N > 0)
	{
		N -= k;
		k += 2;
		x++;
	}
	if(N == 0) return x;
	else return -1;
}

int calSqrt2(int N)
{
	int l = 1;
	int h = N;
	int mid;
	
	while(l <= h){
		mid = l + (h-l)/2;
		int tmp = mid*mid;
		if(tmp == N) return mid;
		else if(tmp > N) h = mid-1;
		else l = mid+1;
	}
	return -1;
}

int main()
{
	//method3 O(N^0.5)
	clock_t start,end;
	double d;
	start = clock();
	for(int i = 1;i<=times;i++)
	{
		int tmp = calSqrt3(i);
	//	if(tmp > 0) cout<<i<<":"<<tmp<<endl;
	}
	end = clock();
	d = (double)(end - start) / CLOCKS_PER_SEC;
	cout<<d<<endl<<endl;

	//method2 O(logn)
	start = clock();
	for(int i = 1;i<=times;i++)
	{
		int tmp = calSqrt2(i);
	//	if(tmp > 0) cout<<i<<":"<<tmp<<endl;
	}
	end = clock();
	d = (double)(end - start) / CLOCKS_PER_SEC;
	cout<<d<<endl<<endl;
	return 0;
}

 方法2的复杂度最小,实测也最快。

5. 谷歌面试题:在半径为 1 的圆中随机选取一点。

回答: 假设圆心所在位置为坐标元点(0,0)。

方法 1. 在 x 轴[-1,1],y 轴[-1,1]的正方形内随机选取一点。然后判断此点是否在圆内(通过计算 此点到圆心的距离) 。如果在圆内,则此点即为所求;如果不在,则重新选取直到找到为止。 正方形的面积为 4,圆的面积为 pi,所以正方形内的随机点在圆内的概率是 pi/4。

方法 2. 从[0,2*pi)中随机选一个角度,对应于圆中的一条半径,然后在此半径上选一个点。但 半径上的点不能均匀选取, 选取的概率应该和距圆心的长度成正比, 这样才能保证随机点在 圆内是均匀分布的。


7.谷歌面试题:设计一个数据结构,其中包含两个函数,1.插入一个数字,2.获得中数。并估计时间复杂度。

回答: 1).使用数组存储。 插入数字时,在 O(1)时间内将该数字插入到数组最后。 获取中数时,在 O(n)时间内找到中数。 (选数组的第一个数和其它数比较,并根据比较 结果的大小分成两组, 那么我们可以确定中数在哪组中。 然后对那一组按照同样的方法进一 步细分,直到找到中数。 )

2).使用排序数组存储。 插入数字时,在 O(logn)时间内找到要插入的位置,在 O(n)时间里移动元素并将新数字 插入到合适的位置。获得中数时,在 O(1)复杂度内找到中数。

3).使用大根堆和小根堆存储。 使用大根堆存储较小的一半数字,使用小根堆存储较大的一半数字。 插入数字时,在 O(logn)时间内将该数字插入到对应的堆当中,并适当移动根节点以保 持两个堆数字相等(或相差 1) 。 获取中数时,在 O(1)时间内找到中数。

方法3代码如下:

#include<iostream>
#include<vector>
#include <ctime>
#include <cstdlib>
using namespace std;

template <class T>
class MidVec{
	vector<T> smallerHeap;
	vector<T> largerHeap;
	int mid;


	void minHeapify(vector<T> & vec,int i)
	{
		int left = i*2 + 1;
		int right = i*2 + 2;
		int smallest = i;
		if(left < vec.size()){
			smallest = (vec[left] < vec[smallest])?left:smallest;
		}
		if(right < vec.size())
		{
			smallest = (vec[right] < vec[smallest])?right:smallest;
		}
		if(smallest != i){
			swap(vec[i],vec[smallest]);
			minHeapify(vec,smallest);
		}
	}
	void maxHeapify(vector<T> & vec,int i)
	{
		int left = i*2 + 1;
		int right = i*2 + 2;
		int largest = i;
		if(left < vec.size()){
			largest = (vec[left] > vec[largest])?left:largest;
		}
		if(right < vec.size())
		{
			largest = (vec[right] > vec[largest])?right:largest;
		}
		if(largest != i){
			swap(vec[i],vec[largest]);
			maxHeapify(vec,largest);
		}
	}
public:
	void push(int i)
	{
		if(i > mid){
			if(largerHeap.size() > smallerHeap.size()){
				largerHeap[0] = i;
				smallerHeap.push_back(mid);
				swap(smallerHeap[0],smallerHeap[smallerHeap.size()-1]);
				for(int j = smallerHeap.size()/2;j>=0;j--)
					maxHeapify(smallerHeap,j);
			}else{
				largerHeap.push_back(i);
				swap(largerHeap[0],largerHeap[largerHeap.size()-1]);
			}
			for(int j = largerHeap.size()/2;j>=0;j--)
				minHeapify(largerHeap,j);
		}else{
			if(smallerHeap.size() > largerHeap.size()){
				smallerHeap[0] = i;
				largerHeap.push_back(mid);
				swap(largerHeap[0],largerHeap[largerHeap.size()-1]);
				for(int j = largerHeap.size()/2;j>=0;j--)
					minHeapify(largerHeap,j);
			}else{
				smallerHeap.push_back(i);
				swap(smallerHeap[0],smallerHeap[smallerHeap.size()-1]);
			}
			for(int j = smallerHeap.size()/2;j>=0;j--)
					maxHeapify(smallerHeap,j);
		}
		if(smallerHeap.size() >= largerHeap.size()) mid = smallerHeap[0];
		else mid = largerHeap[0];
	}
	int getMid()
	{
		return mid;
	}

};

int main()
{
	MidVec<int> vec;

	int a[] = {1,7,8,4,2,5,3,6,9,0};
	for(int i = 0;i<10;i++)
	{
		srand(a[i]);                                           //根据系统时间设置随机数种子
		int tmp = rand() % 100;     
		cout<<tmp<<" ";
		vec.push(tmp);
		cout<<vec.getMid()<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值