LeetCode笔记:Weekly Contest 247(补发)

1. 题目一

给出题目一的试题链接如下:

1. 解题思路

这一题挺直接的,由于都是正数,所以直接对原数据进行排序,然后选取最大的两个元素相乘减去最小的两个元素的乘积即可得到最大值。

2. 代码实现

给出python代码实现如下:

class Solution:
    def maxProductDifference(self, nums: List[int]) -> int:
        nums = sorted(nums)
        return nums[-1]*nums[-2] - nums[0]*nums[1]

提交代码评测得到:耗时164ms,占用内存15.4MB。

2. 题目二

给出题目二的试题链接如下:

1. 解题思路

这一题的思路还是比较清晰的,我的解法是先将每一圈的元素拿出来,然后进行旋转,最后重新填入到矩阵当中。

2. 代码实现

给出python代码实现如下:

class Solution:
    def rotateGrid(self, grid: List[List[int]], k: int) -> List[List[int]]:
        n, m = len(grid), len(grid[0])
        l = min(n, m) // 2
        res = [[0 for _ in range(m)] for _ in range(n)]
        for i in range(l):
            s = [grid[j][i] for j in range(i, n-i)] + [grid[n-1-i][j] for j in range(i+1, m-i)] + [grid[j][m-1-i] for j in range(n-i-2,i,-1)] + [grid[i][j] for j in range(m-i-1,i,-1)]
            # print(s)
            delta = k % len(s)
            s = s[-delta:] + s[:-delta]
            idx = 0
            for j in range(i, n-i):
                res[j][i] = s[idx]
                idx += 1
            for j in range(i+1, m-i):
                res[n-1-i][j] = s[idx]
                idx += 1
            for j in range(n-i-2,i,-1):
                res[j][m-1-i] = s[idx]
                idx += 1
            for j in range(m-i-1,i,-1):
                res[i][j] = s[idx]
                idx += 1
        return res

提交代码评测得到:耗时140ms,占用内存14.7MB。

3. 题目三

给出题目三的试题链接如下:

1. 解题思路

这一题我自己是没有搞定,最后看了别人的解法才想到的解法。

不过解法确实巧妙。

由于我们一共只有10个字符,且每个字符只有奇数和偶数两种状态,因此,我们只需要使用 2 10 2^{10} 210,即1024个状态即可记录下所有可能的状态值。

其中,0的初始状态值就为1。

当我们每经过一个字符,我们可以更新当前的状态值,此时,我们遍历所有与当前状态位数相差为1的状态出现的次数,就可以得到所有到当前字符为止的所有可能的wonderful substring的个数。

累加其全部的结果我们即可得到最终的结果。

2. 代码实现

给出python代码实现如下:

class Solution:
    def wonderfulSubstrings(self, word: str) -> int:
        n = len(word)
        loc = [0 for _ in range(1024)]
        loc[0] = 1
        status = 0
        res = 0
        for i, c in enumerate(word):
            c = ord(c) - ord('a')
            status = status ^ (1 << c)
            res += loc[status]
            for j in range(10):
                pre = status ^ (1 << j)
                res += loc[pre]
            loc[status] += 1
        return res

提交代码评测得到:耗时2688ms,占用内存15.4MB。

4. 题目四

给出题目四的试题链接如下:

1. 解题思路

这一题多少有点看答案的成分在里面吧,不过能把这题搞定还是很开心的。

这题的整体思路可以拆分为两个部分:

  1. 通过出度来获取整个树的拓扑排序序列;
  2. 通过拓扑排序序列来求解所有可能的排序数目。

其中,第一部分事实上还是比较好实现的,关键在于第二部分,数学的部分偏多一点。

我们假设某一棵树的根节点 r 0 r_0 r0包含 k k k个直接的子节点(记为 r 1 r_1 r1 r k r_k rk),每个子节点展开的子树的大小(即所有的节点数目)分别为 s 1 s_1 s1 s k s_k sk,那么,我们可以很快推导得到,所有关于这棵树的拓扑排序数目为:

f ( r 0 ) = ( ∑ i = 1 k s i ) ! Π i = 1 k ( s i ! ) ⋅ Π i = 1 k f ( r i ) f(r_0) = \frac{(\sum_{i=1}^{k}{s_i})!}{\Pi_{i=1}^{k}(s_i!)} \cdot\Pi_{i=1}^{k}f(r_i) f(r0)=Πi=1k(si!)(i=1ksi)!Πi=1kf(ri)

这个公式也很好解释,首先当成完全有序排列,此时共有 ( ∑ i = 1 k s i ) ! (\sum_{i=1}^{k}{s_i})! (i=1ksi)!可能的排序方法,然后由于每一个子树事实上都是一个拓扑序列,他们内部的排序数目不能够使用全排列,而应该修改为其拓扑排序的数目,因此,我们要对结果乘上一个修正因子 f ( r i ) s i ! \frac{f(r_i)}{s_i!} si!f(ri),遍历 r 0 r_0 r0所有的子节点即可得到上述推导公式。

可以看到,由此,最终的答案就可以通过一个递推函数快速地给出来。

但是,需要注意的是,由于这里我们需要对 1 0 9 + 7 10^9+7 109+7进行同余操作,因此,我们还需要对我们的求解公式进行一定的调整,将除法操作转换为乘法操作,这个可以通过乘法逆元进行实现,而python 3.9中的pow函数可以快速地实现这个功能,只要计算pow(a, -1, mod)就可以快速地得到a关于mod的乘法逆元。

综上,我们就可以最终得到上述问题的解答了。

2. 代码实现

给出python代码实现如下:

class Solution:
    def waysToBuildRooms(self, prevRoom: List[int]) -> int:
        MOD = 10**9+7
        n = len(prevRoom)
        
        def get_topological_seq(prevRoom):
            deg = Counter(prevRoom)
            nodes = [u for u in range(n) if u not in deg]
            i, m = 0, len(nodes)
            while i < m:
                u = nodes[i]
                v = prevRoom[u]
                deg[v] -= 1
                if v != -1 and deg[v] == 0:
                    nodes.append(v)
                    m += 1
                i += 1
            return nodes
        
        def get_subtree_size(nodes, prevRoom):
            sizes = [1 for _ in range(n)]
            for u in nodes[:-1]:
                sizes[prevRoom[u]] += sizes[u]
            return sizes
        
        def get_graph(prevRoom):
            graph = defaultdict(list)
            for u, v in enumerate(prevRoom):
                graph[v].append(u)
            return graph
        
        def get_factorial(n):
            f = [1 for _ in range(n+1)]
            for i in range(2, n+1):
                f[i] = (f[i-1] * i) % MOD
            g = [pow(x, -1, MOD) for x in f]
            return f, g
        
        nodes = get_topological_seq(prevRoom)
        sizes = get_subtree_size(nodes, prevRoom)
        graph = get_graph(prevRoom)
        f, g = get_factorial(n)
        dp = [f[sizes[i]-1] for i in range(n)]
        for u in nodes:
            if graph[u] == []:
                continue
            for v in graph[u]:
                dp[u] = (dp[u] * dp[v] * g[sizes[v]]) % MOD
        return dp[0]

提交代码评测得到:耗时3928ms,占用内存55MB。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值