# 2020q3 Homework4 (quiz4) contributed by < [`OliveLake`](https://github.com/OliveLake) > > [quiz4 題目描述](https://hackmd.io/@sysprog/2020-quiz4) ## Q1:LeetCode [461. Hamming Distance](https://leetcode.com/problems/hamming-distance/) 兩個整數間的 Hamming distance 為其二進位的每個位元的差。請計算輸入參數兩整數 x 與 y 的 Hamming distance,例如整數 1 的二進位為 0 0 0 1,而整數 4 的二進位為 0 1 0 0,則 1 與 4 的 Hamming distance 為 2。 ```cpp int hammingDistance(int x, int y) { return __builtin_popcount(x OP y); } ``` 解題: 參數 x 和 y 作 `exclusive-or` 後,若兩者位元不同為 1 ,位元相同為 0,再利用 gcc 提供對應的內建函式:__builtin_popcount(x),計算 x^y 總共有幾個 1 ,即為 Hamming Distance 。 #### 延伸問題: 1.不使用 gcc 實作 ```cpp= int hammingDistance(int x, int y){ int i = x ^ y; int n = 0; while (i > 0) { if ((i & 1) == 1) n++; i >>= 1; } return n; } ``` 比起根據題目範圍做 31 次迴圈,先做 X^Y 可以知道哪些數字要計算距離,減少迴圈次數。再用```if ((i & 1) == 1) n++```計算每個位元的差。最後 i 再不斷右移,直到測資為零。 2.練習 [LeetCode 477. Total Hamming Distance](https://leetcode.com/problems/total-hamming-distance/) ```cpp= int totalHammingDistance(int* nums, int numsSize){ int ans = 0; for (int i = 0; i < 32; ++i) { int cnt = 0; for (int j = 0; j<numsSize; j++) { if (nums[j] & ((uint32_t)1 << i)) ++cnt; } ans += cnt * (numsSize - cnt); } return ans; } ``` 如果兩兩互取 Hamming Distance 的話,會因為測資有10000筆而超出時間。比較好的方法是,因為位元只有 0 和 1 兩種可能,從 LSB 開始分成為 0 的一堆,為 1 的一堆,分完算出距離再前進一位,這樣就只需要做 31 次迴圈( 31 個位元),最後每個位元距離加總。 第 6 行 ```if (nums[j] & ((uint32_t)1 << i)) ++cnt;``` 判斷第 i 個位元是否為 1 。第 8 行 ```res += cnt * (n - cnt);``` 總合會是 0 的數量乘上 1 的數量。 舉例測資是 2(0010)、4 (0100)、14(1110) | 位元 | 為 0 | 為 1 |距離 | -------- | -------- | -------- | -------- | | 0 | 2、4、14 | X | 0 | 1 | 4 | 2、14 | 2 | 2 | 2 | 4、14 | 2 | 3 | 2、4 | 14 |2 距離總和是 6 ![](https://i.imgur.com/EsYPigh.png) 參考 [RusselCK](https://hackmd.io/@RusselCK/sysprog2020_quiz4) 同學的寫法,改正 第 6 行```if (nums[j] & ((uint32_t)1 << i)) ++cnt;``` 為 ```cnt += nums[j] >> i & 1;```後,因為不需 if 判斷,速度可以再提升。 ![](https://i.imgur.com/DLm24GT.png) 3.研讀[錯誤更正碼簡介](https://w3.math.sinica.edu.tw/math_media/d184/18404.pdf)及[抽象代數的實務應用](https://www.math.sinica.edu.tw/www/file_upload/summer/crypt2017/data/2017/上課講義/[20170710][抽象代數的實務應用].pdf),摘錄其中 Hamming Distance 和 Hamming Weight 的描述並重新闡述,舉出實際的 C 程式碼來解說 ## Q2:[LeetCode 1483. Kth Ancestor of a Tree Node](https://leetcode.com/problems/kth-ancestor-of-a-tree-node/) ```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); } ``` ### AAA 由第 3 行開始的 struct 宣告及第 10 行的記憶體配置 ```cpp=10 TreeAncestor *obj = malloc(sizeof(TreeAncestor)); obj->parent = malloc(n * sizeof(int *)); ``` 型態是```TreeAncestor *```的 obj 指向 parent ,並且 parent 要了一段型態是```int *```的空間,因此 AAA 應為```int **parent``` ### BBB