注意!
边界情况的考虑
函数命名、变量命名要有逻辑。最好用完整的英文单词组合命名变量和函数
选择合适的数据结构:数组、链表、树
1、从3个方面确保代码的完整性:功能测试+边界测试+负面测试
2、功能测试:突破常规思维,考虑隐形的限制条件,如整型int的最大值的限制
3、边界测试:递归、循环的退出条件
4、负面测试:一些可能的错误输入,输入之后要怎么判断,怎么作出反应。有三种错误处理方式:返回值、全局变量(专门用一个值来记录是否出错)、异常抛出try-catch
题目
数值的整数次方
实现函数double Power(double base,int exponent)
,求base的exponent次方,不得使用库函数,同时不需要考虑大数的问题
思路
全面但不高效的代码
1、只考虑指数为正数的情况,那么这道题就很简单了
2、考虑指数为负数的情况,如果指数是负数,那么结果就应该是base的exponent 的绝对值次方的倒数。
3、考虑了上面之后又要考虑特殊的情况了,想到求倒数,那0呢?对0求倒数?这不允许。其实0的0次方是没有意义的,以前学的时候是说任何数的0次方都等于1,但是如果base是0,但指数不是呢?
bool g_InvalidInput = false;//全局变量,用于判断是否有错误输入,即0的负数次幂
double Power(double base, int exponent)
{
g_InvalidInput = false;
//如果底数是0,指数还是负数,这是不允许的
//所以要用全局变量提示出错了,那在调用的函数中就要对全局变量进行判断
if (base < 0.00000001 && exponent < 0) {//double类型的比较只能用近似值
g_InvalidInput = true;
return 0.0;
}
unsigned int absExponent = (unsigned int)(exponent); //求绝对值
if (exponent < 0)
absExponent = (unsigned int)(-exponent);
double result = PowerWithUnsignedExponent(base, absExponent);
if (exponent < 0)
return 1.0 / result;
return result;
}
double PowerWithUnsignedExponent(double base, unsigned int absExponent)
{
double result = 1.0;
for (int i = 0; i < absExponent; i++)
result *= base;
return result;
}
既全面又高效的解法
如果输入的指数是32,则在函数要进行32次循环乘法。如果我们已经直到底数的16次方,那么我们只要在这个基础上再计算一次平方就可以了。而16次方又是8次方的平方,8次方又是4次方的平方,4次方又是 2次方的平方。如此下来计算32次方,只要做5次乘方就可以了。
当n为偶数时, an=an/2.an/2 a n = a n / 2 . a n / 2 ;当n为奇数时, an=an−1/2.an−1/2.a a n = a n − 1 / 2 . a n − 1 / 2 . a
以下用位运算代替除法和判断是否为奇数,提高了效率
double PowerWithUnsignedExponent(double base, unsigned int absExponent)
{
if (absExponent == 0)
return 1.0;
if (absExponent == 1)
return base;
double result = PowerWithUnsignedExponent(base, absExponent >> 1);//!!!!!>>除以2
result *= result;
if (absExponent & 0x1 == 1) //与1相与,判断是不是奇数!!!!!
result *= base;
return result;
}
打印从1最大的n位数(看似简单其实一点也不简单的题)
输入数字n,按顺序打印出从1到最大的n位十进制数,比如输入3,则打印出1,2,3,……,999
思路
注意大数据,这是一个大数问题====》大数神器——字符串
在字符串上模拟数字加法
1、在字符串表达的数字上模拟加法
2、把字符串表达的数字打印出来
#include<algorithm>
#include<iostream>
using std::cout;
//打印从1到最大的n位数
void Print1ToMaxOfNDigits(int n)
{ //负面情况
if (n <= 0)
return;
char* number = new char[n + 1];//因为n位长的数字的字符串其实长度应该为n+1,最后一位是'\0'
memset(number, '0', n);//为number数组的元素清0
number[n] = '\0';
while (Increment(number))
PrintNumber(number);
delete[] number;
}
//功能1:判断是否到了最大的n位数:n个9
//功能2:得到下一个数,+1
bool Increment(char* number)
{
bool isOverflow = false;
int nTakeOver = 0;//进位标志
int nLength = strlen(number);
for (int i = nLength-1; i >=0; i--)
{ //number[i] - '0':找到当前位置对应的int值
//比如说百位数上是'5',那下一位i-1就没有进位了
int nSum = number[i] - '0' + nTakeOver;
//个位数上加1,其他位就是看有没有进位了
if (i == nLength - 1)
nSum++;
if (nSum >= 10) {
if (i == 0)
//只有达到最大的n位数才会在第0位上有进位
isOverflow = true;//已经到达最大的n位数了
else {
nSum -= 10;
//在当前的i对下一个位有进位,但是下下一个位也有进位吗?就是用完一次进位之后它并没有还原为0啊
//上面这个逻辑是错的,它是一直进位直到碰到不需要进位的就break,退出此次的循环了。
//比如199,在第一个9+1=10>=10之后,就有一个进位,之后进入下一个循环;
//下一位依然是9-0+1=10>=10,还是有进位,下一个循环;1-0+1=2<10所以没有进位了,直接break,后面的高位的数就不用改变了
nTakeOver = 1;
number[i] = '0' + nSum;
}
}
else {
number[i] = '0' + nSum;
break;//到了这一步,高位的数就和上一个数一样,可以退出了
}
}
return isOverflow;
}
//每生成一个数就打印一个数,为什么不能直接打印?
//因为在生成数的时候,我们在数的前面补了'0'字符。
//打印的时候我们希望能按照我们的阅读习惯打印出来
void PrintNumber(char* number)
{
bool isBegining0 = true;
int nLength = strlen(number);
for(int i=0;i<nLength;i++){
if (isBegining0&&number[i] != '0')
isBegining0 = false;
if (!isBegining0)
cout << number[i];
}
cout << "\t";
}
把问题转换成数字排列的解法,递归
//每生成一个数就打印一个数,为什么不能直接打印?
//因为在生成数的时候,我们在数的前面补了'0'字符。
//打印的时候我们希望能按照我们的阅读习惯打印出来
void PrintNumber(char* number)
{
bool isBegining0 = true;
int nLength = strlen(number);
for(int i=0;i<nLength;i++){
if (isBegining0&&number[i] != '0')
isBegining0 = false;
if (!isBegining0)
cout << number[i];
}
cout << "\t";
}
//使用递归:0到9的n个全排列
void Print1ToMaxOfDigitsWithRec(int n)
{
if (n <= 0)
return;
char* number = new char[n + 1];
number[n] = '\0';
//最高位第0位开始触发
for (int i = 0; i < 10; i++) {
numb'aer[0] = i + '0';//使用ASCII
PrintToMaxOfDigitsRecursively(number, n, 0);
}
}
void PrintToMaxOfDigitsRecursively(char* number, int length, int index)
{
if (index == length - 1) {
PrintNumber(number);//循环到最后一个数了,生成数完成
return;
}
for (int i = 0; i < 10; i++) {
number[index + 1] = i + '0';
PrintToMaxOfDigitsRecursively(number, length, index + 1);
}
}
如果面试题是关于n位的整数,并且没有限定n的取值范围,或者输入任意大小的整数,那么这道题很可能需要考虑大数的问题。字符串是大数最好的朋友