《剑指Offer》题六十一~题六十八

六十一、扑克牌中的顺子

题目:从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王可以看成任意数字。

 

六十二、圆圈中最后剩下的数字

题目:0, 1, …, n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

 

六十三、股票的最大利润

题目:假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?例如,一只股票在某些时间节点的价格为{9, 11, 8, 5, 7, 12, 16, 14}。如果我们能在价格为5的时候买入并在价格为16时卖出,则能收获最大的利润11。

 

六十四、求1+2+…+n

题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

提示:这道题本身没什么实际意义,但不少面试官认为这是一道考查应聘者发散思维能力的题目。

分析:循环只是让相同的代码重复执行n遍而已,我们可以不用for和while来达到这个效果。比如我们先定义一个类型,接着创建n个该类型的实例,那么这个类型的构造函数将会被调用n次。

利用构造函数求解:

class Temp {
public:
	Temp()
	{
		N++;
		SUM += N;
	}
	static void reset() 
	{
		N = 0;
		SUM = 0;
	}
	static unsigned int getSum()
	{
		return SUM;
	}
	
private:
	static unsigned int N;
	static unsigned int SUM;
};

unsigned int sum_one_to_n(unsigned int n)
{
	Temp::reset();
	
	Temp *arr = new Temp[n];
	delete []arr;
	arr = nullptr;
	
	return Temp::getSum;
}

 

六十五、不用加减乘除做加法

题目:写一个函数,求两个整数之和,要求在函数体内不得使用“+”、“-”、“×”、“÷”四则运算符号。

提示:对数字做运算,除四则运算之外,也就只剩下位运算了。

分析:二进制加法和十进制加法的过程一样,都是①各位相加不进位,②记下进位,③把前两步的结果相加。对于二进制加法来说,第一步的结果和异或的结果是一样的,第二步的结果等价于两个数先做位与运算,然后再向左移动一位,第三步把前两个步骤的结果相加,过程依然是重复前面两步。

位运算解法:

int add_with_bit(int num1, int num2)
{
	int sum = 0;
	int carry = 0;
	do {
		// 第一步 
		sum = num1 ^ num2;
		// 第二步 
		carry = (num1 & num2) << 1;
		// 第三步 
		num1 = sum;
		num2 = carry;
	} while(num2 != 0);
	
	return sum; 
}

 

六十六、构建乘积数组

题目:给定一个数组A[0, 1, …, n-1],请构建一个数组B[0, 1, …, n-1],其中B中的元素B[i] = A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。

 

六十七、把字符串转换成整数

题目:写一个函数StrToInt,实现把字符串转换成整数这个功能。要求不能使用atoi或者其他类似的库函数。

没有考虑非法输入的解法:

int StrToInt(char *pStr)
{
	if(pStr == nullptr)	return -1;
	int num = 0;
	char *pCur = pStr;
	while(*pCur != '\0') {
		num = num * 10 + *pCur - '0';
		pCur++;
	}
	return num;
}

分析:上述解法虽简洁,但也遗漏了许多检错点。比如,①当输入的字符串为空串或输入的字符串是"0"时,该函数都返回0;②'+'和'-'字符是合法的输入符,而其他字符是非法字符;③当输入的字符串只含"+"和"-"时,虽然它们是合法字符,但该字符串却不合法。

完善后的代码:

int StrToInt(char *pStr)
{
	error = 0;
	if(pStr == nullptr) {
		return 0;
		error = 1;
	}
	if(*pStr == '\0') {
		return 0;
		error = 2;
	}
	int plus = 0;
	int minus = 0;
	if(*pStr == '+') {
		plus = 1;
		pStr++;
	}
	if(*pStr == '-') {
		minus = 1;
		pStr++;
	}
	int num = 0;
	while(*pStr != '\0') {
		if(*pStr > '9' || *pStr < '0') {
			return 0;
			error = 3;
		}
		num = num * 10 + *pStr - '0';
		pStr++;
	}
	if(minus == 1) {
		num *= -1;
	}
	if(num == 0)
		error = 4;	
	return num;
}

  

  

 

六十八、树中两个节点的最低公共祖先

题目:输入两个树节点,求它们的最低公共祖先。(1)若该树是二叉搜索树;(2)若该树只是普通的树,但树中的节点中有指向父节点的指针;(3)若该树只是普通的树,而且树中的节点没有指向父节点的指针。

 

posted @ 2018-08-29 08:18  GGBeng  阅读(205)  评论(0编辑  收藏  举报