# 2020q3 Homework4 (quiz4)
contributed by < `CW-B-W` >
###### tags: `sysprog2020`
## Outline
[TOC]
## 測驗`1`
### hammingDistance
* OP = `^`
* xor 會將 x 與 y 間相同的 bits 設為 `0` , 不同的 bits 設為 `1`
* 再利用 popcount 算出 x 與 y 間有幾個不同的 bits 即可
```CPP=
int hammingDistance(int x, int y) {
return __builtin_popcount(x OP y);
}
```
#### [Leetcode 477. Total Hamming Distance](https://leetcode.com/problems/total-hamming-distance/)
## 測驗`2`
### LeetCode 1483. Kth Ancestor of a Tree Node
* 倍增法求 LCA
* 此法可用來輔助找尋 [`Second Minimum Spanning Tree`](https://sites.google.com/view/ntpuprog/%E8%AA%B2%E7%A8%8B%E8%B3%87%E6%BA%90%E8%88%87%E7%B7%B4%E7%BF%92%E6%B8%85%E5%96%AE/2019/%E6%9C%80%E5%B0%8F%E7%94%9F%E6%88%90%E6%A8%B9/%E6%AC%A1%E5%B0%8F%E7%94%9F%E6%88%90%E6%A8%B9)
* 主要概念:我的 `第 2^k 個 parent` 的 `第 2^k 個 parent` , 就是我的 `第 2^(k+1) 個 parent`
* 本質上為 `DP (Dynamic Programming)`
* AAA = `int **parent`
* 由 `line 17` 可知 parent 被當作 `2D-array` 使用
* BBB = `(-1)`
* 此處實作找尋 `我的第 2^j 個 parent`
* 情況一 : `我的第 2^(j-1) 個 parent` 不存在 (i.e. 超出 root) , 則 `我的第 2^j 個 parent` 也不存在
* 特判此狀況是為了防止
```CPP=
obj->parent[obj->parent[i][j - 1]][j - 1];
```
變成
```CPP=
obj->parent[-1][j - 1];
```
導致出錯
* 情況二 : `我的第 2^(j-1) 個 parent` 存在, 則 `我的第 2^j 個 parent` 為 `我的第 2^(j-1) 個 parent` 的 `第 2^(j-1) 個 parent`
* CCC = `1 << i`
* `求 k 個 parent`
* 先舉例 `k = 5`
* `第 5 個(3'b101) parent` 為 `第 1 個(3'b001) parent` 的 `第 4 個(3'b100) parent`
* 由上例可知,將 k 表示為多個 `第 2^i 個 parent` 的組合,可快速利用 `parent[][]` 求出 `第 k 個 parent`
```CPP=
#include <stdlib.h>
typedef struct {
AAA;
int max_level;
} TreeAncestor;
TreeAncestor *treeAncestorCreate(int n, int *parent, int parentSize)
{
TreeAncestor *obj = malloc(sizeof(TreeAncestor));
obj->parent = malloc(n * sizeof(int *));
int max_level = 32 - __builtin_clz(n) + 1;
for (int i = 0; i < n; i++) {
obj->parent[i] = malloc(max_level * sizeof(int));
for (int j = 0; j < max_level; j++)
obj->parent[i][j] = -1;
}
for (int i = 0; i < parentSize; i++)
obj->parent[i][0] = parent[i];
for (int j = 1;; j++) {
int quit = 1;
for (int i = 0; i < parentSize; i++) {
obj->parent[i][j] = obj->parent[i][j + BBB] == -1
? -1
: obj->parent[obj->parent[i][j - 1]][j - 1];
if (obj->parent[i][j] != -1) quit = 0;
}
if (quit) break;
}
obj->max_level = max_level - 1;
return obj;
}
int treeAncestorGetKthAncestor(TreeAncestor *obj, int node, int k)
{
int max_level = obj->max_level;
for (int i = 0; i < max_level && node != -1; ++i)
if (k & (CCC))
node = obj->parent[node][i];
return node;
}
void treeAncestorFree(TreeAncestor *obj)
{
for (int i = 0; i < obj->n; i++)
free(obj->parent[i]);
free(obj->parent);
free(obj);
}
```
### 延伸問題 `2` - 減少記憶體浪費
```CPP=
TreeAncestor *treeAncestorCreate(int n, int *parent, int parentSize)
{
TreeAncestor *obj = malloc(sizeof(TreeAncestor));
int max_level = 32 - __builtin_clz(n) + 1;
obj->parent = malloc(max_level * sizeof(int *));
/* obj->parent[j][i]: The (2^j)-th ancestor of i */
obj->parent[0] = malloc(n * sizeof(int));
for (int i = 0; i < n; i++)
obj->parent[0][i] = parent[i];
for (int j = 1;; j++) {
obj->parent[j] = malloc(n * sizeof(int));
/* cnt is used to count the number of nodes who have the (2^j)-th ancestor */
int cnt = 0;
for (int i = 0; i < parentSize; i++) {
obj->parent[j][i] = obj->parent[j-1][i] == -1
? -1
: obj->parent[j-1][obj->parent[j-1][i]];
if (-1 != obj->parent[j][i]) cnt++;
}
/* If none node has the (2^j)-th ancestor, we don't need to go deeper. */
if (!cnt) break;
}
obj->max_level = max_level - 1;
return obj;
}
```
## 測驗`3`
### FizzBuzz
* KK1 = `div5`
* 用湊得強行湊出來
* KK2 = `div3`
* 用湊得強行湊出來
* KK3 = `2`
* 用湊得強行湊出來
```cpp=
#define MSG_LEN 8
static inline bool is_divisible(uint32_t n, uint64_t M) {
return n * M <= M - 1;
}
static uint64_t M3 = UINT64_C(0xFFFFFFFFFFFFFFFF) / 3 + 1;
static uint64_t M5 = UINT64_C(0xFFFFFFFFFFFFFFFF) / 5 + 1;
int main(int argc, char *argv[]) {
for (size_t i = 1; i <= 100; i++) {
uint8_t div3 = is_divisible(i, M3);
uint8_t div5 = is_divisible(i, M5);
unsigned int length = (2 << div3) << div5;
char fmt[MSG_LEN + 1];
strncpy(fmt, &"FizzBuzz%u"[(MSG_LEN >> KK1) >> (KK2 << KK3)], length);
fmt[length] = '\0';
printf(fmt, i);
printf("\n");
}
return 0;
}
```
## 測驗`4`
### PAGE_QUEUES
* CASES = {`3`, `5`, `7`}
* `CASES` 裡的數字 `Least Significant Bit` 必為 `1`
* 因為 `divident >>= ffs32(divident)` 將 trailing zeros 都移除了
```cpp=
#include <stdint.h>
#define ffs32(x) ((__builtin_ffs(x)) - 1)
size_t blockidx;
size_t divident = PAGE_QUEUES;
blockidx = offset >> ffs32(divident);
divident >>= ffs32(divident);
switch (divident) {
CASES
}
```