2011.10.17百度面试题

2011.10.17百度面试题

1. 进程切换需要注意哪些问题?
答: 

保存处理器PC寄存器的值到被中止进程的私有堆栈;   保存处理器PSW寄存器的值到被中止进程的私有堆栈;    保存处理器SP寄存器的值到被中止进程的进程控制块;

保存处理器其他寄存器的值到被中止进程的私有堆栈;     自待运行进程的进程控制块取SP值并存入处理器的寄存器SP;    自待运行进程的私有堆栈恢复处理器各寄存器的值;

自待运行进程的私有堆栈中弹出PSW值并送入处理器的PSW;     自待运行进程的私有堆栈中弹出PC值并送入处理器的PC。


2. 输入一个升序数组,然后在数组中快速寻找两个数字,其和等于一个给定的值.

答:

如果我们不考虑时间复杂度,最简单想法的莫过去先在数组中固定一个数字,再依次判断数组中剩下的n-1个数字与它的和是不是等于输入的数字。可惜这种思路需要的时间复杂度是O(n2)

我们假设现在随便在数组中找到两个数。如果它们的和等于输入的数字,那太好了,我们找到了要找的两个数字;如果小于输入的数字呢?我们希望两个数字的和再大一点。由于数组已经排好序了,我们是不是可以把较小的数字的往后面移动一个数字?因为排在后面的数字要大一些,那么两个数字的和也要大一些,就有可能等于输入的数字了;同样,当两个数字的和大于输入的数字的时候,我们把较大的数字往前移动,因为排在数组前面的数字要小一些,它们的和就有可能等于输入的数字了。

我们把前面的思路整理一下:最初我们找到数组的第一个数字和最后一个数字。当两个数字的和大于输入的数字时,把较大的数字往前移动;当两个数字的和小于数字时,把较小的数字往后移动;当相等时,打完收工。这样扫描的顺序是从数组的两端向数组的中间扫描。

问题是这样的思路是不是正确的呢?这需要严格的数学证明。感兴趣的读者可以自行证明一下。

关键代码片段如下:

bool FindTwoNumbersWithSum
(
      int data[],           // a sorted array
      unsigned int length,  // the length of the sorted array     
      int sum,              // the sum
      int& num1,            // the first number, output
      int& num2             // the second number, output
)
{

      bool found = false;
      if(length < 1)
            return found;

      int ahead = length - 1;
      int behind = 0;

      while(ahead > behind)
      {
            long long curSum = data[ahead] + data[behind];

            // if the sum of two numbers is equal to the input
            // we have found them
            if(curSum == sum)
            {
                  num1 = data[behind];
                  num2 = data[ahead];
                  found = true;
                  break;
            }
            // if the sum of two numbers is greater than the input
            // decrease the greater number
            else if(curSum > sum)
                  ahead --;
            // if the sum of two numbers is less than the input
            // increase the less number
            else
                  behind ++;
      }

      return found;
}

3、有一个名人和很多平民在一块,平民都认识这个名人,但是这个名人不认识任何一个平民,任意两个平民之间是否认识是未知的,请设计一个算法,快速找个这个人中的那个名人。  已知已经实现了一个函数  bool know(int a,int b) 这个函数返回true的时候,表明a认识b,返回false的时候表明a不认识b。

思路:首先将n个人分为n/2组,每一组有2个人,然后每个组的两个人调用这个know函数,假设为know(a,b),返回true的时候说明a认识b,则a肯定不是名人,a可以排除掉了,依次类推,每个组都调用这个函数依次,那么n个人中就有n/2个人被排除掉了,数据规模将为n/2。同理在剩下的n/2个人中在使用这个方法,那么规模就会将为n/4,这样所有的遍历次数为n/2+n/4+n/8+........ 这个一个等比数列,时间复杂度为o(n)。


4、有一类数组,例如书序[1,2,3,4,6,8,9,4,8,11,18,19,100] 前半部分是是一个递增数组,后面一个还是递增数组,但整个数组不是递增数组,那么怎么最快的找出其中一个数?

思路: 先找到那个分割数字(该数字前后都是递增数组),然后判断指定的数字位于分割前还是后的数组.

代码如下:

#include <iostream>
using namespace std;

int binary_search(int* a, int low, int high, int goal)    //二分查找
{
	while(low <= high)
	{
		int middle = (low+high)>>1;    //(low+high)/2
		if(a[middle] == goal)
			return middle;
		//在右半边
		else if(a[middle] < goal)
			low = middle + 1;
		//在左半边
		else
			high = middle - 1;
	}
	return -1;
}
void getNum(int *a, int len, int goal)
{
	int i, index;
	for(i = 0; i < len-1; i++)
	{
		if(a[i] > a[i+1])     //找到前、后两个数组的分界点
			break;
	}
	if(a[i] >= goal)          //对前面数组进行二分查找
	{
		index = binary_search(a, 0, i, goal);
		printf("%d\n",index);
	}
	if(a[i+1] <= goal)         //对后面数组进行二分查找
	{
		index = binary_search(a+i+1, 0, len-i-2, goal);
		if(index != -1)
			index += (i+1);    //后面的那个数组相对于前面数组的偏移量为i+1
		printf("%d\n",index);
	}
}

int main(void)
{
	int a[]={1,2,3,4,6,8,9,4,8,11,18,19,100};
	int len = 13, goal = 4;
	getNum(a,len,goal);
	return 0;
}

5. 判断一个自然数是否是某个数的平方,当然不能使用开方运算.

思路:
方法1:

遍历从1到N的数字,求取平方和并和N进行比较.如果平方小于N,则继续遍历;如果等于N,则成功退出;如果大于N,则失败退出.

复杂度为O(n^0.5).

方法2:

使用二分查找法,对1到N之间的数字进行判断,复杂度为O(log n).

方法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中的乘法,所以速度会更快些。
例如:3^2 = 9 = 1 + 2*1+1 + 2*2+1 = 1 + 3 + 5
4^2 = 16 = 1 + 2*1 + 1 + 2*2+1  + 2*3+1

int square(int n)

{
	int i = 1;
	n = n - i;
	while( n > 0 )
	{
		i += 2;
		n -= i;
	}
	if( n == 0 )        //是某个数的平方
		return 1;
	else                //不是某个数的平方
		return 0;
}


参考资料:http://blog.csdn.net/hackbuteer1/article/details/6878627

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值