【周赛】第150场-2019-8-18

目录

1-拼写单词-easy。哈希表、字符串

2-最大层内元素和-medium。树、层序遍历

3-地图分析-medium。BFS

4-按字典序排在最后的子串-hard。栈、字典序


1-拼写单词-easy。哈希表、字符串

给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars

假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌握了这个单词。

注意:每次拼写时,chars 中的每个字母都只能用一次。

返回词汇表 words 中你掌握的所有单词的 长度之和

示例 1:

输入:words = ["cat","bt","hat","tree"], chars = "atach"
输出:6
解释: 
可以形成字符串 "cat" 和 "hat",所以答案是 3 + 3 = 6。

示例 2:

输入:words = ["hello","world","leetcode"], chars = "welldonehoneyr"
输出:10
解释:
可以形成字符串 "hello" 和 "world",所以答案是 5 + 5 = 10。

 DIY的想法就是对words中的每个词都看看能不能用chars组成,但这样每次都要新建一个新chars的字典,后来看大神们的做法也差不多,难道考点利用题目条件说只有小写字母所以用26长度的数组代替字典?

也有对每个词新建字典然后比较chars里的频数的方法,本质是一样的

class Solution:
    def countCharacters(self, words: List[str], chars: str) -> int:
        if not words or not chars:
            return 0
        dic = [0]*26
        res = 0
        for w in chars:
            dic[ord(w)-ord('a')] += 1
        for w in words:
            cur = dic[:]
            flag = True
            for c in w:
                if cur[ord(c)-ord('a')] <= 0:
                    flag = False
                    break
                cur[ord(c)-ord('a')] -= 1
            if flag:
                res += len(w)
        return res

2-最大层内元素和-medium。树、层序遍历

给你一个二叉树的根节点 root。设根节点位于二叉树的第 1 层,而根节点的子节点位于第 2 层,依此类推。

请你找出层内元素之和 最大 的那几层(可能只有一层)的层号,并返回其中 最小 的那个。

 

示例:

输入:[1,7,0,7,-8,null,null]
输出:2
解释:
第 1 层各元素之和为 1,
第 2 层各元素之和为 7 + 0 = 7,
第 3 层各元素之和为 7 + -8 = -1,
所以我们返回第 2 层的层号,它的层内元素之和最大。

没什么难点,理解清楚题意就是如果最大的和有多组,返回层数最小的那一层。考察层序遍历,涉及到队列机制

还有好久没用DFS方法

# BFS
class Solution:
    def maxLevelSum(self, root: TreeNode) -> int:
        if not root:
            return 0
        res = root.val
        level = 1
        q = [root]
        i = 0
        while q:
            cur_res = 0
            for _ in range(len(q)):
                cur = q.pop(0)
                cur_res += cur.val
                if cur.left:
                    q.append(cur.left)
                if cur.right:
                    q.append(cur.right)
            i += 1
            if cur_res > res:
                res = cur_res
                level = i
        return level

# DFS
class Solution:
    def maxLevelSum(self, root: TreeNode) -> int:
        if not root:
            return 0
        res = {}
        self.dfs(root, res, 1)
        ans = 0
        ssum = float('-inf')
        for k in res:
            if res[k] > ssum:
                ssum = res[k]
                ans = k
        return ans
    
    def dfs(self, root, res, level):
        if not root:
            return
        res[level] = res.get(level, 0) + root.val
        self.dfs(root.left, res, level+1)
        self.dfs(root.right, res, level+1)
        return

3-地图分析-medium。BFS

你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远的海洋区域是是哪一个吗?请返回该海洋区域到离它最近的陆地区域的距离。

我们这里说的距离是『曼哈顿距离』( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个区域之间的距离是 |x0 - x1| + |y0 - y1| 。

如果我们的地图上只有陆地或者海洋,请返回 -1

示例 1:

输入:[[1,0,1],[0,0,0],[1,0,1]]
输出:2
解释: 
海洋区域 (1, 1) 和所有陆地区域之间的距离都达到最大,最大距离为 2。

示例 2:

输入:[[1,0,0],[0,0,0],[0,0,0]]
输出:4
解释: 
海洋区域 (2, 2) 和所有陆地区域之间的距离都达到最大,最大距离为 4。

DIY的想法是每个0位置都BFS找距离最短的1,最后比较出最大的,但超时,确实是有很多重复计算。所以这道题的正确解法应该是从每个1位置出发去标记周围的cell,因为是BFS,所以对于一个water cell来说肯定是距离它最近的land cell最先把它标记,其他要么和它等距要么更远。跟这道题相近的有大西洋和太平洋水流向的那题,计算水流向的同时把距离也更新了

逆向思维,或者说以后这种题就都用这种套路把

class Solution:
    def maxDistance(self, grid: List[List[int]]) -> int:
        if not grid:
            return -1
        m = len(grid)
        n = len(grid[0])
        res = -1
        dp = [[-1 for _ in range(n)] for _ in range(m)]
        around = [[-1, 0], [1, 0], [0, -1], [0, 1]]
        q = []
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    dp[i][j] = 0
                    q.append((i, j)) 
        self.helper(grid, m, n, q, dp, around)
        for i in range(m):
            for j in range(n):
                res = max(res, dp[i][j])
        return res if res != 0 else -1
    
    def helper(self, grid, m, n, q, dp, around):
        while q:
            x, y = q.pop(0)
            for d in around:
                n_x = x + d[0]
                n_y = y + d[1]
                if n_x < 0 or n_x >= m or n_y < 0 or n_y >= n or dp[n_x][n_y] != -1:
                    continue
                dp[n_x][n_y] = dp[x][y]+1
                q.append((n_x, n_y))
        return

4-按字典序排在最后的子串-hard。栈、字典序

给你一个字符串 s,找出它的所有子串并按字典序排列,返回排在最后的那个子串。

示例 1:

输入:"abab"
输出:"bab"
解释:我们可以找出 7 个子串 ["a", "ab", "aba", "abab", "b", "ba", "bab"]。按字典序排在最后的子串是 "bab"。

示例 2:

输入:"leetcode"
输出:"tcode"

2种方法

  • 暴力+剪枝,暴力就是找到所有子串,剪枝就是字典序最大的子串必然是包含最后一个字符的又是连续的,所以必然是从某个位置开始slice到最后构成的子串,python的强大max还能比较字符串的字典序,所以这道题可以这么暴力或者说带点作弊的思想解把
  • 当成hard算法题来解的话,这道题必然要用到单调栈,但只能作为解题的第一步,
# 剪枝后的暴力
class Solution:
    def lastSubstring(self, s: str) -> str:
        res = ''
        for i in range(len(s)):
            res = max(res, s[i:])
        return res

# 正解

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值