文章

[LeetCode] 每日一题 1007. 行相等的最少多米诺旋转(思考题)

题目描述

在一排多米诺骨牌中,tops[i]bottoms[i] 分别代表第 i 个多米诺骨牌的上半部分和下半部分。(一个多米诺是两个从 1 到 6 的数字同列平铺形成的 —— 该平铺的每一半上都有一个数字。)

我们可以旋转第 i 张多米诺,使得 tops[i]bottoms[i] 的值交换。

返回能使 tops 中所有值或者 bottoms 中所有值都相同的最小旋转次数。

如果无法做到,返回 -1.

题目链接

https://leetcode.cn/problems/minimum-domino-rotations-for-equal-row

示例输入

示例 1

输入:tops = [2,1,2,4,2,2], bottoms = [5,2,6,2,3,2]
输出:2
解释: 
图一表示:在我们旋转之前, tops 和 bottoms 给出的多米诺牌。 
如果我们旋转第二个和第四个多米诺骨牌,我们可以使上面一行中的每个值都等于 2,如图二所示。 

示例 2

输入:tops = [3,5,1,2,3], bottoms = [3,6,3,3,4]
输出:-1
解释: 在这种情况下,不可能旋转多米诺牌使一行的值相等。

提示

  • 2 <= tops.length <= 2 * 10^4

  • bottoms.length == tops.length

  • 1 <= tops[i], bottoms[i] <= 6

解题思路

这道题其实不是典型的模拟题,而是一道判断可行性 + 目标选择 + 条件计数的组合题,思路上还是比较直接的。我一开始也没有套用什么复杂的算法,而是结合题目本质做了简化。

我们注意到,最终想让 topsbottoms 全部变成同一个值。这个值必然是 tops[0]bottoms[0](否则无法构成全相等)。因此我们可以分别尝试这两个数作为目标值,然后通过一个辅助函数 change 来判断:

  • 如果当前这一位已经是目标值,无需旋转;

  • 如果另一面是目标值,需要旋转一次;

  • 如果两面都不是目标值,说明这个目标根本不可能达成,直接返回 -1

最终我们对这两种可能情况分别取最小值,得到结果。

代码实现

class Solution {
    public int minDominoRotations(int[] tops, int[] bottoms) {
        int first = change(tops, bottoms, tops[0]);
        if (first == -1) {
            return change(tops, bottoms, bottoms[0]);
        }
        int second = change(tops, bottoms, bottoms[0]);
        if (second == -1) {
            return first;
        }
        return Math.min(first, second);
    }

    private int change(int[] tops, int[] bottoms, int target) {
        int top = 0;
        int bottom = 0;
        int n = tops.length;
        for (int i = 0; i < n; i++) {
            if (tops[i] != target && bottoms[i] != target) {
                return -1;
            }
            if (tops[i] != target) {
                top++;
            } else if (bottoms[i] != target) {
                bottom++;
            }
        }
        return Math.min(top, bottom);
    }
}

复杂度分析

  • 时间复杂度:O(n)
    尝试两个目标值,每次遍历一次数组,整体是线性时间

  • 空间复杂度:O(1)
    只用了常数级别的变量计数,没有额外空间开销

总结

这题的核心其实是判断“是否可达”和“哪个更优”。没有过多复杂的数据结构,完全是靠对问题的正确建模和细致的条件判断来解的。我在写的时候也一度担心情况多不好处理,但把目标值限制在 top[0]bottom[0] 后,整个逻辑就非常清晰了。通过这种方式,能训练我们在处理数组题时的目标归纳和条件思维能力,属于典型的“思考题”

希望这篇分享能为你带来启发!如果你有任何问题或建议,欢迎在评论区留言,与我共同交流探讨。

License:  CC BY 4.0