LeetCode剑指offer记录

leetcode剑指offer66题笔记

  • 个人刷题的一些笔记
    • 面试题3数组中的重复数字
    • 面试题4二维数组中的查找
    • 面试题5替换空格
    • 面试题6从尾到头打印链表
    • 面试题7重建二叉树
    • 面试题8二叉树下一个节点
    • 面试题9两个栈模拟队列
    • 面试题10
      • 斐波那契数列
      • 青蛙跳台阶
    • 面试题11旋转数组的最小数字
    • 面试题12矩阵中路径
    • 面试题13机器人的运动范围
    • 面试题14剪绳子
      • dp
      • 贪婪
    • 面试题15二进制中1的个数
      • 相似扩展
    • 面试题16数值的整数次方
    • 面试题17打印从1到最大的n位数
    • 面试题18删除链表的节点
    • 面试题19正则表达式匹配
    • 面试题20表示数值的字符串
    • 面试题21调整数组顺序使奇数位于偶数前面
    • 面试题22链表中倒数第K个节点
    • 面试题23链表中环的入口节点
    • 面试题24反转链表
    • 面试题25合并两个有序链表
    • 面试题26树的子结构
    • 面试题27二叉树的镜像
    • 面试题28对称的二叉树
    • 面试题29顺时针打印矩阵
    • 面试题30包含min函数的栈
    • 面试题31栈的压入弹出序列
    • 面试题32从上到下打印二叉树
      • 32-1
      • 32-2
      • 32-3
    • 面试题33二叉搜索树的后序遍历序列
      • 法1
      • 法2
    • 面试题34二叉树中和为某一值的路径
    • 面试题35复杂链表的复制
    • 面试题36二叉搜索树与双向链表
    • 面试题37序列化二叉树
    • 面试题38字符串的排列
    • 面试题39数组中出现次数超过一半的数字
    • 面试题40最小的K个数
    • 面试题41数据流的中位数
    • 面试题42连续子数组的最大和
    • 面试题43 1~n的整数中出现1的次数
    • 面试题44 数字序列中某一位的数字
    • 面试题45把数组排成最小的数
    • 面试题46把数字翻译成字符串
    • 面试题47礼物的最大价值
    • 面试题48最长不含重复字符的子字符串
    • 面试题49丑数
    • 面试题50第一个只出现一次的字符
    • 面试题51数组中的逆序对
    • 面试题52两个链表的第一个公共节点
    • 面试题53在排序数组中查找数字
      • 53-1
      • 53-2
    • 面试题54二叉搜索树的第k大节点
    • 面试题55二叉树的深度
      • 55-1
      • 55-2
    • 面试题56数组中数字出现的次数
      • 56-1
      • 56-2
    • 面试题57和为s的两个数字
      • 57-1
      • 57-2
    • 面试题58反转字符串
      • 58-1
      • 58-2
    • 面试题59队列的最大值
      • 59-1
      • 59-2
    • 面试题60n个骰子的点数
    • 面试题61扑克牌中的顺子
    • 面试题62圆圈中最后剩下的数字
    • 面试题63股票的最大利润
    • 面试题64 1+2+。。。。。。+n
    • 面试题65不用加减乘除做加法
    • 面试题66构建乘积数组
    • 面试题67把字符串转换为整数
    • 面试题68树中两个节点的最低公共祖先
      • 68-1
      • 68-2

个人刷题的一些笔记

面试题3数组中的重复数字

  1. 排序后遍历,判断是否重复,时间复杂度O(nlogn)
  2. 借助hash表,判断元素是否已在其中,时间复杂度O(n),空间复杂度O(n)
  3. 尝试把元素摆放到正确的位置使nums[i]=i,如果不等交换nums[i]与nums[nums[i]],一旦两者相等,则为重复元素,时间复杂度O(n),空间复杂度O(1)
  4. 二分思想,遍历统计mid值左右元素个数是否大于一半,进而缩小区间查找,时间复杂度o(nlogn),空间复杂度o(1),不改变原数组。

面试题4二维数组中的查找

  1. 利用矩阵值的性质,从右上角或者左下角开始,根据矩阵元素与目标值的大小关系逐渐逼近。如从左下角开始时,如果矩阵元素大于目标值,往上一行搜索;小于目标值,往下一列搜索。

