leetcode 2022 秋季编程大赛(个人赛)

作者: | 更新日期:

这次比赛没有遗憾,自己的能力确实无法做出最后一题了。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、背景

今年的 leetcode 秋季赛编程大赛比晚年晚一些。

想到这里我又要吐槽了, 这次的团队赛 leetcode 安排在国庆假期的最后一天,感觉大部分人都无法参加了。

回到个人赛,这次比赛 5 道题,我做出前 4 道,排名进入前百名,但是没能进去前 50 名。

最后一题想的是直接使用动态规划做,结果状态转移方程推导不出来,最后看题解发现需要二分。
这次没做出来是自己的问题。
求最值的最值是个经典的问题,确实需要二分的,自己忘记了。
既然不知道这个,看到求最值,也可以往二分方向去思考的,以后要注意了。

一、气温变化趋势

题意:给两个正数数组,数组内相邻位置的值有三种关系:大于、等于、小于。
问两个数组相同位置关系相等的最长区间是多少。

思路:数组预处理为关系,相等的关系标记为 1,否则标记为 0。
问题就转化为了最长连续 1 的个数,典型的动态规划。

二、交通枢纽

题意:给一个有向图的边列表(没告诉顶点个数),问是否有一个超级顶点,这个顶点没有出边,所有其他顶点都可以到达这个顶点。
如果存在,输出这个超级顶点。

思路:预处理边,统计每个顶点的入度与出度与顶点的个数。
如果出度为0 的顶点只有一个,再判断其他顶点到这个顶点是否都有边即可。

三、弹珠游戏

题意:给一个矩阵,矩阵的值分为四种:终止点、左转点、右转点、空白点。
现在可以从矩阵的四条边垂直射入一个珠子,问在指定步数内是否可以到达终止点。
射入有两个限制:入口的值必须是空白点,并且入口不再四个角上。
求出所有的满足条件的入口坐标。

思路:枚举所有的合法入口,记忆化搜索即可。

矩阵每个位置可能有四个方向通过,所以状态个数为矩阵大小的四倍。

注意事项:题目是问是否可以在指定步数内到达终点,可以先求出入口到达终点的步数,然后再比大小即可。

四、二叉树灯饰

题意:给一个有根二叉树,数的值为 0 和 1。
现在可以对一个子树做下面三种操作:根节点值反转、根和儿子的值反转、根和所有后代的值反转(子树)。
问最少需要多少步骤,可以把整个二叉树的值变为 0.

思路:典型的树上 DP。

有三个操作,枚举组合就是 8 种情况。

具体到每个子树时,父子的操作不存在,所以变为 4 种状态。

状态 1)不受父节点影响
状态 2)影响,根节点反转
状态 3)影响,除了根,子树都反转 状态 4) 影响,子树反转

对于每个子树的每个状态,我们枚举所有操作组合,求小答案即可。

比赛的时候,我人肉梳理出了 4*8=32 中情况,即写了这么多 if/else

赛后,推导了下状态转移方程,发现不难。
如果我比赛推导公式的话,应该排名更靠前一些。

// 001 根反转
// 010 子树反转
// 100 父子反转
int Dfs(TreeNode* root, const int flag) {
  if (root == nullptr) return 0;
  if (h[flag].count(root))  return h[flag][root];
  int& ret = h[flag][root]  = INT_MAX;
  int preOne = __builtin_popcount(flag);
  for (int mask = 0; mask < 8; mask++) {
    const int one = __builtin_popcount(mask);
    if ((one + preOne + root->val) % 2 == 1) continue;  // 奇偶性判断
    const int child = ((mask ^ flag) & 2) | (mask >> 2);
    ret = min(ret, one + Dfs(root->left, child) + Dfs(root->right, child));
  }
  return ret;
}

五、舒适的湿度

题意:给一个数组,数字代表温度,可能是升高也可能是降低。
如果数字升高或降低的含义确定时,所有子区间的和的绝对值的最大值称为波动温度。
问数字的升高与降低组合序列中,可以得到的最小的波动温度是多少。

思路:题意理解起来比较麻烦,其实就是求最大值中的最小值。
即有两个条件,条件1确定时,所有的条件2可以得到一个最大值。
现在求所有条件1里面,条件2得到的最大值的最小值。

对于这种题型,典型的做法是二分答案,判断这个答案是否成立。

在想怎么二分之前,我们先看下暴力做这道题需要怎么做。
从前到后,对于每个数字,与前缀得到的集合相加与相减,不考虑数据值的范围,得到的不同值可能就是 2^n 个。

题目中可以看到,数字最多 1000个,值的范围是 [1,1000]
可以证明,答案不会超过 2000, 即不会超过两个最大值。

这样,数据范围就降低到 2000 以内了。
这样复杂度也降低到 n^2 了。

六、最后

这次比赛题目挺好的。

第一题动态规划。
第二题都不算图论。
第三题矩阵记忆化搜索。
第四题树上DP。 第五题二分+动态规划。

最后一题我已经证明最优值不会大于 1n了,如果能想到二分的话,我应该应该就可以做出来了。
不过这道题确实有难度,没做出来也没有遗憾。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
公众号ID:tiankonguse-code

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越