Minimum Domino Rotations For Equal Row LT1007

时间:2022-08-03 19:13:43

In a row of dominoes, A[i] and B[i] represent the top and bottom halves of the i-th domino.  (A domino is a tile with two numbers from 1 to 6 - one on each half of the tile.)

We may rotate the i-th domino, so that A[i] and B[i] swap values.

Return the minimum number of rotations so that all the values in A are the same, or all the values in B are the same.

If it cannot be done, return -1.

 

Example 1:

Minimum Domino Rotations For Equal Row LT1007

Input: A = [2,1,2,4,2,2], B = [5,2,6,2,3,2] Output: 2 Explanation:  The first figure represents the dominoes as given by A and B: before we do any rotations. If we rotate the second and fourth dominoes, we can make every value in the top row equal to 2, as indicated by the second figure. 

Example 2:

Input: A = [3,5,1,2,3], B = [3,6,3,3,4] Output: -1 Explanation:  In this case, it is not possible to rotate the dominoes to make one row of values equal. 

 Idea 1. Bruteforce, swap or not swap(0-1), similar to subsets problem, typical backtracking

Time complexity: O(n2^n)

Space complexity: O(1)

 1 class Solution {
 2     private void swap(int[] A, int[] B, int pos) {
 3         int temp = A[pos];
 4         A[pos] = B[pos];
 5         B[pos] = temp;
 6     }
 7     private boolean isEqual(int[] A) {
 8         for(int i = 1; i < A.length; ++i) {
 9             if(A[i] != A[i-1]) {
10                 return false;
11             }
12         }
13         return true;
14     }
15     
16     private void helper(int[] A, int[] B, int pos, int currCnt, int[] cnt) {
17         if(pos == A.length) {
18             if(isEqual(A) || isEqual(B)) {
19                 cnt[0] = Math.min(cnt[0], currCnt);
20             }   
21             return;
22         }
23         
24         if(A[pos] != B[pos]) {
25             swap(A, B, pos);
26             helper(A, B, pos+1, currCnt+1, cnt);
27             swap(A, B, pos);
28         }
29         
30         helper(A, B, pos+1, currCnt, cnt);  
31     }
32     public int minDominoRotations(int[] A, int[] B) {
33         int[] cnt = new int[1];
34         cnt[0] = Integer.MAX_VALUE;
35         helper(A, B, 0, 0, cnt);
36         return cnt[0] == Integer.MAX_VALUE? -1: cnt[0];   
37     }
38 }

Idea 2. 有时候具体的题目要求更restrict, 反而简化了问题,这题要求all elments equal in A[i] or B[i], 如果我们知道交换后的结果数组的相同数,只能是四种:A-> { A[0], B[0] }, B-> { A[0], B[0] },

make A be all A[0] or B[0]

make B be all A[0] or B[0]

然后计算最小步数

Time complexity: O(n), 4 times scan

Space complexity: O(1)

 1 class Solution {
 2     int helper(int[] A, int[] B, int target) {
 3         int cnt = 0;
 4         for(int i = 0; i < A.length; ++i) {
 5             if(A[i] != target) {
 6                 if(B[i] == target) {
 7                     ++cnt;
 8                 }
 9                 else {
10                     return Integer.MAX_VALUE;
11                 }
12             }
13         }
14         return cnt;
15     }
16     public int minDominoRotations(int[] A, int[] B) {
17            int result = Math.min(helper(A, B, A[0]),
18                                  helper(A, B, B[0]));
19            result = Math.min(result,
20                              Math.min(helper(B,A, B[0]),
21                                      helper(B, A, A[0])));
22            return result == Integer.MAX_VALUE? -1: result;
23     }
24 }

Idea 2.a 网上看到的,一次遍历同时计算A,B所需的步数

Time complexity: O(n), 2 times scan

Space comlexity: O(1)

 1 class Solution {
 2     private int helper(int[] A, int[] B, int target) {
 3         int swapA = 0, swapB = 0;
 4         for(int i = 0; i < A.length; ++i) {
 5             if(A[i] != target && B[i] != target) {
 6                 return Integer.MAX_VALUE;
 7             }
 8             
 9             if(A[i] != target){
10                 ++swapA;
11             }
12             else if(B[i] != target) {
13                 ++swapB;
14             }
15         }
16         
17         return Math.min(swapA, swapB);
18     }
19     public int minDominoRotations(int[] A, int[] B) {
20            int result = Math.min(helper(A, B, A[0]),
21                                 helper(A, B, B[0]));
22         
23            return result == Integer.MAX_VALUE? -1: result;
24     }
25 }

Idea 3. intersection set of {A{i}, B{i}}, 为了完成swap可以让数组相等,each position in either A or B should have the element, we can use set.retailAll, the steps = A.length - countA[A[i]]

Time complexity: O(n)

Space complexity: O(1), HashMap + HashSet

 1 class Solution {
 2     public int minDominoRotations(int[] A, int[] B) {
 3           Set<Integer> candidates = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6));
 4           int[] countA = new int[7];
 5           int[] countB = new int[7];
 6         
 7           for(int i = 0; i < A.length; ++i) {
 8               ++countA[A[i]];
 9               ++countB[B[i]];
10               candidates.retainAll(new HashSet<>(Arrays.asList(A[i], B[i])));
11           }
12         
13            for(int val: candidates) {
14                return Math.min(A.length - countA[val], A.length - countB[val]);
15            }
16         
17            return -1;
18     }
19 }

用数组代表set

 1 class Solution {
 2     public int minDominoRotations(int[] A, int[] B) {
 3           int[] countA = new int[7];
 4           int[] countB = new int[7];
 5           int[] common = new int[7];
 6         
 7           for(int i = 0; i < A.length; ++i) {
 8               ++countA[A[i]];
 9               ++countB[B[i]];
10               if(A[i] == B[i]) {
11                   ++common[A[i]];
12               }
13           }
14         
15           for(int i = 1; i < 7; ++i) {
16               if(countA[i] + countB[i] - common[i] >= A.length) {
17                   return Math.min(A.length - countA[i], A.length - countB[i]);
18               }
19           }
20         
21            return -1;
22     }
23 }