概览
剑指offer:不用加减乘除做加法、构建乘积数组、把字符串转换成整数、二叉搜索树的最近公共祖先、二叉树的最近公共祖先
剑指offer
1.70 不用加减乘除做加法
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
解:
观察发现,无进位和 与 异或运算 规律相同,进位 和 与运算 规律相同(并需左移一位)。
//位运算
class Solution {
public int add(int a, int b) {
while(b != 0){ // 当进位为 0 时跳出
int carry = (a & b) << 1; //进位
a ^= b; //非进位和加
b = carry;
}
return a;
}
}
1.71 构建乘积数组
给定一个数组 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,2,3,4,5]
输出: [120,60,40,30,24]
// 表格法
class Solution {
public int[] constructArr(int[] a) {
if(a.length == 0) return new int[0];
int[] b = new int[a.length];
b[0] = 1;
int temp = 1;
// 计算b:b[i]表示a[0...i-1]的乘积
for(int i=1; i<a.length; i++){
b[i] = b[i-1] * a[i-1];
}
// temp 表示a[i...n-1]的乘积
for(int i=a.length-1; i>=0; i--){
b[i] *= temp;
temp *= a[i];
}
return b;
}
}
1.72 把字符串转换成整数
写一个函数 StrToInt,实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
class Solution {
public int strToInt(String str) {
//去除str首尾的多余空格
char[] array = str.trim().toCharArray();
//如果array的长度为0 返回0
if (array.length==0) return 0;
//sign表示标志位 1为正 -1 为负 i代表array从何处开始遍历
int res = 0, sign = 1, i = 1;
//设置限制值,因为在遍历中先判断res是否越界,再向res赋值,因而对limit的要求/10
int limit = Integer.MAX_VALUE / 10;
//如果array[0]=- 表明该数是负数 sign =-1
if (array[0]=='-') sign = -1;
else if (array[0]!='+') i = 0;
for (int j = i; j < array.length; j++) {
//判断当前字符是否为数字 不是直接退出
if (array[j]>'9'||array[j]<'0') break;
//判断遍历到j-1的位置后 res是否大于limit 如果当前res已经大于limit 加上array[j]一定越界
//当res等于limit时,我们需要判断array[j]是否大于Integer.MAX_VALUE的末位数7
if (res>limit||res==limit&&array[j]>'7') return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
res = res * 10 + (array[j] - '0');
}
return res*sign;
}
}
1.73 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
//迭代
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
while(root != null) {
if(root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
root = root.right; // 遍历至右子节点
else if(root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
root = root.left; // 遍历至左子节点
else break;
}
return root;
}
}
//递归
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right, p, q);
if(root.val > p.val && root.val > q.val)
return lowestCommonAncestor(root.left, p, q);
return root;
}
}
1.74 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
//DFS
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
//左右子树同时为null,root左右子树均不包含p,q,返回null
if(left == null && right == null) return null;
//左为空,右不为空,p,q不在左子树中,返回right,分为两种情况:
//p,q 其中一个在root的右子树中,此时right指向p(假设为p);
//p,q 两节点都在root的右子树中,此时的right指向最近公共祖先节点 ;
if(left == null) return right;
//左不为空,右为空,p,q不在右子树中,返回left
if(right == null) return left;
return root; //if(left != null and right != null)
}
}
年度总结
- Java和Android的基础知识点基本整理完了(当然还有很多遗漏的),来年会先复习计算机基础知识,然后收集整理面经查漏补缺,再学习常见框架(源码),熟悉项目。
- 算法已经基本刷完《剑指offer》的题,来年继续LeetCode100热题,最后进行模板总结。
- 今天是2022年1月31日,除夕。回顾这一年,我遇到了一个真心爱我的人,遇到了许多好老师,做了一个外包的项目,参加了互联网比赛,也收获了一份较为满意的成绩…
来年三月,我将正式进行春招,在前行中跌倒,又站起来继续前行~
我本平凡,仅因对互联网的热爱,让我踏上这一条路,相信明年将会更好,未来可期,新年快乐~