最近因為工作面試的關系,我都在練習寫 Leetcode (畢竟從大學畢業之後我的主力語言都是 C (MCU / low level)、Go (Linux / Networking Applications)跟 網頁(HTML 、CSS 、JS 那堆)。雖然我都跟我面試的主管說「我都沒在寫 Leetcode」(因為我不想他們以「平常有寫多少 Leetcode 」為顧用考慮之一),但是或多或少因為有一段時間沒寫 C++ 了所以還是要找些免費題目來抓回以前的感覺。
最近我在寫 LeetCode 的時候發現一個滿有趣的現像,就是一般很多題目都會有一些特別特殊的極端例子(超快、或是超省記憶體)的情況。去翻一翻這些 code sample 之後我發現了一段很有趣的 code。
int speedUp = []
{std::ios::sync_with_stdio(0); std::cin.tie(0); return 0; }();
bool has[100002];
int digit(char c)
{
return c & 15;
}
bool isDigit(char c)
{
return '0' <= c && c <= '9';
}
int init = [] {
std::ofstream out("user.out");
std::cout.rdbuf(out.rdbuf());
for (string s; std::getline(std::cin, s); std::cout << '\n') {
int n = count(s.begin(), s.end(), ',') + 3;
memset(has, 0, n);
for (int _i = 1, _n = s.length(); _i < _n; ++_i) {
if (s[_i] == '-')for (_i += 2; isDigit(s[_i]); ++_i);
else {
int v = s[_i++] & 15;
while (isDigit(s[_i])) v = v * 10 + digit(s[_i++]);
if (0 < v && v < n) has[v] = true;
}
}
for (int i = 1;; ++i)
if (!has[i]) {
std::cout << i;
break;
}
}
exit(0);
return 0;
}();
沒錯,是一段 C++ 的 runtime cheat code。先上面的部分開始看,這邊它使用了 lambda function 來透過「假裝」定義 speedup variable 來執行了一些 STDIO redirect 的功能。我猜它應該是把之後執行的東西的 STDOUT 跟 parent 的 STDIN 接收的邏輯切開來。 之後它定義了一個 has 的超長 boolean array 來裝東西。
std::ios::sync_with_stdio(0); // 斷開 runtime output 與 STDIO 的同步
std::cin.tie(0); //停止 flushing (一般來說是執行時會自動把 cin 的資料 flush 到 cout)
下面的部分看上去很複雜,但是簡單來說它只是在做兩件事情:
- 從 STDOUT 那邊抓資料(我猜這邊應該是截取了 leetcode 執行你的 code 部分的輸出)
- 進行一些資料的預處理,從 count 那邊我們看到它輸出的資料應該是 csv 格式的(,分隔,總共有 3 個數字)
- 對 csv 進行數據處理(這邊我有點看不懂,因為不知道原本的 input 長怎樣的所以也很難猜)
- 把處理好的資料從 has 那邊吐回到 STDOUT(應該是 leetcode 前端 callback / request 回覆?)
把這段代碼加到 class Solution 上面之後,同一段 code 的分數就由這樣:
變成這樣:
至於這段東西在日常中有甚麼用嘛,額。。。不知道(