面试中的各项能力
Q. 两个链表第一个公共节点
A. 思路:通过倒序遍历两个链表,即使用两个stack来装载两个链表的节点,分别比较两个stack.top(),直到不相等时说明出现了分叉
Q. 排序二叉树中两个节点的最低公共祖先
A. 思路:从根节点出发,如果root.value比两个节点的值都大,则遍历root.left; 如果root.value比两个节点的值都小,则遍历root.right; 否则root就是最低公共祖先
Q. 任意树(有指针指向父节点)中两个节点的最低公共祖先
A. 思路:从给定的两个节点出发,遍历到根节点,生成两个链表,从而转化为求两个链表的第一个公共节点问题
Q. 在排序数组中查找数字: 数字在排序数组中出现的个数 {1,1,2,2,3,3,3,3} -> {3: 4}
A. 思路:
- 可以微调k调用两次二分查找,分别找到起止位置;
- 可以加入判断,当number[mid] == k and number[mid-1] != k时,此时startIndex = mid; 否则继续查找左区间 right = mid-1;
- 当number[mid] == k and number[mid+1] != k时,此时endIndex = mid; 否则继续查找右区间 left = mid+1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21def binarySearch(numbers: list, k):
left, right = 0, len(numbers) - 1
while left < right:
mid = (left + right) // 2
if numbers[mid] == k:
return mid
elif numbers[mid] > k:
right = mid
else:
left = mid + 1
return left
def getNumberOfK(numbers: list, k):
if numbers == None or len(numbers) == 0:
return
k1 = k - 0.1
k2 = k + 0.1
return binarySearch(numbers, k2) - binarySearch(numbers, k1)
Q. 二叉搜索树的第k大节点:给定一棵二叉搜索树,找出其中第k大的节点1
2
3
4k=3 -> 4
5
3 7
2 4 6 8
A. 思路:中序遍历二叉搜索树,会得到递增序列,转化为求第k大的数
Q. 二叉树的深度:根节点到页节点的最长路径
A. 思路:递归遍历左右子树,返回1+max(left, right)即可
1 | class treeNode: |
Q. 平衡二叉树:判断是否为平衡二叉树,即各节点左右子树深度不超过1
A. 思路:
- 调用getMaxDepth函数,在每次计算两边深度时都进行一次判断,但会造成多次重复访问
- 改造getMaxDepth函数,在访问某个节点时要记录其之前的深度,模拟后序遍历,先遍历左右子树,再判断当前节点深度差
1 | def isBalanced(root: treeNode, depth: int): |
Q. 数组中数字出现的个数:一个数组中只有两个数字出现了一次,其余数字均出现了两次,请找出这两个数字,要求时间、空间复杂度O(n)、O(1)1
{2,4,3,6,3,2,5,5} -> {4,6}
A. 思路:异或
- 首先对数组中的元素逐个异或,由于相同的元素异或会抵消,所以最终结果的二进制位一定有一位是1(因为有两个元素不同)
- 假设第n位为1,接下来通过第n位是否为1将原数组划分为两个数组,这样保证了相同的数字一定在同一个数组中,而且两个不同的数字一定位于不同的数组
- 对两个数组逐个异或即可
1 | def findNumsApperOnce(numbers:list): |
Q. 数组中唯一只出现一次的数字:一个数组中除一个数字只出现一次外,其他数字都出现了三次,求只出现一次的数字
A. 思路:从位运算角度考虑,如果一个数字出现了三次,那么其对应的二进制位的1也出现了三次,对每个二进制位进行加和,只出现一次的数字对应的二进制位之和一定不能被3整除。
1 | def findNumsAppearOnceIn3(numbers: list): |
Q. 和为s的两个数字:输入一个递增排序数组
和一个数字s,在数组中查找两个数使得输入之和为s。
A. 思路:双指针法,分别指向头尾,如果当前加和结果小于s,则前指针后移,否则后指针前移。
Q. 和为s的连续正数序列:输入一个正数s,打印出所有和为s的连续的正数数列。15->{1,2,3,4,5},{4,5,6},{7,8}
A. 思路:双指针法,small,big分别从1,2开始,如果两个指针之间序列和小于s,则加大big,否则加大small
1 | def FindContinuousSequence(sum: int): |
Q. 队列的最大值:给定一个数组和滑动窗口的大小,找出所有滑动窗口里的最大值。{2,3,4,2,6,2,5,1}, 3 -> {4,4,6,6,6,5}
A. 思路:
Q. n个骰子的点数:把n个骰子扔在地上,所有骰子朝上一面点数之和为s,打印出s的所有可能出现的值的概率
A. 思路:f(n) = f(n-1)+f(n-2)+f(n-3)+f(n-4)+f(n-5)+f(n-6)
- n个骰子点数和的最小值为n,最大值为6n,共有6^n种排列情况。
- 递归法:定义一个
6n-n+1
长度的数组,将和为s的次数保存在第s-n
的位置处。把骰子分成两拨,第一堆只有一个,第二堆有n-1个,时间效率不够好
1 | def PrintProbablity(num: int): |
Q. 扑克牌中的顺子:从扑克牌中随机抽五张牌,判断是否是顺子,joker代替任意牌。
A. 思路:
- 把joker看作0,JQK看作11、12、13;
- 对数组排序,如果有对子则不可能是顺子;
- 统计连续数组中有多少间隔,判断能否用joker补上。
1 | def isContinuous(numbers: list): |
Q. 圆圈中最后剩下的数字:0,1…n-1排成一个圆圈,从0开始,每次从这个圆圈中删除第m个数字,求这个圆圈中剩下的最后一个数字。
A. 思路:
- 用环形链表模拟圆圈,时间复杂度O(mn)
- 递推:f(n, m) = (f(n-1, m) + m)%n | n>1; f(n, m) = 0 | n=1
1 | def LastRemaining(n: int, m: int): |
Q. 股票的最大利润:把股票价格按时间顺序输入,如何买入一次卖出一次才能获得最大利润。{9,11,8,5,7,12,16,14}->{5入16出}
A. 思路:设diff[i]代表到i时能获得的最大利润,则diff[i] = price[i] - min[0:i-1]
1 | def MaxDiff(price: list): |