1. 单词替换
在英语中,我们有一个叫做 词根(root) 的概念,可以词根后面添加其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如,词根an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。
现在,给定一个由许多词根组成的词典 dictionary 和一个用空格分隔单词形成的句子 sentence。你需要将句子中的所有继承词用词根替换掉。如果继承词有许多可以形成它的词根,则用最短的词根替换它。
你需要输出替换之后的句子。
分析:
首先将词典中所有词根放入一个哈希集合中,然后对于句子中的每个单词,由短至长遍历它所有的前缀,如果这个前缀出现在哈希集合中,则我们找到了当前单词的最短词根,将这个词根替换原来的单词。最后返回重新拼接的句子。
class Solution:
def replaceWords(self, dictionary: List[str], sentence: str) -> str:
dictionarySet = set(dictionary)
words = sentence.split(' ')
for i, word in enumerate(words):
for j in range(1, len(words) + 1):
if word[:j] in dictionarySet:
words[i] = word[:j]
break
return ' '.join(words)
2. II 平衡二叉树
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
分析:
采用后序遍历的方法,递归的去访问当前节点的左右子树, 并返回左右子树的高度来判断是否是平衡二叉树
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
def recur(root):
if not root: return 0
left = recur(root.left)
if left==-1:return -1
right = recur(root.right)
if right==-1:return -1
return max(left ,right) + 1 if abs(left-right) <= 1 else -1
return recur(root)!=-1
3. 数组中数字出现的次数
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:
异或操作的性质:对于两个操作数的每一位,相同结果为 0,不同结果为 1。那么在计算过程中,成对出现的数字的所有位会两两抵消为 0,最终得到的结果就是那个出现了一次的数字。
使用位运算来解决:
- 先对所有数字进行异或操作, 得到两个只出现一次数字的异或结果
- 找到结果中任意为1的位
- 遍历数组,找到这一位为1的数的位置,把数组分为两组
- 对每个组内进行异或操作,得到这两个数
class Solution:
def singleNumbers(self, nums: List[int]) -> tuple[int, int]:
x = 0
y = 0
n = 0
m = 1
for num in nums:
n ^= num
while (n & m == 0):
m <<= 1
for num in nums:
if num & m:
x ^= num
else:
y ^= num
return x, y
4. 数组中数字出现的次数 II
在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
分析:
没要求时间复杂度与空间复杂度,就没有用位运算,是用哈希表简单完成.
class Solution {
public int singleNumber(int[] nums) {
HashMap<Integer, Integer> map = new HashMap<>();
int res = 0;
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], map.getOrDefault(nums[i],0)+1);
}
for (int i = 0; i < nums.length; i++) {
if (map.get(nums[i]) == 1){
res = nums[i];
break;
}
}
return res;
}
}
5. 和为s的两个数字
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
分析:
双指针问题, 初始时一个指向数组第一个元素(i=0),一个指向最有一个元素(j=length-1),不断地与s比较,移动i和j,直到两数之和为s
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
i = 0
j = len(nums) - 1
while i < j:
num = nums[i] + nums[j]
if num < target: i += 1
elif num > target: j -= 1
else: return nums[i], nums[j]
return []
6. 和为s的连续正整数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
分析:
滑动窗口:
- 左边界 i = 1 ,右边界 j = 2 ,元素和 s = 3 ,结果列表 res
- 当i<j时,循环:
当 s > target 时: 向右移动左边界 i = i + 1,并更新元素和 s ;
当 s < target 时: 向右移动右边界 j = j + 1,并更新元素和 s ;
当 s = target 时: 记录连续整数序列,并向右移动左边界 i = i + 1; - 返回结果列表 res
class Solution:
def findContinuousSequence(self, target: int) -> List[List[int]]:
i,j,count,res = 1, 2, 3, []
while i<j:
if count == target:
res.append(list(range(i, j+1)))
if count >= target:
count -= i
i += 1
else:
j += 1
count += j
return res