https://avatars.githubusercontent.com/u/42119758?v=4

davidlei blog

golang 定時器(一) Time, Ticker 基本用法整理

在後端中常常會有需要定時的場景出現,像是如果處理 request 超過一定時間就觸發 timeout,或者利用定時的功能推送請求等等,這篇文章將會簡單介紹一些 golang 內建的定時器功能,以及可能會遇到的坑。 所有有關定時器的功能都在 time 內,使用前必須先 import "time" 單次定時事件 - Timer // src/time/sleep.go // The Timer type represents a single event. // When the Timer expires, the current time will be sent on C, // unless the Timer was created by AfterFunc. // A Timer must be created with NewTimer or AfterFunc. type Timer struct { C <- chan Time r runtimeTimer } 在 golang 中 Timer 可以用來表示一個單一事件,可以用 NewTimer 或者 AfterFunc 兩個 function 去建立一個新的 Timer,簡單的使用範例如下

leetcode 56. Merge Intervals [Medium]

題目敘述 這題的題目本身意思很直觀,給很多 區間,然後將所有範圍重疊的 區間 合併。 思考 一開始在看到題目的時候沒有想清楚就開始寫了,起初的想法是把 case 分成三種,如下圖所示 這樣判斷起來很沒有效率,後來才想到可以利用排序的方式,來讓所有的 case B 都消失,簡化主要邏輯判斷。如果在寫題目的過程中,發現自己的寫法可能遇到物件出現在前後的 case,必須要先思考看看是否能透過排序來解決,在這題中,透過排序可以讓每個分段都按照 start 先排過一輪,就不會出線上圖 case B 的情況了。 解題流程 class Solution { public: vector<vector<int>> merge(vector<vector<int>>& intervals) { int length = intervals.size(); vector<vector<int>> solution; sort(intervals.begin(), intervals.end()); int cur = 0; while (cur < length) { int start = intervals[cur][0]; int end = intervals[cur][1]; int walker = cur + 1; while (walker < length) { if (intervals[walker][0] > end) { break; } end = max(end, intervals[walker][1]); walker++; } solution.

leetcode 210. Course Schedule II [Medium]

題目敘述 給一個 prerequisites,每個元素 prerequisites[i] = [a, b],都代表如果想選 a 課程,必須先修過 b 課程。題目要求回傳可能的修課順序,如果不可能修過全部的課程,回傳一個空的陣列。 思考 什麼情況下會導致無法修過全部的課程? 考慮以下組合為例 prerequisites[0] = (1, 0), 修課程 1 之前必須修過課程 0 prerequisites[1] = (2, 1), 修課程 2 之前必須修過課程 1 prerequisites[2] = (0, 2), 修課程 0 之前必須修過課程 2 如果轉成有向圖則會變成以下情況 所以說這題其實是一題圖論的題目,把修課的條件建立成一個 graph,然後用 dfs 去尋訪,如果偵測到 cycle 代表一定有課程沒辦法修到,回傳空陣列。 在 dfs 的過程中用 status 來紀錄每個節點的狀態,如果 status[cur] == 1,代表這個節點是目前尋訪的點,用 status 來判斷是否有 cycle 的存在。 解題紀錄 class Solution { public: vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) { vector<vector<int>> graph(numCourses); // 建立有向圖 for (const auto &requisite: prerequisites) { graph[requisite[1]].

leetcode 1306. Jump Game III [Medium]

題目敘述 給定一非負整數陣列 arr,你一開始位於位置 start。當你位於索引值 i 時,你可以跳到 i + arr[i] 或是 i - arr[i],判斷你是否可以抵達任何位置其陣列值為 0 。 注意你在任意時刻都不能跳出陣列。 限制: 1 ≦ arr.length ≦ 5 × 10 ^ 4 0 ≦ arr[i] < arr.length 0 ≦ start < arr.length 解題紀錄 簡單的 dfs 解決,用一個 vector<bool> 去紀錄該 index 是否走過,避免發生無限迴圈的情況,如果 record[index] == true 代表已經走過,直接返回 false,記得還要判斷這次 jump 之後有沒有跳出迴圈的範圍。 static const auto fastIO = []() { ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); return 0; }(); class Solution { public: int len; vector<bool> record; bool canReach(vector<int> &arr, int start) { len = arr.

linux socket programming(三): socket programming 中常用的位置轉換函數

一般我們在表示 ip 位置時都會寫成人類比較容易讀的形式,像是125.102.25.62 以 ipv4 來說,address 是由4個 byte,32個 bit所組成,在實務上我們常常需要做字串與實際數值(uint32_t)的轉換,linux 函式庫提供了一系列輔助位置轉換的 function。 一般來說,address 的實際數值都會用 in_addr 或者 in_addr_t 來表示 其本質就是 uint32_t,用總共 32 個 bits 來表示一個 IPv4 的地址 typedef uint32_t in_addr_t; // 4 byte struct in_addr { in_addr_t s_addr; }; 常用的有以下這五種 只能用在 IPv4 的處理 inet_addr inet_aton inet_ntoa 兼容 Ipv4 與 IPv6 inet_pton inet_ntop 使用前必須先 #include <arpa/inet.h> inet_addr in_addr_t inet_addr(const char *cp) 功能: 將字串轉換成數值表示的 ip address 回傳: 假如輸入的地址合法,會回傳 uint32_t 的數值,若不合法則回傳 INADDR_NONE INADDR_NODE = 0xFFFFFFFF (32 個 bits 全部填一)

leetcode 222. Count Complete Tree Nodes [Medium]

題目連結 題目敘述 給予一棵 Complete Binary Tree,求節點個數。 Complete Binary Tree 定義 BFS 用最直觀的 BFS 來解,每從 queue 拿出一個節點,count 加一。 class Solution { public: int countNodes(TreeNode* root) { if (!root) return 0; int cnt = 0; queue<TreeNode*> q; q.push(root); while (!q.empty()) { TreeNode *node = q.front(); q.pop(); if (node->left) q.push(node->left); if (node->right) q.push(node->right); cnt++; } return cnt; } }; Runtime: 24 ms, faster than 95.34% of C++ online submissions for Count Complete Tree Nodes.