面试题5替换空格

  1. 直接计算出变更后字符串长度,从尾到头移动元素。
  2. python中的str不允许直接下标修改值,需要转换为list处理,同时python内置操作可以str直接用replace操作完成。

面试题6从尾到头打印链表

  1. 用栈结构处理
  2. 递归,输出本节点之前先输出下一个节点

面试题7重建二叉树

  1. 根据中序和先序遍历特点划分利用先序遍历寻找根节点再在中序遍历中划分属于左右子树的节点,递归建立二叉树。
  2. 迭代思想,先序遍历中从当前节点到中序遍历当前节点在先序中位置的部份都是当前节点的左子树,相等的话则当前的先序遍历节点为之前的逆先序遍历与中序遍历最后相等的节点的右子树。可以用栈模拟过程,遍历先序遍历,利用一个index访问中序。

面试题8二叉树下一个节点

  1. 该节点有右子树,则下一个节点为右子树中最左子树节点
  2. 如果没有,则往上搜索,第一个是左儿子节点的节点的父节点就是要找的下一个节点

面试题9两个栈模拟队列

  1. 一个栈模拟压入元素,一个栈模拟弹出元素,弹出元素的那个栈由压入的元素的栈pop顺序压入元素

面试题10

斐波那契数列

  1. 根据递推公式,简单的dp问题

青蛙跳台阶

  1. 可看做f(0) = 1的斐波那契问题

面试题11旋转数组的最小数字

按照二分查找的思想进行,但是边界指针移动略有不同,保证旋转点在l与r之间

  1. mid > r时,l = mid + 1
  2. mid > r时,r = mid(mid可能就是需要寻找的点,不能r= mid -1)
  3. mid = r时,r -= 1(分mid在左数组和右数组考虑,详情见leetcode大佬题解)
    面试题11leetcode题解.

面试题12矩阵中路径

  1. dfs搜索即可,记录当前board访问情况以及word中当前比较的字母

面试题13机器人的运动范围

  1. 同上dfs搜索即可,但是判断条件多了一个k而且需要记录一下可达格子数(在dfs中作为返回值传递)

面试题14剪绳子

dp

递推式dp[i] = max(dp[j]*dp[i-j])

贪婪

n>=5时,剪成长度为3的小段是最优的,所以尽可能切分3长度即可,n=4时,切成2即可。

面试题15二进制中1的个数

  1. n&n-1的位运算会消掉n最右边的1,while循环到n为0时,位运算次数就是n的二进制中1个个数。
  2. 直接移位逐位判断的话,负数输入会引起死循环。

相似扩展

  • 判断一个数是不是2的整数次方,n&n-1为0,因为满足条件的数二进制只会有一个1
  • 两个整数m和n,怎么变化m二进制得到n,统计异或后的1的个数。

面试题16数值的整数次方

  • 注意负指数以及0基数
  • 可以用二分思想以及位运算优化速度

面试题17打印从1到最大的n位数

该题想考察的点是用字符串(数组)模拟数字自加,进位的情况,同时也需要我们改写输出函数完成要求的输出格式(过滤数字左边多余的0)
1.首先用n+1位数组存储数字,初始化全为0,当自加到最高位为1时停止循环。
2.循环内部不断自加1且判断进位操作
3.每次自加完后调用输出函数,从左往右第一个不为0的元素开始整合成一个整数输出。
(python没有单字符变量,都是用字符串(21byte),比整数型12byte还要大,所以不如用int数组)

面试题18删除链表的节点

1.如果要删除的节点传入的是一个指针,可以直接让p.val = p.next.val ,p.next = p.next.next覆盖掉要删除的节点(尾节点属于特殊情况)
2.如果是个节点的val值,就老老实实遍历到p.next.val = val,然后p.next = p.next.next,可以加一个哨兵节点在链表开头,就不用处理边界情况。
另外注意扩展题删除链表中重复节点
LeetCode82. 删除排序链表中的重复元素 II.

面试题19正则表达式匹配

