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
下面给出完成的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); }