【剑指offer】day15
不用加减乘除做加法
题目要求
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
例子:
1 | 输入: a = 1, b = 1 |
提示:
a
,b
均可能是负数或 0- 结果不会溢出 32 位整数
思路分析
位运算
进位和n
与进位c
的计算公式如下:
-
非进位和(异或运算)公式:
n = a^b;
-
进位(与运算+左移一位):
c = a&b<<1;
-
s = a+b -> n+c;
循环求n和c,直到c=0,返回n即可;(此时s=n)
代码实现
1 | class Solution { |
构建乘积数组
题目要求
给定一个数组 A[0,1,…,n-1]
,请构建一个数组 B[0,1,…,n-1]
,其中 B[i]
的值是数组 A
中除了下标 i
以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]
。不能使用除法。
例子:
1 | 输入: [1,2,3,4,5] |
提示:
- 所有元素乘积之和不会溢出 32 位整数
a.length <= 100000
思路分析
该题不能使用除法
根据例子,列出下图:
- 初始化数组b,b[0] = 1,辅助变量temp,初始值temp=1;
- 计算上图中,b[i]的下三角个元素乘积,乘积入b[i];
- 计算上图中,b[i]的上三角个元素乘积,先使用temp记录,然后乘积入b[i];
- 将数组b返回;
代码实现
1 | class Solution { |
把字符串转换成整数
题目要求
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
提示:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
例子1:
1 | 输入: "42" |
例子2:
1 | 输入: " -42" |
例子3:
1 | 输入: "4193 with words" |
例子4:
1 | 输入: "words and 987" |
例子5:
1 | 输入: "-91283472332" |
思路分析
字符情况处理
- 首位空格:删除即可;
- 符号位:+,-和无符号三种情况,新建变量保存,返回之前判断正负;
- 非数字字符:遇到首个非数字字符,直接返回;
- 数字字符:
- 字符转数字:该数字的ASCII码与数字0的ASCII码相减即可;
- 数字拼接:从左向右遍历,假定当前字符为
c
,当前数字为x
,结果为res
,则拼接公式:res = 10 * res + x; x = ascii(c) - ascii('0');
- 数字越界问题:在每轮数字拼接前,判断
res
在该轮拼接后是否超过 214748364721474836472147483647 ,若超过则加上符号位直接返回;
代码实现
1 | class Solution { |
二叉搜索树的最近公共祖先
题目要求
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
例子:
1 | 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 |
提示:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉搜索树中。
思路分析
二叉搜索树的左子树一定小于根节点,右子树一定大于根节点
- p>root,q>root,那么p和q一定在右子树;
- p<root,q<root,那么p和q一定在右子树;
代码实现
1 | /** |
二叉树的最近公共祖先
题目要求
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
例子:
1 | 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 |
提示:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉树中。
思路分析
递归
我们递归遍历整棵二叉树,定义 表示节点的子树中是否包含p
节点或q
节点,如果包含为 true,否则为 false;
那么一定满足关系式:( && ) || ((x = p || x = q) && ( || ));
其中l
和r
分别代表x
的左右子节点;
代码实现
1 | /** |