运用dp思想。
1.a[i] == b[j] 或者b[j]==’.’, dp[i][j]= dp[i-1][j-1]
2.b[j] == ‘*’,先考虑忽略b[j-1],使dp[i][j] = dp[i][j] or dp[i][j-2]
3.如果b[j-1] = a[i]或者b[j-1]=’.’,则延长这个字符,使dp[i][j] = dp[i][j] or dp[i-1][j]

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m = len(s)
        n = len(p)
        dp = [[False] * (n+1) for _ in range(m+1)]
        dp[0][0] = True
        for i in range(m+1):
            for j in range(1,n+1):
                if p[j-1] != '*':
                    if i > 0 and (s[i-1] == p[j-1] or p[j-1] == '.'):
                        dp[i][j] = dp[i-1][j-1]
                else:
                    if j >= 2:
                        #可以选择不匹配,忽略*和之前一个字符
                        dp[i][j]= dp[i][j] or dp[i][j-2]
                    if i > 0 and (s[i-1] == p[j-2] or p[j-2] == '.'):
                        #继续用p的上一个字符匹配
                        dp[i][j]= dp[i][j] or dp[i-1][j]
        return dp[m][n]

面试题20表示数值的字符串

1.可以按照剑指offer上面拆分
2.可以设计一个自动机
3.推荐写法,设立4个标志变量,用来记录 e 和小数点以及数字还有e 之后的数字有没有出现过。
然后遍历整个整个字符串

  • 出现正负号,不在开头或者e后面,false
  • 出现小数点,如果已经出现过小数点和e,直接返回false,否则小数点记录变量True
  • 出现e,前面出现了e或者前面数字没有出现过,直接返回false,否则e记录变量True
  • 出现了数字,e没有出现就把数字记录变量True,出现了e就把e之后数字变量True
  • 出现其他字符,直接返回false
  • 遍历完成之后如果没有出现e直接返回数字记录变量,如果出现了e,返回数字记录变量且e之后数字变量
class Solution:
    def isNumber(self, s: str) -> bool:
        s = s.strip()
        n = len(s)
        # 用四个标记记录 e 和小数点以及数字和 e 之后的数字有没有出现过
        e_show_up, dot_show_up, num_show_up, num_after_e = False, False, False, False

        for i in range(n):
            c = s[i]
            # 如果是数字,则将数字和 e 后出现的数字都标记为 true
            # 没有 e 的浮点数也认为 e 之后出现过数字
            if c.isdigit():   
                if e_show_up:
                    num_after_e = True
                else:
                    num_show_up = True
            # 如果是正负号, 只有出现在首位或是 e 后面才合法
            elif c in ('+', '-'):
                if i > 0 and s[i-1] != 'e':
                    return False
            # 如果是小数点,那么必须保证 e 和小数点都没有出现过
            elif c == '.':
                if dot_show_up or e_show_up:
                    return False
                dot_show_up = True
            # 如果是 e, 要保证已经有数字出现,并且 e 没有出现过
            elif c == 'e':
                if e_show_up or not num_show_up:
                    return False
                e_show_up = True
            # 其他情况都为非法
            else:
                return False
        return num_show_up if not e_show_up else num_show_up and num_after_e

面试题21调整数组顺序使奇数位于偶数前面

双指针,l=0,r=len-1
当l < r时判断l所在元素满不满足条件,如果不满足,l与r位置的元素互换,然后r-=1
如果满足l+=1,即可完成交换。

面试题22链表中倒数第K个节点

常规的双针法,但是要注意鲁棒性,考虑空指针以及链表总长都没有k的情况

面试题23链表中环的入口节点

剑指offer上把问题分为了3步

  1. 快慢指针找到环上的点
  2. 得到环的长度
  3. 再通过链表头节点和第长度n个节点同速移动在入口相遇
    但是实际上2步就可以解决
  4. 快慢指针找到环上的点
  5. 通过链表头节点和环上节点同速移动在入口相遇

面试题24反转链表

该题迭代或者递归都是一个很清晰的解决方法

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        p1 = None
        p2 = head
        while p2:
            p2.next,p1,p2 = p1,p2,p2.next
        return p1

或者

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if(head==None or head.next==None):
            return head
        #head后面的链表都以及反转好了
        new_head = self.reverseList(head.next)
        #把head加上去
        head.next.next = head
        #尾节点处理好
        head.next = None
        return new_head

面试题25合并两个有序链表

操作有点像归并排序的merge部分
如果两个链表当前节点都不为空,取值小的为新链表的下一个节点,该链表往前走一步;
如果有一个链表空了,另一个链表直接加到新链表的尾部。

面试题26树的子结构

首先遍历A树,找到和B树根节点相同的节点,这个便利顺序或者递归迭代实现都随意。
找到之后调用判断函数,每个节点的遍历判断两个子树是否相等,注意A,B中分别出现空指针的返回不相等。

