[LeetCode] 每日一题 1007. 行相等的最少多米诺旋转(思考题)
题目描述
在一排多米诺骨牌中,tops[i] 和 bottoms[i] 分别代表第 i 个多米诺骨牌的上半部分和下半部分。(一个多米诺是两个从 1 到 6 的数字同列平铺形成的 —— 该平铺的每一半上都有一个数字。)
我们可以旋转第 i 张多米诺,使得 tops[i] 和 bottoms[i] 的值交换。
返回能使 tops 中所有值或者 bottoms 中所有值都相同的最小旋转次数。
如果无法做到,返回 -1.
题目链接
示例输入
示例 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
解题思路
这道题其实不是典型的模拟题,而是一道判断可行性 + 目标选择 + 条件计数的组合题,思路上还是比较直接的。我一开始也没有套用什么复杂的算法,而是结合题目本质做了简化。
我们注意到,最终想让 tops 或 bottoms 全部变成同一个值。这个值必然是 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] 后,整个逻辑就非常清晰了。通过这种方式,能训练我们在处理数组题时的目标归纳和条件思维能力,属于典型的“思考题”
希望这篇分享能为你带来启发!如果你有任何问题或建议,欢迎在评论区留言,与我共同交流探讨。