owned this note
owned this note
Published
Linked with GitHub
# 2020q3 Homework4 (quiz4)
contributed by < ddj5523fa >
---
### 想法 & 思考
#### 測驗一
題目:
```cpp=
int hammingDistance(int x, int y) {
return __builtin_popcount(x OP y);
}
```
求x,y的hamming distance。
ANS: hamming distance經過題目上的圖片觀察也能得知: ==是每個位元的差==
所以X、Y的binary中不一樣的bit個數極為答案,而該程式碼中```__builtin_popcount```
是找binary中有幾個1,所以可以聯想到 X 跟 Y 做XOR就能得不同bit變成1。
所以, OP為 ^ <------ ==ANSWER==
##### 延伸學習2.
在測驗2第六題曾做過分別1bit、1bit的比較後再進行一些操作,加上此題題目上程式碼用XOR,讓我將數字轉成binary之後做觀察!
1.得出結論是:
數字(binary)每1bit,分別有多少0跟1的數量相乘,可得到其距離。
EX: [4,12,1]
|4|0100|
|-----|--------|
|12|1100 |
|1 |0001 |
最低位分別為0 0 1 可得到距離: 2* 1 = 2.
第2低位別為0 0 0 距離: 0
第3低位1 1 0 距離: 2 * 1 =2.
第4低位0 1 0 距離: 1 * 2 =2
總和=2+0+2+2=6
hamming distance =6 !
寫成C程式碼:
```cpp=
#include <stdio.h>
int totalHammingDistance(int* nums, int numsSize){
int res = 0, n = numsSize;
for (int i = 0; i < 32; ++i) {
int cnt = 0;
for (int num=0 ;num<numsSize;num++) {
if ((nums[num]>>i) & (1)) ++cnt;
}
res += cnt * (n - cnt);
}
return res;
}
int main ()
{
int nums[]={4,14,2};
printf("%d\n",totalHammingDistance(nums, 3));
}
```
----
#### 測驗二:
題目:
AAA:由malloc()會回傳a pointer to a pointer to int,可知道被指定的對象的型別應該也要是a pointer to a pointer to int,所以答案:int** parent
接下來程式碼多,我認為應舉個例子trace一次以利於理解:
EX:
```graphviz
digraph skew_BST {
size="5"
node [fontname="Arial"];
0 -> 1;
1 -> 2;
2 -> 3;
3 -> 4;
4 -> 5;
}
```
**parent 指向的記憶體空間的內容初始化後長相:
(下圖直接跳到已經補上了node的第一個parent)
```graphviz
digraph hash_table {
nodesep = .05;
rankdir = LR;
node[shape = record, width = 1.1, height = .1];
node0[label = "<f0> int *|<f1> node1 |<f2> int *|<f3> node 3|<f4> int *|<f5> int *", height = 2];
node [width = 1];
node1[label = "{ -1|-1|-1|-1|-1}"];
node2[label = "{ 1|-1|-1|-1|-1}"];
node4[label = "{ 3|-1|-1|-1|-1}"];
node5[label = "{ 4|-1|-1|-1|-1}"];
node0:f0 -> node1;
node0:f4 -> node4;
node0:f5 -> node5;
node0:f2 -> node2;
}
```
接下來依據程式碼可Trace:
表格:
|i \\ j|0|1|2|3|
|-|-|-|-|-|-|
|0|-1|-1|-1|-1|
|1|0|-1|-1|-1|
|2|1|0|-1|-1|
|3|2|1|-1|-1|
|4|3|2|0|-1|
|5|4|3|1|-1|
整理一下規律:parent[i][j]為node i 的往上第$2^j$的node
而BBB選擇-1是因為:
```cpp=
for (int j = 1;; j++) {
int quit = 1;
for (int i = 0; i < parentSize; i++) {
obj->parent[i][j] = obj->parent[i][j + (-1)/*BBB*/] == -1
? -1
: obj->parent[obj->parent[i][j - 1]][j - 1];
if (obj->parent[i][j] != -1) quit = 0;
}
```
第6行程式碼:obj->parent[obj->parent[i][j - 1]][j - 1]; 為依據。
```cpp=
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;
}
```
找第k個根據上面整理的規律:parent[i][j]為node i 的往上第$2^j$的node
所以CCC選擇i<<1。
##### 延伸學習2:
原版:
![](https://i.imgur.com/pP9lZKu.jpg)
第一版更改效率:
![](https://i.imgur.com/sJtu9aJ.jpg)
我只是發現初始化方式是以for迴圈,所以改成了memset(來自於測驗二的靈感)
第二版記憶體空間:(參考了同學quantabase13的表格例子)
我確定了此程式碼運作會有多出一行都-1。所以進行-1與各種debug
某些地方我還沒了解,剛好改完能成功提交而已。日後還需繼續理解:
最終結果:
![](https://i.imgur.com/SOqxUqu.jpg)
-----
#### 測驗三:
bitwise.c
```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;
}
```
依據題目先前的程式碼與觀察提示:
```cpp=
#define MSG_LEN 8
char fmt[MSG_LEN + 1];
strncpy(fmt, &"FizzBuzz%u"[start], length);
fmt[length] = '\0';
printf(fmt, i);
printf("\n");
```
觀察 printf 的(格式)字串,可分類為以下三種:
整數格式字串 "%d" : 長度為 2 B
“Fizz” 或 “Buzz” : 長度為 4 B
“FizzBuzz” : 長度為 8 B
```
string literal: "fizzbuzz%u"
offset: 0 4 8
```
得出的關鍵為此``` strncpy(fmt, &"FizzBuzz%u"[(MSG_LEN >> KK1) >> (KK2 << KK3)], length);```
然後依據divid 3 OR 5 OR 15 ...得到的offset或是說字元長度 來組合出符合所有可能的答案。
我們依據input 需要得到字串複製的起始點與長度(length)
而```unsigned int length = (2 << div3) << div5;```依據此句程式碼可得長度,再依此推出KK1~KK3。
條件:
case 1: 被3整除;不被5整除
=>length=(2<<1)<<0 =4
=>而output要是Fizz
=>所以offset=0
case 2: 被5整除:不被3整除
=>length=(2<<0)<<1 =4
=>output為Buzz
=>所以offset要是4
case 3:同時被3 與5整除
=>length=(2<<1)<<1=8
=>output=FizzBuzz
=>所以offset=0
Case 4:不被3 && 不被5 整除
=>length=2
=>output:%u
=>所以Offset=8
而MSG_LEN=8,Case4時候位移0剛好得到其offset (div3=0,div5=0)
Case1的時候,需右移4 (div3=1,div5=0)
Case2需右移1 (div3=0,div5=1)
Case3需右移動4 (div3=1,div5=1)
符合的組合便是
FizzBuzz%u[(MSG_LEN >> KK1) >> (KK2 << KK3)]
=FizzBuzz%u[(8>> div5) >> (div3 << 2)]-----------==Answer==
P.S.
原本我以為是div5、2、div3這樣的組合
反省之後,發現此組合將會少考慮到Case 2 :會變成右移3。
-----