面试题27二叉树的镜像

分析可得,递归把每个子树的左右儿子互换即可达到要求

面试题28对称的二叉树

检查树以一种方式遍历以及对应反序遍历的结果是否相等。(t1左和t2右对比,t1右和t2左对比)

面试题29顺时针打印矩阵

用4个变量记录已经还没打印部分的上下左右四个边界,一个循环打印一圈,并每部分输出时判断是否越界了。

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix: return []
        l, r, t, b, res = 0, len(matrix[0]) - 1, 0, len(matrix) - 1, []
        while True:
            for i in range(l, r + 1): res.append(matrix[t][i]) # left to right
            t += 1
            if t > b: break
            for i in range(t, b + 1): res.append(matrix[i][r]) # top to bottom
            r -= 1
            if l > r: break
            for i in range(r, l - 1, -1): res.append(matrix[b][i]) # right to left
            b -= 1
            if t > b: break
            for i in range(b, t - 1, -1): res.append(matrix[i][l]) # bottom to top
            l += 1
            if l > r: break
        return res

来自LeetCode题解: Krahets.

面试题30包含min函数的栈

在正常的栈操作之外,添加一个辅助栈,大小和数据栈一致,但是栈里面的值是当前位置之前的最小值,每次push元素时,辅助栈压入栈顶和当前元素中的较小值。

面试题31栈的压入弹出序列

两个指针记录当前比较的压栈元素和出栈元素,如果辅助栈栈顶元素不是出栈元素,就压入入栈序列的下一个元素,知道入栈序列遍历完之后,看辅助栈的倒序是不是剩下来的出栈序列就可完成判断。

面试题32从上到下打印二叉树

32-1

借用FIFO队列完成层次遍历

32-2

设立两层循环,每个小循环里面完成一层打印操作,控制循环变量在刚进入循环部分时len(q)的值内技能防止越界,只输入这一层的节点。

32-3

同上,但是输出一层节点时判断是偶数层还是奇数层做不同的处理。

面试题33二叉搜索树的后序遍历序列

法1

以序列最后一个元素为根,小于它的为左子树节点,大于它的为右子树节点,判断序列中大于它的原始是否都在小于它的元素后面,如果时,递归检查左右子树是否满足条件

法2

单调栈思想,对于后序遍历的逆序列而言,遍历时一旦出现了下降的元素,意味着当前根节点的右子树遍历完了,开始处理左子树了。就不能大于当前的根,否则就是不满足的条件的序列。初始根设置为无穷大,相当于把原来的树当作无穷大节点的左子树。

面试题34二叉树中和为某一值的路径

因为路径从根节点开始,很容易利用回溯法,不断修改当前路径和以及路径元素,当路径和满足且为叶节点时把路径加入到输出结果即可,注意利用回溯法在某个点的路径搜索完成时记得pop掉它本身。

面试题35复杂链表的复制

1.首先遍历整个链表,把每个链表节点复制一份插入到自身后面,形成A->A‘->B->B’形式。
2.再次遍历链表,把A’->random 设置为A->random->next
3.最后遍历,分割链表

面试题36二叉搜索树与双向链表

注意二叉搜索树的性质,对其中序遍历的结果就是就是从小到大的排序,记录遍历的上一个节点,然后更改pre.right和cur.left即可

面试题37序列化二叉树

按照遍历规则,把问题拆分为分治的子问题即可。

面试题38字符串的排列

把字符串的排列分解为固定的第一个字符和后面的待排序字符串,交换头部和尾部的字符就把n长度字符串的排列变成了n-1个的n-1长度字符串排列问题。(还可以用一个集合看某个字符重复,已经当过前面的首字符了,进行剪枝操作)

面试题39数组中出现次数超过一半的数字

1.借助快速排序的划分函数,划分到N/2位置
2.利用数组特性,保留当前数字及其次数,遇到一样的数字则数字加1,不一样的数字减一,减到0是更换当前保留的数字

面试题40最小的K个数

1.借助快排的划分函数,划分到K-1位置,然后输出即可
2.如果海量数据,利用堆或者红黑树,只保留K个数在内存

面试题41数据流的中位数

利用堆数据结构,一个大项堆保存左半数据,一个小项堆保存右半数据,根据数据个数选择大项堆顶或者大小堆顶平均数作为返回值。

面试题42连续子数组的最大和

