leetcode刷题 420~
题目421题
数组中两个数的最大异或值
给定一个非空数组,数组中元素为 a0, a1, a2, … , an-1,其中 0 ≤ ai < 231 。
找到 ai 和aj 最大的异或 (XOR) 运算结果,其中0 ≤ i, j < n 。
你能在O(n)的时间解决这个问题吗?
示例:
输入: [3, 10, 5, 25, 2, 8]
输出: 28
解释: 最大的结果是 5 ^ 25 = 28.
思路
字典树:将数组中元素转化为二进制后,放入字典树中,同时计算该数字在字典树中所能得到的最大异或值。
实现
class Solution: def findMaximumXOR(self, nums: List[int]) -> int: trie = {} L = len(bin(max(nums))) - 2 nums = [[(x >> i) & 1 for i in range(L)][::-1] for x in nums] result = 0 for num in nums: node = trie revnode = trie cur = 0 for bit in num: if not bit in node: node[bit] = {} node = node[bit] revbit = 1 - bit if revbit in revnode: cur = (cur<<1) | 1 revnode = revnode[revbit] else: cur = cur << 1 revnode = revnode[bit] result = max(result, cur) return result
题目427题
建立四叉树
思路
递归
实现
class Solution: def construct(self, grid: List[List[int]]) -> 'Node': n = len(grid) def helper(r, c, l) -> 'Node': sign = grid[r][c] flag = True for i in range(r,r+l): for j in range(c,c+l): if grid[i][j] != sign: flag = False break if flag: return Node(sign, flag, None, None, None, None) else: l = l//2 topLeft = helper(r,c,l) topRight = helper(r,c+l,l) bottomLeft = helper(r+l,c,l) bottomRight = helper(r+l,c+l,l) return Node(sign, flag,topLeft, topRight, bottomLeft, bottomRight) return helper(0,0,n)
题目429题
N叉树的层次遍历
给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。
思路
递归或者广度优先遍历
实现
class Solution: def levelOrder(self, root: 'Node') -> List[List[int]]: result = [] if not root: return result def helper(level,node): if len(result) == level: result.append([]) result[level].append(node.val) for child in node.children: helper(level+1, child) helper(0,root) return result
题目430题
扁平化多级双向链表
多级双向链表中,除了指向下一个节点和前一个节点指针之外,它还有一个子链表指针,可能指向单独的双向链表。这些子列表也可能会有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。
给你位于列表第一级的头节点,请你扁平化列表,使所有结点出现在单级双链表中。
思路
递归
实现
class Solution: def flatten(self, head: 'Node') -> 'Node': result = head while head: if head.child: next_node = head.next child_node = self.flatten(head.child) head.child = None head.next = child_node child_node.prev = head while child_node.next: child_node = child_node.next if next_node: next_node.prev = child_node child_node.next = next_node head = next_node else: head = head.next return result
题目433题
最小基因变化
一条基因序列由一个带有8个字符的字符串表示,其中每个字符都属于 "A", "C", "G", "T"中的任意一个。
假设我们要调查一个基因序列的变化。一次基因变化意味着这个基因序列中的一个字符发生了变化。
例如,基因序列由"AACCGGTT" 变化至 "AACCGGTA" 即发生了一次基因变化。
与此同时,每一次基因变化的结果,都需要是一个合法的基因串,即该结果属于一个基因库。
现在给定3个参数 — start, end, bank,分别代表起始基因序列,目标基因序列及基因库,请找出能够使起始基因序列变化为目标基因序列所需的最少变化次数。如果无法实现目标变化,请返回 -1。
思路
广度优先遍历
实现
class Solution: def minMutation(self, start: str, end: str, bank: List[str]) -> int: if end not in bank: return -1 gene = "ACGT" bank = set(bank) q = collections.deque() q.append((start,0)) while q: word, level = q.popleft() if word == end: return level for i in range(8): for j in gene: temp = word[0:i] + j + word[i+1:] if temp in bank: q.append((temp,level+1)) bank.remove(temp) return -1
题目434题
字符串中的单词数
统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。
思路实现
class Solution: def countSegments(self, s: str) -> int: result, flag = 0, True for i in s: if i != " " and flag: result += 1 flag = False if i == " ": flag = True return result
题目435题
无重叠区间
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
注意:
可以认为区间的终点总是大于它的起点。
区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。
思路
贪心算法:
当按照起点先后顺序考虑区间的时候:
情况一
当前考虑的两个区间不重叠:
在这种情况下,不移除任何区间,将 prev 赋值为后面的区间,移除区间数量不变。
情况二
两个区间重叠,后一个区间的终点在前一个区间的终点之前。
这种情况下,我们可以简单地只用后一个区间。这是显然的,因为后一个区间的长度更小,可以留下更多的空间(A 和 B),容纳更多的区间。因此, prev更新为当前区间,移除区间的数量 + 1。
情况三
两个区间重叠,后一个区间的终点在前一个区间的终点之后。
这种情况下,我们用贪心策略处理问题,直接移除后一个区间。为了理解这种做法的正确性,请看下图,该图包含了所有可能的情况。从图可以清楚地看出,选择前移区间总会得到更好的结果。因此,prev不变,移除区间的数量 + 1。
实现
class Solution: def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: if not intervals: return 0 intervals = sorted(intervals,key= (lambda x:[x[0],x[1]])) prel, prer = intervals[0][0], intervals[0][1] result = 0 for index in range(1,len(intervals)): left = intervals[index][0] right = intervals[index][1] if prer > left: if prer > right: prel, prer = left, right result += 1 else: prel, prer = left, right return result
题目436题
寻找右区间
给定一组区间,对于每一个区间 i,检查是否存在一个区间 j,它的起始点大于或等于区间 i 的终点,这可以称为 j 在 i 的“右侧”。
对于任何区间,你需要存储的满足条件的区间 j 的最小索引,这意味着区间 j 有最小的起始点可以使其成为“右侧”区间。如果区间 j 不存在,则将区间 i 存储为 -1。最后,你需要输出一个值为存储的区间值的数组。
注意:
你可以假设区间的终点总是大于它的起始点。
你可以假定这些区间都不具有相同的起始点。
思路
二分法:记录每个区间的左值,将其排序。每个值的右值在其寻找最大小于区间左值的点。
实现
class Solution: def findRightInterval(self, intervals: List[List[int]]) -> List[int]: result = [-1 for i in range(len(intervals))] left = dict() for i in range(len(intervals)): left[intervals[i][0]] = i test = sorted(left.keys()) for i in range(len(intervals)): l, r = 0 , len(test)-1 while l < r: mid = l + (r-l)//2 if test[mid] >= intervals[i][1]: r = mid else: l = mid+1 if test[l] >= intervals[i][1]: result[i] = left[test[l]] return result
题目437题
路径总和III
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
思路
深度优先遍历
实现
class Solution: def pathSum(self, root: TreeNode, sum: int) -> int: result = 0 def dfs(node,tmepsum): if not node: return nextsum = [0] for i in tmepsum: temp = i + node.val if temp == sum: nonlocal result result += 1 nextsum.append(temp) dfs(node.left,nextsum) dfs(node.right,nextsum) dfs(root,[0]) return result
题目438题
找到字符串中所有字母异位词
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。
字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:
字母异位词指字母相同,但排列不同的字符串。
不考虑答案输出的顺序。
思路
滑动窗口
实现
class Solution: def findAnagrams(self, s: str, p: str) -> List[int]: ls, lp = len(s), len(p) result = [] if ls < lp: return result dict_s, dict_p = dict.fromkeys(string.ascii_lowercase, 0), dict.fromkeys(string.ascii_lowercase, 0) for index in range(lp): words, wordp = s[index], p[index] dict_p[wordp] += 1 dict_s[words] += 1 for index in range(ls-lp+1): if dict_p == dict_s: result.append(index) if index == ls - lp: break old, new = s[index], s[index+lp] dict_s[old] -= 1 dict_s[new] += 1 return result