算法總結 - 數組 -貪心算法

1007. Minimum Domino Rotations For Equal Row

題目鏈接
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:

![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200501032145664.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JlZ2luYTE0,size_16,color_FFFFFF,t_70)


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.
 

Note

1 <= A[i], B[i] <= 6
2 <= A.length == B.length <= 20000


Abstract
有兩行骰子, 每行個數一樣多
可以把兩行骰子在某個index上的位置互換
求最少經過多少次操作以後,可以讓兩行骰子裏面的某一行的值都是一樣的

Idea
貪心,檢查數組裏每一個元素,儘量選擇用較少的反轉就能達到目的的元素

Question to ask
在什麼情況下可以確認某個骰子的值可以達到目標

Solution
維護三個map,

  • 一個記錄第一行篩子中某數值出現的次數(mapA)
  • 一個記錄第二行篩子中出現數值的次數
  • 最後一個記錄某一個數值在第一行和第二行的index相等的次數(same)
    那麼如果某一個數值的骰子可以通過交換同一列的骰子而達到都在一行的目的那麼它必須滿足一下的條件:
    mapA.get(i) + mapB.get(i) - same.get(i) == A.length
    之後就選擇比較小的交換次數(min(mapA.get(i), mapB.get(i))),然後全局更新最小值即可。

Time Complexity
O(n)

Space Complexity
O(n)

Code

public int minDominoRotations(int[] A, int[] B) {
    Map<Integer, Integer> mapA = new HashMap<>();
    Map<Integer, Integer> mapB = new HashMap<>();
    Map<Integer, Integer> same = new HashMap<>();

    int min = Integer.MAX_VALUE;
    
    for (int i = 0; i < A.length; i++){
        mapA.put(A[i], mapA.getOrDefault(A[i], 0) + 1);
        mapB.put(B[i], mapB.getOrDefault(B[i], 0) + 1);
        if (A[i] == B[i]) same.put(B[i], same.getOrDefault(B[i], 0) + 1);
        //m1
        if (mapA.getOrDefault(A[i], 0) == A.length || B.length == mapB.getOrDefault(B[i], 0)){
            return 0;
        }
    }
    
    for (int i = 0; i < A.length; i++){
        // m2
        int cnt = mapA.get(A[i]) + mapB.getOrDefault(A[i], 0) - same.getOrDefault(A[i], 0);
        if (cnt == A.length && mapA.containsKey(A[i]) && mapB.containsKey(A[i])) {
            min = Math.min(min, Math.min(mapA.get(A[i]), mapB.get(A[i])) - same.getOrDefault(A[i], 0));
        }
    }
    return min == Integer.MAX_VALUE? -1 : min;
}

Mistake
1:如果input數組本來就有一行的篩子數相同,要進行檢查short cut
2. 要麼使用 map.getOrDefault() 要麼檢查map.containsKey(),避免出現null point情況

Summary
需要有抽象思維,把問題全局化和數學化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章