1.数组规律,记录遍历过程的数组和,一旦数组和<0那么从当前元素开始重新求和。
2.dp思想,dp[i] = max(nums[i],dp[i-1]+nums[i])

面试题43 1~n的整数中出现1的次数

寻找数值规律,每一位出现1的次数有如下规律

  1. 该位为0时,出现1的次数相当于n中该位右边置为0得到的数再除以10的次数,如3303的十位会有330次
  2. 该位为1时,相当于在1的基础上扩展了该位左边的数字的次数,如果3313的十位就会出现333次
  3. 该位为其他值时,相当于2里面左边是10的n-i次方的情况,产生一个进位,如3323得到330 + 10 =340次

面试题44 数字序列中某一位的数字

1.判断那一位属于几位数的范围
2.判断那一位具体属于哪一个的几位数
3.输入目标几位数的对应位置

面试题45把数组排成最小的数

定义一种比较规则,mn > nm则n

面试题46把数字翻译成字符串

利用dp思想,利用dp[i]储存从左到i位该数字可以翻译的不同数目,则转移方程可以写成
dp[i] = dp[i-2] + dp[i-1] if nums[i-1]*10 + nums[i] 属于10到25之间,否则
dp[i] = dp[i-1]

面试题47礼物的最大价值

利用dp思想,每个位置的最大价值只和左边以及上面一格的最大价值有关

dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + grid[i][j]

可以进步把dp数组优化为与grid行等长的一维数组

面试题48最长不含重复字符的子字符串

采用动态规划或者滑动窗口思想,记录当前字符在以前出现没有以及出现的位置(在不在当前考虑的窗口内),分别做判断。

面试题49丑数

空间换时间,记录以前生成过的所有丑数,来加快下一步生成。
发现新的丑数一定是由旧的丑数乘上(2,3,5)中一个得到的,所以设立3个指针,指向有可能生成新丑数的3个位数,取其生产的3个丑数中最小的,并对应位置记录右移一个。

面试题50第一个只出现一次的字符

利用hash表(python里字典即可)记录出现次数,因为python3.6以上字典是顺序的,遍历顺序和插入顺序一致。直接访问到的一个只出现一次的就是题目要求的输出。
涉及到多个字符需要多次判断出现与否或者次数的都可以用hash表。

面试题51数组中的逆序对

1.借助归并排序的思想,所以首先写出归并排序代码。
2.分析在归并排序合并两个子部分的时候,每当选中左边部分元素加入排序后数组时,相对于目前正在合并的数组而言,右部分当前元素到左边界的距离就是选中的左边部分元素构成的逆序对个数。所以在归并排序代码加上计数代码即可。

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        def mergeSort(l,r):
            if l >= r:
                return 0
            mid = (l + r) // 2
            i, j, pos = l, mid + 1, l
            #子问题求解
            inv_count = mergeSort(l,mid) + mergeSort(mid+1,r)
            while i <= mid and j <=r:
                if nums[i] <= nums[j]:
                    tmp[pos] = nums[i]
                    inv_count += (j-mid-1)
                    i += 1
                else:
                    tmp[pos] = nums[j]
                    j += 1
                pos += 1
            #一者遍历完毕
            for k in range(i, mid + 1):
                tmp[pos] = nums[k]
                inv_count += (j-mid-1)
                pos += 1
            for k in range(j, r + 1):
                tmp[pos] = nums[k]
                pos += 1
            #赋值
            nums[l:r+1] = tmp[l:r+1]
            return inv_count


        n = len(nums)
        tmp = [0] * n
        return mergeSort(0, n - 1)

面试题52两个链表的第一个公共节点

1.公共节点之后两个链表是一致的,可以设置两个栈保存遍历2个链表的结果,然后找到最后一个相等的栈顶元素。
2.考虑一般情况两个链表A,B长度不相等,但是A+B和B+A是相等的,所以遍历两个链表,每一步都判断节点是否相等,某一指针到了结尾空节点就转移到另一个链表的头,这样两个指针一定在公共节点相遇(或者都是空节点)。

面试题53在排序数组中查找数字

53-1

略微修改二分法,定位数字的左边界和右边界。

53-2

二分查找,判断条件变为i == nums[i]

面试题54二叉搜索树的第k大节点

二叉树的中序遍历就是排好序的结果,所以在中序遍历的基础上对k进行计数判断,k减小到0是就是找到条件节点了,可以返回。

面试题55二叉树的深度

