笔试题1


1.求一个数组的第二大的整数

int intfind_sec_max(int data[], int count)
{
	int max1;  
	int max2;   
	if (data[0]>data[1])
		max1 = data[0], max2 = data[1];
	else
		max1 = data[1], max2 = data[0];
	for (int i = 1; i<count; i++)
	{
		if (data[i] > max1)  
		{
			max2 = max1;
			max1 = data[i];
		}
		else if (data[i] > max2 && data[i] < max1)  
			max2 = data[i];
	}
	return max2;
}


2.判断一个整数n是否可以用其他k(k>=2)个连续的整数相加表示

解题思路:首先对于2^x不能表示连续的整数相加,其他的都可以,然后对于存在的情况,我们依次取最小的数为1到n/2,然后k从2开始依次遍历,直到和数列的和大于n

#include<iostream>  
using namespace std;

int IsTwo(int n)
{
	return (n&(n - 1)) == 0 ? 1 : 0;
}

int main()
{
	int num, sum = 0;
	cin >> num;
	if (IsTwo(num)) cout << "不存在" << endl;
	else {
		for (int i = 1; i <= num / 2; i++)
		{
			for (int k = 1;; k++)
			{
				sum = (k + 1) * (2 * i + k) / 2;
				if (sum > num)
					break;
				if (sum == num)
				{
					cout << num << "=";
					for (int j = 0; j < k; j++)
						cout << i + j << "+";
					cout << i + k << endl;
				}
			}

		}
	}
	return 0;
}

3.不是用浮点数计算一个整数N的开平方根最接近的整数

使用牛顿法,逼近方式为x=(x+N/x)/2

int mySqrt(int x) {
	if (x < 0) return INT_MIN;
	if (x < 2) return x;

	int ret = x / 2;
	while (ret > x / ret || x / (ret + 1) >= ret + 1) {
		ret = (ret + x / ret) / 2;
	}
	return (x-ret*ret)<((ret+1)*(ret+1)-x) ? ret:ret+1;
}

另外解法:移位法【转:http://www.cppblog.com/QUIRE-0216/archive/2008/01/23/41714.html】

本算法只采用移位、加减法、判断和循环实现,因为它不需要浮点运算,也不需要乘除运算,因此可以很方便地运用到各种芯片上去。
我们先来看看10进制下是如何手工计算开方的。
先看下面两个算式,
x = 10*p + q  (1)
公式(1)左右平方之后得:
x^2 = 100*p^2 + 20pq + q^2 (2)
现在假设我们知道x^2和p,希望求出q来,求出了q也就求出了x^2的开方x了。
我们把公式(2)改写为如下格式:
q = (x^2 - 100*p^2)/(20*p+q) (3)
这个算式左右都有q,因此无法直接计算出q来,因此手工的开方算法和手工除法算法一样有一步需要猜值。
我们来一个手工计算的例子:计算1234567890的开方
首先我们把这个数两位两位一组分开,计算出最高位为3。也就是(3)中的p,最下面一行的334为余数,也就是公式(3)中的(x^2 - 100*p^2)近似值
    3
  ---------------
 / 12 34 56 78 90
    9
  ---------------
 /  3 34

下面我们要找到一个0-9的数q使它最接近满足公式(3)。我们先把p乘以20写在334左边:
                           3  q
                         ---------------
                        / 12 34 56 78 90
                           9
                         ---------------
(20*3+q)*q      /  3 34

我们看到q为5时(60+q)*q的值最接近334,而且不超过334。于是我们得到:
      3  5
    ---------------
   / 12 34 56 78 90
      9
    ---------------
65 /  3 34
      3 25
    ---------------
         9 56


接下来就是重复上面的步骤了,这里就不再啰嗦了。

这个手工算法其实和10进制关系不大,因此我们可以很容易的把它改为二进制,改为二进制之后,公式(3)就变成了:
q = (x^2 - 4*p^2)/(4*p+q) (4)
我们来看一个例子,计算100(二进制1100100)的开方:
       1  0  1  0
      -----------
     / 1 10 01 00
       1
      -----------
 100 / 0 10 
       0 00 
      -----------
1001 /   10 01
         10 01
      -----------

          0 00


这里每一步不再是把p乘以20了,而是把p乘以4,也就是把p右移两位,而由于q的值只能为0或者1,所以我们只需要判断余数(x^2 - 4*p^2)和(4*p+1)的大小关系,如果余数大于等于(4*p+q)那么该上一个1,否则该上一个0。

下面给出完成的C语言程序,其中r表示p,rem表示每步计算之后的余数,通过(a >> (n * 2 - 2))取a的最高 2位,通过a<<=2将计算后的最高2位剔除。

#include <iostream>
#include <cmath>
using namespace std;

typedef unsigned int uint;
///四舍五入法
uint sqrt_round(uint a) {
	uint r = 0;
	int n = sizeof(a) * 8 / 2;
	uint rem = (a >> (n * 2 - 2));
	for (int i = 0; i<n + 1; i++) {
		r <<= 1;
		if (rem >= 2 * r + 1)
		{
			rem -= 2 * r + 1; 
			++r;
		}
		a <<= 2;
		rem <<= 2;
		rem += (a >> (n * 2 - 2));
	}
	return (r >> 1) + (r & 1);
}


///下取整
uint sqrt_floor(uint a) {
	uint r = 0;
	int n = sizeof(a) * 8 / 2;
	uint rem = (a >> (n * 2 - 2));
	for (int i = 0; i<n; i++) {
		r <<= 1;
		if (rem >= 2 * r + 1)
		{
			rem -= 2 * r + 1; ++r;
		}
		a <<= 2;
		rem <<= 2;
		rem += (a >> (n * 2 - 2));
	}
	return r;
}
///上取整
uint sqrt_ciel(uint a) {
	uint r = 0;
	int n = sizeof(a) * 8 / 2;
	uint rem = (a >> (n * 2 - 2));
	for (int i = 0; i<n; i++) {
		r <<= 1;
		if (rem >= 2 * r + 1)
		{
			rem -= 2 * r + 1; ++r;
		}
		a <<= 2;
		rem <<= 2;
		rem += (a >> (n * 2 - 2));
	}
	return r + (rem >0);
}













猜你喜欢

转载自blog.csdn.net/alatebloomer/article/details/80729359