剑指offer|解析和答案(C++/Python) (六)

匿名 (未验证) 提交于 2019-12-02 22:51:30

剑指offer|解析和答案(C++/Python) (六)

参考剑指offer(第二版),这里做一个学习汇总,包括解析及代码。代码均在牛客网进行验证(摘自自己的牛客网笔记)。

习题

两个面试案例
1.把字符串转换成数组
(牛客网上部分题是剑指offer的思考题,不多,下面就是那些剩下的题)
2.变态跳台阶
3.矩形覆盖

1.把字符串转换成数组

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
示例1
输入:
+2147483647
1a33
输出:
2147483647
0

思路:
这题本身不难,不够需要注意许多细节。
特殊用例的测试:
1.空指针
2.空字符串""
3.正负号
4.溢出

这里着重讲一下正负数溢出。
参考:
https://zhidao.baidu.com/question/194668811.html
https://zhidao.baidu.com/question/2052829228594311827.html

  • A.负数溢出

这里对应的测数数据为"-2147483649",正确的输出为:0,但很有可能造成错误输出:2147483647。这因为32位的int数据范围是 -2147483648 ―― 2147483647
-2147483649 可以看成 -2147483648 + (-1) 。(补充:计算机中数字全部是以补码的形式进行存储)。
-2147483648的原码是:0x80000000,反码是0xFFFFFFFF,补码是0x80000000。
举例理解:-8的补码。
(1)如果用4位二进制数表示的话,原码1000(“1”表示“-”号,“000”可以看成数字位“111”+1的结果)――反码1111――补码1000。
(2)如果用8位二进制数表示的话,原码1000 1000――反码1111 0111――补码1111 1000。
这也是为什么**-2147483648**补码是0x80000000而不是0x180000000的原因,数字被限定用32位int型数据表示。
-1的原码是0x80000001,反码是0xFFFFFFFE,补码是0xFFFFFFFF。
所以2147483649=2147483648+(1)-2147483649 = -2147483648 + (-1)Ϊ 0x80000000 + 0xFFFFFFFF =0x7FFFFFFF(补码相加),而0x7FFFFFFF又等于2147483647,这就是负数溢出,造成错误的原因。
如何判断负数溢出:首先判断负数标志位,接着判断最高位是否为0(因为产生了进位)

B.正数溢出
正数溢出和负数溢出类似,正数的最大值为2147483647,输入测试数据2147483648,正确的输出为0,但很容易造成错误输出:-2147483648
一样的分析,2147483648 = 2147483647 + 1
2147483647 原码=反码=补码=0x7FFFFFFF,1的原码=反码=补码=0x00000001。
2147483647 + 1为0x7FFFFFFF + 0x00000001 = 0x80000000,而0x80000000是**-2147483648**的补码,这就是造成错误的原因。
如何判断正数溢出:首先判断正数标志位,接着判断最高位是否为1(因为产生了进位)
代码:
C++

