leetcode
leetcode 901 ~ 950
行相等的最少多米诺旋转

行相等的最少多米诺旋转

难度:

标签:

题目描述

在一排多米诺骨牌中,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 * 104
  • bottoms.length == tops.length
  • 1 <= tops[i], bottoms[i] <= 6

代码结果

运行时间: 57 ms, 内存: 16.8 MB


/*
题目思路:
1. 找出可能的目标值,即所有牌的上半部分或下半部分的值。
2. 使用Java Stream计算需要的旋转次数。
3. 返回最小的旋转次数,如果无法实现返回-1。
*/

import java.util.stream.IntStream;

public class Solution {
    public int minDominoRotations(int[] tops, int[] bottoms) {
        int rotations = check(tops[0], tops, bottoms);
        if (rotations != -1 || tops[0] == bottoms[0]) return rotations;
        else return check(bottoms[0], tops, bottoms);
    }

    private int check(int target, int[] tops, int[] bottoms) {
        long countA = IntStream.range(0, tops.length).filter(i -> tops[i] != target && bottoms[i] == target).count();
        long countB = IntStream.range(0, tops.length).filter(i -> tops[i] == target && bottoms[i] != target).count();
        if (IntStream.range(0, tops.length).anyMatch(i -> tops[i] != target && bottoms[i] != target)) return -1;
        return (int) Math.min(countA, countB);
    }
}

解释

方法:

这道题的思路是尝试使得所有多米诺骨牌的上半部分或下半部分的数字都变成相同的。因为每个多米诺骨牌的数字范围是1到6,所以我们只需要尝试这6种可能的数字。对于每一种数字,我们遍历整个多米诺骨牌数组,如果当前多米诺的上半部分不等于这个数字,就检查其下半部分是否等于这个数字,如果是,就将旋转次数加1;同理,如果下半部分不等于这个数字,就检查上半部分并相应增加旋转次数。如果遍历完整个数组后没有中断(即没有遇到无法通过旋转使某个多米诺的两部分之一等于目标数字的情况),就更新最小旋转次数。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在检查每个多米诺骨牌的上下部分时,碰到一个无法旋转的情况就立即中断循环?
在检查过程中,如果遇到某个多米诺骨牌的上下部分都不等于目标数字且不能通过旋转达到目标,那么这个目标数字是无法通过旋转使得所有多米诺骨牌的上半部分或下半部分统一的。此时,继续检查剩余的多米诺骨牌是没有意义的,因为已经确定无法达成目标。因此,程序通过中断循环来避免无用的计算,提高效率。
🦆
在尝试1到6这6个数字时,是否可能存在对于某个数字无法通过旋转达到目标但对其他数字可以达到目标的情况?
是的,可能存在这样的情况。因为多米诺骨牌的每一半可以是1到6中的任何一个数字,对于某一个特定的数字,可能存在多米诺骨牌的上下两部分都不是这个数字,且无法通过旋转使其任一部分成为这个数字。而对于另一个数字,可能通过旋转可以实现让所有多米诺骨牌的上半部分或下半部分统一。因此,算法需要尝试所有6种可能的数字,以找到可能的最小旋转次数。
🦆
题解中旋转次数的更新逻辑是什么意思?为什么是在内层循环结束后,使用`min(a, b)`来更新最小旋转次数?
在题解中,变量`a`和`b`分别记录将多米诺骨牌上半部分或下半部分全部旋转成目标数字需要的最小旋转次数。如果在检查所有多米诺骨牌后没有中断过循环(即所有多米诺骨牌至少有一部分是目标数字或可以通过旋转成为目标数字),则说明目标数字可行。此时用`min(a, b)`更新最小旋转次数,因为我们只需要选择上半部分统一或下半部分统一的最小旋转次数。这样可以确保我们得到的是所有尝试中的最小旋转次数。
🦆
在实际应用中,如何处理当`tops`和`bottoms`数组长度不相等的情况?
在题目的假设中,`tops`和`bottoms`数组的长度应该是相等的,因为每个多米诺骨牌都有一个上半部分和一个下半部分。如果在实际应用中遇到`tops`和`bottoms`长度不相等的情况,这通常指示着输入数据有误或不完整。在这种情况下,应当首先验证输入数据的正确性和完整性。如果确认数据错误,需要进行适当的错误处理,如抛出异常或返回错误信息,而不应继续执行旋转逻辑。

相关问题