---
# System prepended metadata

title: Algorithm - Medium
tags: [HackerRank]

---

# Algorithm - Medium
###### tags: `HackerRank`

## The Coin Change Problem (DP)
- 題目
![](https://i.imgur.com/vXBU7lc.png)
![](https://i.imgur.com/ZcWGSk0.png)

- 想法
:::info
- 假設使用m種幣值組合成n元的方法數可表示成 $f(m, n)$
    則 $f(m, n) = f(m-1, n) + f(m, n-C_m)$
    其中$C_i$代表第$i$種幣值

- 依序求出各種$f(i, j)$的值並記錄，就可以算出目標

```
Note: 使用遞迴會造成大量Overhead，時間複雜度($O(f(n))$)會大幅增加，因此應該避免使用`
```
```c=
//遞迴版本
long getWays(int n, int c_count, long* c) {
    if (n == 0) 
        return 1;
    
    if (n < 0)
        return 0;
        
    if (c_count <= 0 && n > 0)
        return 0;
        
    return getWays(n, c_count -1, c) + getWays(n - c[c_count - 1], c_count, c);
}

```
:::


```c=
//DP版本
long storage[51][251];

long getWays(int n, int m, long* c) {
    for (int i = 0; i < m+1; i++) {
        storage[i][0] = 1; 
        //printf("%d ", storage[i][0]);
    }
    
    for (int j = 1; j < n+1; j++) {
        storage[0][j] = 0;
        //printf("%d ", storage[0][j]);
        
    }
    
    for (int k = 1; k < m+1; k++) {
        for (int l = 1; l < n + 1; l++) {  
            long y = (l-c[k-1] >= 0) ? storage[k][l-c[k-1]]:0;
            storage[k][l] = storage[k-1][l] + y;
            //printf("storge[%d][%d] = %d ", k, l, storage[k][l]);
        }
        
    }
/*
    for (int i = 0; i < m+1; i++) {
        for (int j = 0; j < n+1; j++)
            printf("%d ", storage[i][j]);
    }
*/
    return storage[m][n];
}
```
- 分析
    - 時間複雜度 $O(mn)$
    - 空間複雜度 $O(mn)$


## Equal
- 題目
![](https://i.imgur.com/Tc9JdCt.png)
:::success
若有n個人，每一輪給予n-1個人{1,2,5}個，使得最後大家個數相同，求最少輪數
:::
- 想法
:::info
- 每輪可給n-1人{1,2,5}個，相當於可以收回其中一人{1,2,5}個
- 因為有"+1"的選項，因此最後的個數可以是任何數
- 考慮所有人與最小值的差值
    - ex. {2,3,7}最小值為2, 差值為{0,1,5}
        - 第一輪, 第三位-5 -> {0,1,0}
        - 第二輪, 第二位-1 -> {0,0,0}
        - 因此最少需要2輪
    - 例外 {2,6,6}最小值為2, 差值為{0,4,4}
        1. 由上述方法
            - 第二輪, 第二位-2 -> {0,2,4}
            - 第二輪, 第二位-2 -> {0,0,4}
            - 第三輪, 第三位-2 -> {0,0,2}
            - 第四輪, 第三位-2 -> {0,0,0}
            - 因此最少需要4輪...嗎?
        2. 如果減少最小值=1, 差值為{1,5,5}
            - 第一輪, 第一位-1 -> {0,5,5}
            - 第二輪, 第二位-5 -> {0,0,5}
            - 第三輪, 第三位-5 -> {0,0,0}
            - 只需要3輪就可以完成
    - 出現例外的狀況是當**差值少於5**時會變成先減掉2, 造成如果需要減掉4就會需要2輪,但其實也可以先把最小值減1, 再減5, 雖然一樣是兩輪, 但如果出現多個同樣差值一來一往就會需要更多輪
        - 因此還需要考慮 $max(最小值-4, 0)$到最小值的狀況
            - ex. 最小值為2時需要考慮{2,1,0}三種狀況
            - ex. 最小值為7時需要考慮{7,6,5,4,3}五種狀況
:::

```c=
int equal(int arr_count, int* arr) {
    
    // find mininum
    int min = arr[0];
    for (int i = 0; i < arr_count; i++) {
        if (arr[i] < min) {
            min = arr[i];
        }
    }
    
    //calc difference
    int diff[arr_count];
    int possibility[5] = {-1};
    for (int j = min; j >= ((min-4 > 0) ? (min-4):0); j--) {
        long count = 0;
        for (int i = 0; i < arr_count; i++) {
            diff[i] = arr[i] - j;
            count += diff[i]/5;     //-5
            count += (diff[i]%5)/2; //-2
            count += (diff[i]%5)%2; //-1
        }
        possibility[j%5] = count;
    }
    
    int ans = possibility[0];
    for (int i = 1; i < 5; i++) {
        if (possibility[i] > 0 && possibility[i] < (unsigned)ans)
            ans = possibility[i];
    }
    return ans;
}
```

- 分析
`Note: Test Case 15沒有過...`
    - 時間複雜度: $O(n)$
    - 空間複雜度



##
- 題目

- 想法
:::info
:::

```
```

- 分析
    - 時間複雜度
    - 空間複雜度