LeetCode 第136场双周赛个人题解

Q1. 求出胜利玩家的数目

原题链接

Q1. 求出胜利玩家的数目

思路分析

直接模拟

时间复杂度:O(N)

AC代码

class Solution {
public:
    int winningPlayerCount(int n, vector<vector<int>>& pick) {
        unordered_map<int, unordered_map<int, int>> cnt;
        for (auto& v : pick) {
            cnt[v[0]][v[1]] ++;
        }
        int res = 0;
        for (auto& [x, u] : cnt) {
            for (auto [c, d] : u) {
                if (x == 0 || d > x) {
                    ++ res;
                    break;
                }
            }
        }
        return res;
    }
};

Q2. 最少翻转次数使二进制矩阵回文 I

原题链接

Q2. 最少翻转次数使二进制矩阵回文 I

思路分析

直接贪心就行,计算原矩阵和转置矩阵的每一行的不同的两两对称位置的数目,取小的那个

时间复杂度:O(MN)

AC代码

class Solution:
    def minFlips(self, grid: List[List[int]]) -> int:
        res1 = 0
        for row in grid:
            n = len(row)
            l, r = 0, n - 1
            while l < r:
                res1 += 1 if row[l] != row[r] else 0
                l += 1
                r -= 1
        
        grid = list(zip(*grid))
        res2 = 0
        for row in grid:
            n = len(row)
            l, r = 0, n - 1
            while l < r:
                res2 += 1 if row[l] != row[r] else 0
                l += 1
                r -= 1
        return min(res1, res2)

Q3. 最少翻转次数使二进制矩阵回文 II

原题链接

Q3. 最少翻转次数使二进制矩阵回文 II

思路分析

思维+分组背包

左上左下右上右下关于原点对称,所以矩阵只要满足回文,这四部分中1的数目一定是4的倍数

我们只需考虑行列为奇数的时候横对称轴和竖对称轴的情况

同样对两个对称轴的两两对称位置遍历,他们最终的结果要么是两个1要么是两个0,两个0的代价就是2 - 他们的和,两个1的代价也是2 - 他们的和

我们发现这就是一个分组背包问题,最多(n + m) / 2个组,每组内2个物品,背包容量为4

我们处理完四个对称部分的调整次数后,对横对称轴和竖对称轴求分组背包即可

时间复杂度:O(NM + N + M)

AC代码

class Solution:
    def minFlips(self, grid: List[List[int]]) -> int:
        res = c = 0
        m, n = len(grid), len(grid[0])
        buf = []
        res = 0
        for i in range(m // 2):
            for j in range(n // 2):
                s = grid[i][j] + grid[m - 1 - i][j] + grid[i][n - 1 - j] + grid[m - 1 - i][n - 1- j]
                res += min(4 - s, s)
        if m % 2:
            row = grid[m // 2]
            l, r = 0, n - 1
            while l < r:
                s = row[l] + row[r]
                buf.append([[0, s], [2, abs(2 - s)]])
                l += 1
                r -= 1
        if n % 2:
            l, r = 0, m - 1
            while l < r:
                s = grid[l][n // 2] + grid[r][n // 2]
                buf.append([[0, s],  [2, abs(2 - s)]])
                l += 1
                r -= 1
        if m % 2 and n % 2:
            t = grid[m // 2][n // 2]
            buf.append([[t, 0], [0, t]])
            
        if not buf:
            return res

        f = [inf, inf, inf, inf]
        for r in buf:
            nf = f.copy()
            for j in range(4):
                mi = inf
                for x, v in r:
                    t = ((j - x) % 4 + 4) % 4
                    if nf[x % 4] == inf:
                        f[x % 4] = min(f[x % 4], v)
                    mi = min(nf[t] + v, mi)

                if nf[j] == inf:
                    f[j] = min(f[j], mi)
                else:
                    f[j] = mi
                    
        return res + f[0]

Q4. 标记所有节点需要的时间

原题链接

Q4. 标记所有节点需要的时间

思路分析

换根dp

很明显的换根dp,为什么呢?

0时刻从根节点开始标记所需时间取决于根节点的孩子和根节点的奇偶性

而且题目要我们求出每个结点作为根时的情况,自然想到换根dp

先一次dfs0预处理d[],d[u] 代表0时刻开始标记u,u所在子树全部搞定的时间

然后dfs1 进行换根

求u 的儿子结点中 d[v] + (v & 1 ? 1 : 2)的最大值和次大值fi, se

那么我们换根为v时,如果d[v] + (v & 1 ? 1 : 2) == fi, 那么换根后d[u] = se,否则为fi

时间复杂度:O(N)

AC代码

class Solution:
    def timeTaken(self, edges: List[List[int]]) -> List[int]:
        n = len(edges) + 1
        adj = [[] for _ in range(n)]
        for x, y in edges:
            adj[x].append(y)
            adj[y].append(x)

        d = [0] * n

        def dfs0(u: int, p: int) -> None:
            for v in adj[u]:
                if v == p:
                    continue
                dfs0(v, u)
                d[u] = max(d[u], d[v] + (1 if v % 2 else 2))
        dfs0(0, -1)
        ans = [0] * n
        def dfs1(u: int, p: int) -> None:
            fi, se = 0, 0
            for v in adj[u]:
                if d[v] + (1 if v % 2 else 2) > fi:
                    se = fi
                    fi = d[v] + (1 if v % 2 else 2)
                elif d[v] + (1 if v % 2 else 2) > se:
                    se = d[v] + (1 if v % 2 else 2)

            ans[u] = fi
            
            for v in adj[u]:
                if v == p:
                    continue
                d[u] = se if d[v] + (1 if v % 2 else 2) == fi else fi
                dfs1(v, u)
        dfs1(0, -1)
        return ans

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值