55-1

depth(root) = max(depth(root.left),depth(root.right)) + 1

55-2

该题如果像上面一小问处理的话,会重复处理一个节点好多次。
所以应该从底向上处理,如果某个节点不平衡,直接返回-1给父节点,如果平衡就返回自己的深度以供父节点判断自己平不平衡。父节点收到一个-1也就可以立马返回不平衡-1.

面试题56数组中数字出现的次数

56-1

类比只有一个数字出现一次的那道题,该题有两个数字那么他们的异或结果肯定有一位为1既两个数该位不同,那么根据这一点把数组分为a,b两部分,每部分就只包含一个只出现一次的数,就可以按之前的方法解答了。

56-2

用32位数组记录数组中数字的二进制形势下,各位出现1的情况,如果总的出现次数能整除3的肯定不是只出现一次的数该有的位,把不能整除3的位取出来还原成10进制即可。

面试题57和为s的两个数字

57-1

双指针从左右向中间扫描,如果两数之和大于目标,r-=1,反之l+=1

57-2

使用滑动窗口思想,判断滑动窗口内之和是否等于target,滑动时对记录的原窗口之和加减操作即可变成新值,不必每次sum求和。

面试题58反转字符串

58-1

1.python库函数,split和strip切割以及过滤
2.双指针定位每个单词左右边界实施反转。

58-2

1.python简单切片
2.通过3次反转实现,a,b反转,再反转a+b

面试题59队列的最大值

59-1

滑动窗口思想,用一个降序的双端队列保存遍历中的结果,每次遍历到数组中元素大于队列头或者当前队列头是窗口左边界外的元素,则把它挪出队列,压入新的元素;遍历到每个位置上时队列头的元素就是窗口内最大值。

59-2

同时维护一个普通队列和上一小问一样的双端队列即可

面试题60n个骰子的点数

利用dp思想,记录n-1个骰子的取值概率,然后推演出n个骰子的(n-1的每个概率值均摊到+1~+6的下一个取值中)

面试题61扑克牌中的顺子

数组中不出现对子且最大最小牌之间的差距小于5即可

面试题62圆圈中最后剩下的数字

设f(n,m)为n个数按照m间隔删除数字后留下的那个,那么来寻找f(n-1,m)和f(n,m)的递推关系。
分析可得f(n,m) = (f(n-1,m)+m)%n按照递推关系式写出递归或者迭代程序即可得出结果。

面试题63股票的最大利润

设置变量保存之前的最大利润和出现的最低价格,每次遍历到一个元素都计算出当前可获得的利润,和保存的最大利润最比较。

面试题64 1+2+。。。。。。+n

首先发现递归或者迭代方法的话都要考虑一下终止条件问题。
所以可以利用逻辑操作里面的短路操作

n > 1 and self.sumNums(n - 1)

如果n是1就不会调用下一个n-1了,就终止了迭代。

面试题65不用加减乘除做加法

不能用正常3四则运算时,我们就要想到位运算这个一神器。
二进制的不进位加法可以用a^b来模拟,而加法的进位可用(a&b)<<1模拟,那么不断地把不进位加法的和以及进位结果相加直到进位为0时,就完成了加法操作。

#需要注意的是python中整数没有固定储存长度
#需要&0xffffffff固定到32位进行操作
#最后结果的首位如果是1则说明本来应该负数,我们的截断到32位操作需要还原这个负数在python中的表达方式~(a ^ x)是将 32 位以上的位取反,即由0 变为 1 , 1 至 32 位不变。

面试题66构建乘积数组

从头到尾遍历一次得出元素左边数组之积,
从尾到头遍历一次得出元素右边数组之积,
两者对应相乘就是结果。

面试题67把字符串转换为整数

常规考题,但是注意考虑边界情况。
1.非法输入
2.越界

面试题68树中两个节点的最低公共祖先

68-1

如果树是二叉搜索树的话,根据其特点:根节点大于左子树而小于右子树。
从树的根节点开始往下搜索,如果两个节点都大于这个值,往右子树递归,小于就往左子树递归,如果一大一小,那么根节点就恰好是要找的节点。

68-2

1.使用两个数组保存根节点到两个节点的路径,然后倒着求最后一个公共点即可。
2.使用后序遍历,把子树中的搜索结果返回,避免对子节点重复检索。

你可能感兴趣的:(LeetCode,算法,数据结构,面试)