class Solution { public: 	enum Status{kValid = 0, kInvalid}; 	int g_nStatus = kValid;     int StrToInt(string str) {         g_nStatus = kInvalid; 		long long num = 0; 		//str.size() 获取str长度 不包括\0 		if(str.size() > 0){ 			bool minus = false;//负数的标志 			if(str[0] == '+'){ 				str = str.substr(1);//截断字符串 			}else if(str[0] == '-'){ 				str = str.substr(1);//截断字符串 				minus = true; 			} 			if(str.size() > 0 && str[0] != '\0'){ 				num = StrToIntCore(str, minus); 			} 		} 		return (int)num;     } 	int StrToIntCore(string str, bool minus){ 		int num = 0; 		int length = str.size(); 		for(int i = 0; i < length; ++i){ 			if(str[i] <= '9' && str[i] >= '0'){//合法的输入 				int flag = minus? -1:1;//正负数 				cout<<"str[i]:"<<str[i]<<endl; 				num = num*10 + flag*(str[i] - '0'); 				cout<<"num:"<<num<<endl; 				if((!minus&&((num>>31)&0x1) == 1)||//正数溢出 				(minus&&((num>>31)&0x1) == 0)){//负数溢出 				    cout<<"error"<<endl; 					num = 0; 					break; 				} 			}else{//非法输入 				num = 0; 				break; 			} 		} 		return num; 	} }; 

Python

# -*- coding:utf-8 -*- class Solution:     def StrToInt(self, s):         # write code here         length = len(s)         num = 0         if length > 0:             minus = False             if s[0] == '+':                 s = s[1:]#截断             elif s[0] == '-':                 minus = True#负数                 s = s[1:]             if len(s) > 0:                 num = self.StrToIntCore(s, minus)                  return num          def StrToIntCore(self, s, minus):         length = len(s)         num = 0         for i in range(length):             if s[i] >= '0' and s[i] <= '9':                 if minus == True:                     flag = -1                 else:                     flag = 1                 num = num*10 + flag*(int)(s[i])                 #判断是否溢出                 if (minus == False and ((num>>31)&0x1) == 1) or \                     (minus == True and ((num>>31)&0x1) == 0):                     num = 0                     break             else:                 num = 0                 break                  return num 

2.变态跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

思路:
1.递归求解。分析递归条件,我们用f(i)f(i)表示青蛙跳i层台阶存在的跳法。
可以得出条件:
f(1)=1f(1)=1
f(2)=2f(2)=2
f(i)=f(i1)+f(i2)++f(2)+f(1)+1f(i)=f(i-1)+f(i-2)+\ldots+f(2)+f(1)+1
2.循环:自底向上。根据递归公式得到递推公式:
f(i)=f(i1)+f(i2)++f(2)+f(1)+1f(i)=f(i-1)+f(i-2)+\ldots+f(2)+f(1)+1
f(i1)=f(i2)++f(2)+f(1)+1f(i-1)=f(i-2)+\ldots+f(2)+f(1)+1
f(i)f(i1)=f(i1)f(i)-f(i-1)=f(i-1)
f(i)=2×f(i1)f(i)=2 \times f(i-1)
f(i)=2i1f(i)=2^{i-1}
于是可以使用循环操作,效率更高。
代码:
C++

class Solution { public:     int jumpFloorII(int number) { 		int jumpFloor = 1; 		for(int i = 0; i < number - 1; ++i) 			jumpFloor *= 2; 		return jumpFloor;     } }; 

Python

# -*- coding:utf-8 -*- class Solution:     def jumpFloorII(self, number):         # write code here         jumpFloor = 1         for i in range(1, number):             jumpFloor *= 2         return jumpFloor 

3.矩形覆盖

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

思路:
把2n有多少中覆盖方法记为f(n)f(n)。用第一个21的小矩形去覆盖大矩形的最左边时有两种选择:竖着放或横着放。
当竖着放的时候,右边还剩下2*(n - 1)的区域,这种情形下,覆盖种类有f(n1)f(n-1)
当横着放的时候,右边还剩下2*(n - 2)的区域,这种情形下,覆盖种类有f(n2)f(n-2)
此时f(n)=f(n1)+f(n2)f(n)=f(n-1)+f(n-2)。其实就是斐波拉契数列。
参考图示:

代码:
C++

class Solution { public:     int rectCover(int number) { 		if(number < 3) 			return number; 		int rectOne = 2; 		int rectTwo = 1; 		int rectNums; 		for(int i = 3; i <= number; ++i){ 			rectNums = rectOne + rectTwo; 			rectTwo = rectOne; 			rectOne = rectNums; 		} 		return rectNums;     } }; 

Python

# -*- coding:utf-8 -*- class Solution:     def rectCover(self, number):         # write code here         if number < 3:             return number         rectOne = 2         rectTwo = 1         for i in range(3, number + 1):             rectNums = rectOne + rectTwo             rectTwo = rectOne             rectOne = rectNums                      return rectNums 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!