1. 问题描述:
在一排多米诺骨牌中,A[i] 和 B[i] 分别代表第 i 个多米诺骨牌的上半部分和下半部分。(一个多米诺是两个从 1 到 6 的数字同列平铺形成的 —— 该平铺的每一半上都有一个数字。)
我们可以旋转第 i 张多米诺,使得 A[i] 和 B[i] 的值交换。返回能使 A 中所有值或者 B 中所有值都相同的最小旋转次数。如果无法做到,返回 -1.
示例 1:
输入:A = [2,1,2,4,2,2], B = [5,2,6,2,3,2]
输出:2
解释:
图一表示:在我们旋转之前, A 和 B 给出的多米诺牌。
如果我们旋转第二个和第四个多米诺骨牌,我们可以使上面一行中的每个值都等于 2,如图二所示。
示例 2:
输入:A = [3,5,1,2,3], B = [3,6,3,3,4]
输出:-1
解释:
在这种情况下,不可能旋转多米诺牌使一行的值相等。
提示:
1 <= A[i], B[i] <= 6
2 <= A.length == B.length <= 20000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-domino-rotations-for-equal-row
2. 思路分析:
① 因为最终需要判断A或者B中牌通过旋转之后的全部值是否是相等的,所以一开始想到的是哈希表(字典)来记录各个数字出现的位置,可以声明两个字典来分别统计A与B中1-6数字出现的位置,求解他们的并集判断并集的长度是否大于等于A的长度,假如相等说明是可以通过翻转使得最终牌的所有元素是相等的,然后我们求解两个字典记录的当前数字出现位置的交集,因为这些位置是不需要通过交换的,在求解最短长度的时候就可以减去不需要交换的位置的长度从而得到较短的旋转次数
② 除了①中的方法之外,还可以使用贪心的思路解决(感觉有的时候需要多思考一下可能会想到更优的解决思路),我们知道最终A或者B的牌通过翻转之后全部元素可能是相等的,所以我们只需要判断A或者B中的第一张牌是否能够通过翻转使得最终的元素全部是相等的即可,因为第一张牌不可以翻转得到那么最终肯定不能够是否全部牌是相等的,想清楚这一点剩下来的就简单了
3. 代码如下:
两个字典记录数字出现的位置:
import collections
from typing import List
class Solution:
def minDominoRotations(self, A: List[int], B: List[int]) -> int:
dicA, dicB = collections.defaultdict(list), collections.defaultdict(list)
# 字典分别记录数字出现的位置
for i in range(len(A)):
dicA[A[i]].append(i)
dicB[B[i]].append(i)
res = len(A) + 1
for i in range(1, 7):
if i in dicA:
n1, n2 = dicA[i], dicB[i]
if len(set(n1 + n2)) >= len(A):
# 求解两个集合的交集
l = list(set(n1) & set(n2))
# 减去不需要交换元素的长度
res = min(res, len(n1) - len(l), len(n2) - len(l))
return -1 if res == len(A) + 1 else res
官方贪心代码:
from typing import List
class Solution:
def minDominoRotations(self, A: List[int], B: List[int]) -> int:
def check(x):
rotations_a = rotations_b = 0
for i in range(n):
if A[i] != x and B[i] != x:
return -1
elif A[i] != x:
rotations_a += 1
elif B[i] != x:
rotations_b += 1
return min(rotations_a, rotations_b)
n = len(A)
rotations = check(A[0])
if rotations != -1 or A[0] == B[0]:
return rotations
else:
return check(B[0])