第7周Leetcode记录

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 ,该树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

img

输入:root = [1,3,null,null,2]
输出:[3,1,null,null,2]
解释:3 不能是 1 左孩子,因为 3 > 1 。交换 1 和 3 使二叉搜索树有效。

img

输入: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
    
    
posted @ 2020-11-07 14:47  Jimmyhe  阅读(72)  评论(0编辑  收藏  举报