contributed by < JimmyLiu0530
>
進階電腦系統理論與實作
給定一個由 C 風格字串構成的陣列 arr
,字串 s
是將 arr
某個字串連接所得的字串,若 s
中的每個字元都只出現一次,於是這會是個可能解。請提供所有可能解 s
中最大的長度。
範例 1
arr =
["un", "iq", "ue"]
4
"", "un", "iq", "ue", "uniq", "ique"
,最大長度為 4
範例 2
arr =
["cha", "r", "act", "ers"]
6
範例 3
arr =
["abcdefghijklmnopqrstuvwxyz"]
26
提示:
\0
),僅有小寫英文字母本題用遞迴來思考:依序走訪每個單詞,對於目前的字串,若與之前連接的字串沒有相同的字串,那我們就可選擇將其串接或不串接。反之,若目前字串與之前串接的字串存在相同字元,那我們就無法串接。
以下 C 程式是對應的解法:
請補完程式碼,使得符合預期。
首先,我們看 maxLength
這個函式。一開始宣告一個大小為 arr_size
的整數陣列 a
,而這個 a
用來表示每個字串所使用到的英文字母的位元表示,簡單來說就是狀態壓縮。比如說假設第 i
個字串為 "abc"
,則 a[i]=7(=00...00111)
。
接下來,line 21 的 for
迴圈會根據每個字串 arr[i]
去更新 a
。我們設想一種情況:
假設某個字串中存在重複的字母,則此字串沒必要被選來與其他字串串接,因為不管怎麼串接,一定會有重複的字母出現,因此,ACT1
就在排除掉這種情況,所以 ACT1 為 if (__builtin_popcount(k) != len) continue
。
建立完 a
後,呼叫 dfs
,透過遞迴走訪每個字串,來決定不重複字母的最長字串長度。
想法如下:
就目前的字串 arr[i]
而言,考慮與之前串接的字串 c
是否存在相同字母,
c
,並且檢查串接後是否加長字串,因此 ASSIGN 為 c |= arr[i]
,ACT2 為 *maxm = MAX(__builtin_popcount(c), *maxm)
最終,走訪完所有字串後,就會得到最長字串長度 maxm
。
考慮以下透過 mmap 實作快速檔案複製的程式碼: mmap-filecopy.c
編譯方式:
假設原本已有檔名為 in
的檔案,且 out
不存在目前的路徑,可執行以下命令:
這樣即可達成快速的檔案複製。
請補完程式碼,使得符合預期。
根據 Linux manual page – mmap(2),首先我們能了解 mmap 的作用為在呼叫者的虛擬記憶體上建立一個檔案的映射,通過對這段記憶體的讀取和修改,實現對檔案的讀取和修改。
mmap 有上面這些參數,我們將一一的解釋其用途:
addr
: "希望"映射記憶體的初始位置,實際的初始位置為此呼叫的回傳值,不一定等於 addr
。
NULL
,則由 Linux 核心決定其初始位置length
: 映射空間的大小
prot
: 描述想要對該映射空間作什麼記憶體保護措施,但注意不能與檔案的開啟模式有衝突 (例如檔案為唯讀 (raed-only),但卻有 PROT_WRITE
flag)
PROT_EXEC
: 可能會被執行PROT_READ
: 可能會被讀取PROT_WRITE
: 可能會被寫入PROT_NONE
: 可能不會被存取因此,就可以回答 PROP = PROT_READ | PROT_WRITE
。
flags
: 決定對該映射空間的更新是否可讓其他一樣映射到此空間的行程 (process) 所看見 (映射空間的共享性)
MAP_SHARED
: 允許其他映射到此空間的行程共享,並且對映射空間的寫入會複製回文件。MAP_PRIVAT
: 不允許其他映射到此空間的行程共享,對映射空間的寫入會產生一個映射的複製 (copy-on-write),對此空間所做的修改不會寫回原文件。flags
可以使用,請參考 Linux manual page – mmap(2)fd
: 由 open
返回的文件描述符 (file descriptor),代表要映射到核心中的文件。
offset
: 映射空間初始位置的偏移量,通常為0。此外,offset
必須是分頁大小的整數倍
跟 mmap 搭配的 munmap
,用來關閉記憶體映射
munmap 刪除特定記憶體區段的映射,使原先合法參照此記憶體區段變為不合法。當行程終止時,該記憶體區段也會自動刪除。然而,關閉文件描述符並不會刪除映射。
如果成功,回傳 0
;否則,回傳 -1
,並設定 errno
指出錯誤的原因。
最後,mmap 帶來什麼好處呢?