10.30 32.移动石子
三枚石子放置在数轴上,位置分别为 a,b,c。
每一回合,我们假设这三枚石子当前分别位于位置 x, y, z 且 x < y < z。从位置 x 或者是位置 z 拿起一枚石子,并将该石子移动到某一整数位置 k 处,其中 x < k < z 且 k != y。
当你无法进行任何移动时,即,这些石子的位置连续时,游戏结束。
要使游戏结束,你可以执行的最小和最大移动次数分别是多少? 以长度为 2 的数组形式返回答案:answer = [minimum_moves, maximum_moves]
思路
最少0或1或2,分情况。
我的解
class Solution:
def numMovesStones(self, a: int, b: int, c: int) -> List[int]:
tmp = [a,b,c] # 先对xyz赋值
tmp.sort()
x,y,z = tmp[0],tmp[1],tmp[2]
if x + 1 == y and y + 1 == z: # a,b,c连续
return [0,0]
else:
if y-x == 2 or z-y == 2 or (x+1 == y or y + 1 == z): # 中间隔一个或者有两个挨着
minimum_moves = 1
else:
minimum_moves = 2
maximum_moves = (y-x)+(z-y)-2
return [minimum_moves,maximum_moves]
11.1 33. 拼写单词
给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars。
假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。
注意:每次拼写(指拼写词汇表中的一个单词)时,chars 中的每个字母都只能用一次。
返回词汇表 words 中你掌握的所有单词的 长度之和。
输入:words = ["cat","bt","hat","tree"], chars = "atach"
输出:6
解释:
可以形成字符串 "cat" 和 "hat",所以答案是 3 + 3 = 6。
思路
用counter将chars每个字母出现的次数提取出来,分别遍历数组里每一个单词的counter,符合条件的即是。
我的解
class Solution:
def countCharacters(self, words: List[str], chars: str) -> int:
from collections import Counter
from copy import deepcopy
chars_dic = Counter(chars)
res_list = []
for word in words:
fit = 1
dic_copy = deepcopy(chars_dic)
per_dic = Counter(word)
dic_copy.subtract(per_dic)
for i in dic_copy.values():
if i < 0:
fit = 0
break
if fit:
res_list.append(word)
return len(''.join(res_list))
11.2 34. 搜索旋转排序数组
给你一个升序排列的整数数组 nums ,和一个整数 target 。
假设按照升序排序的数组在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
思路
可以遍历,时间复杂度高。
利用二分法,分为L,R两个数组,因为是有序数组分的。如果L和R都是有序,判断target在哪个区间。继续二分。如果L[0] > L[-1] 说明L无序,如果target在R里,可以丢弃L,如果target不在,继续二分。判断并丢弃。
最优解
class Solution:
@classmethod
def search(self, nums: list, target: int) -> int:
if not nums:
return -1
l, r = 0, len(nums) - 1
while l <= r:
mid = (l + r) // 2
if nums[mid] == target:
return mid
if nums[0] <= nums[mid]:
if nums[0] <= target < nums[mid]:
r = mid - 1
else:
l = mid + 1
else:
if nums[mid] < target <= nums[len(nums) - 1]:
l = mid + 1
else:
r = mid - 1
return -1
总结
每次可以至少得到一个有序区间,如果target在此区间丢弃另一个,如果不在丢弃自身。
11.3 35. 恢复二叉搜索树
给你二叉搜索树的根节点 root
,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。
输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。
输入:root = [3,1,4,null,null,2]
输出:[2,1,4,null,null,3]
解释:2 不能在 3 的右子树中,因为 2 < 3 。交换 2 和 3 使二叉搜索树有效。
最优解一:显示中序遍历
-
为什么用中序
根据题意,任意根节点,左边比根节点小,右边比根节点大。有序的搜素树中序遍历一定有序
class Solution(object): def recoverTree(self, root): nodes = [] # 中序遍历二叉树,并将遍历的结果保存到list中 def dfs(root): if not root: return dfs(root.left) nodes.append(root) dfs(root.right) dfs(root) x = None y = None pre = nodes[0] # 扫面遍历的结果,找出可能存在错误交换的节点x和y for i in xrange(1,len(nodes)): if pre.val>nodes[i].val: y=nodes[i] if not x: x = pre pre = nodes[i] # 如果x和y不为空,则交换这两个节点值,恢复二叉搜索树 if x and y: x.val,y.val = y.val,x.val