meyr543
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    6
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Leetcode刷題學習筆記 -- Monotonic Stack ## 簡介 stack中保持著一定的順序,例如遞增或是遞減。 如果要新增的element比top還大/小。就把top pop出去。然後繼續往下比,直到保持一定的遞增或是遞減的順序。通常是找序列中比自己後面,但是值比自己還大/小的題目。 ## 使用時機? ### 1. 需要==往前或是往後==尋找,==下一個比自己大或比自己小==的元素就可以使用monotonic stack #### PLE(Previous Less Element) Good reference : [Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums/solutions/178876/stack-solution-with-very-detailed-explanation-step-by-step/?orderBy=most_votes) 找出之前比自己還小的值。 + stack 存放index。因為存index有很多好處,其中之一就是可以算和target的差距。 + 如果stack為empty則填入-1,也是有利計算差距。 ```cpp vector<int> nums; vector<int> ple(nums.size()); stack<int> st; // 存放index for(int i = 0; i < nums.size(); ++i) { while(!st.empty() && nums[st.top()] > nums[i]) st.pop(); ple[i] = st.empty() ? -1 : st.top(); st.push(i); // 將目前index推入stack } ``` #### NLE(Next less element) 找出之後比自己還小的值。 + code snippet一樣,只是for反過來尋找 + 如果stack為empty則填入nums.size() ```cpp vector<int> nums; int sz = nums.size(); vector<int> nle(sz); stack<int> st; for(int i = nums.size() - 1; i >= 0; --i) { while(!st.empty() && nums[st.top()] > nums[i]) st.pop(); nle[i] = st.empty() ? sz : st.top(); st.push(i); } ``` 另一種寫法,如果沒辦法從後面走訪數列的話 ```cpp vector<int> nums; int sz = nums.size(); vector<int> nle(sz, sz); stack<int> st; for(int i = 0; i < sz; ++i) { while(!st.empty() && nums[st.top()] > nums[i]) { nle[st.top()] = i; st.pop(); } st.push(i); } ``` ### 2. 往前或是往後看的最大/小值 剛剛第一種情況是往前或是往後看,第一個比自己大或小的值。另一種情況是往前看或是往後看,找出最大值。如果自己本身是最大值就是自己。 以下的code是從自己往後看,看到最大值的index。 ```cpp= vector<int> nums; int sz = nums.size(); vector<int> bwdMax(sz); // index stack<int> st; // index for(int i = 0; i < sz; ++i) { // stack中比目前的值還小,就丟掉,因為接下來的index只會看到這個 while(!st.empty() && nums[i] >= nums[st.top()]) st.pop(); if(st.empty()) st.push(i); // 如果沒了就是看到自己 bwdMax[i] = st.top(); } ``` 以下的code使從自己往前看,看到最大值的index。 ```cpp= vector<int> nums; int sz = nums.size(); vector<int> fwdMax(sz); // index stack<int> st; // index for(int i = sz - 1; i >= 0; --i) { while(!st.empty() && nums[i] >= nums[st.top()]) st.pop(); if(st.empty()) st.push(i); fwdMax[i] = st.top(); } ``` 後來想想,其實找fordward max或是backward max不需要使用stack,只要用以下簡單的方法即可。 ```cpp= int maxv = -1; vector<int> bwd(sz); for(int i = 0; i < sz; ++i) { maxv = max(maxv, nums[i]); bwd[i] = maxv; } ``` ### Example #### [42. Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water/) 給你一個vector<int> height,下雨過後會有多少雨水留在裡面。 > 1. 雨水留在裡面的多少會由,這格往前往後看的最大值決定。 > 2. 所以使用monotonic stack來計算每格往前往後看的最大值。 ```cpp= class Solution { public: int trap(vector<int>& height) { auto sz = height.size(); stack<int> st; vector<int> bwdMax(sz), fwdMax(sz); // backward max value index for(int i = 0; i < sz; ++i) { while(!st.empty() && height[i] >= height[st.top()]) st.pop(); if(st.empty()) st.push(i); bwdMax[i] = st.top(); } // clean the stack while(!st.empty()) st.pop(); // forward max value index for(int i = sz - 1; i >= 0; --i) { while(!st.empty() && height[i] >= height[st.top()]) st.pop(); if(st.empty()) st.push(i); fwdMax[i] = st.top(); } // calculate each rain int ans{0}; for(int i = 0; i < sz; ++i) { ans += min(height[fwdMax[i]], height[bwdMax[i]]) - height[i]; } return ans; } }; ``` 也可以使用以下簡單的方法 ```cpp= class Solution { public: int trap(vector<int>& height) { int sz = height.size(); vector<int> fwd(sz), bwd(sz); int maxv = -1; for(int i = 0; i < sz; ++i) { maxv = max(maxv, height[i]); bwd[i] = maxv; } maxv = -1; for(int i = sz - 1; i >= 0; --i) { maxv = max(maxv, height[i]); fwd[i] = maxv; } int ans{0}; for(int i = 0; i < sz; ++i) { ans += min(fwd[i], bwd[i]) - height[i]; } return ans; } }; ``` ### [739. Daily Temperatures[Medium]](https://leetcode.com/problems/daily-temperatures/) 給你一個每日溫度的數列vector<int> temperatures。求出過給天後,會比現在還溫暖。例如: Input: temperatures = [73,74,75,71,69,72,76,73] Output: [1,1,4,2,1,1,0,0] 解題思路: > 這是一個典型的單調遞增stack的問題。 ```cpp= vector<int> dailyTemperatures(vector<int>& temperatures) { stack<pair<int, int>> st; // 使用pair來紀錄 auto n = temperatures.size(); vector<int> ans(n, 0); for(int i = 0; i < n; ++i) { if(!st.empty()) { while(!st.empty() && temperatures[i] > st.top().first) { auto item = st.top(); ans[item.second] = i - item.second; st.pop(); } } st.push({temperatures[i], i}); } return ans; } ``` 2022/07/06 和上面的相比,stack只需存index即可。 2022/10/29 因為這題是找出後面第一個比自己大的值,所以是monotonic stack ```cpp= vector<int> dailyTemperatures(vector<int>& temp) { stack<int> s; //index int sz = temp.size(); vector<int> rtn(sz); for(int i = sz - 1; i >= 0; --i) { while(!s.empty() && temp[i] >= temp[s.top()]) s.pop(); rtn[i] = s.empty() ? 0 : s.top() - i; s.push(i); } return rtn; } ``` #### [901. Online Stock Span](https://leetcode.com/problems/online-stock-span/description/) 找出price左邊連續比它還小的數值。 > 1. 一開始有想到monotone stack但是怎麼寫都是不對。原因是少了一個變數。這邊使用了stack<pair<int, int>>。多了一個資訊。統計這個數字的span。全部的span加起來剛好是輸入price的個數。 > 2. 使用monotone stack是因為不需要找比自己還大的數字。 > 3. 可以看成我們在整理這個vector > [100] > [100, 80] > [100, 80, 60] > [100, 80, [60, 70]] --> [100, 80, 70(2)] > [100, 80, 70(2), 60] > [100, 80, [70(2), 60, 75]] --> [100, 80, 75(4)] > [100, [80, 75(4), 85]] --> [100, 85(6)] ```cpp class StockSpanner { stack<pair<int, int>> st; // value, span public: StockSpanner() { } int next(int price) { int ret{1}; while(!st.empty() && st.top().first <= price) { ret += st.top().second; st.pop(); } st.emplace(price, ret); return ret; } }; ``` 2022/10/29 因為這題是找出前面比自己還要大的數,所以使用monotonic stack。 ```cpp class StockSpanner { vector<int> prices; stack<int> st; int idx{0}; public: StockSpanner() { } int next(int price) { while(!st.empty() && prices[st.top()] <= price) st.pop(); int rtn = st.empty() ? idx + 1: idx - st.top(); prices.push_back(price); st.push(idx); idx++; return rtn; } }; ``` ### 3. 找出以第i個位置的山峰或是山谷 應用前面的找出前面和後面比自己高或是比自己低的位置,如果左右邊都應用的話,就是找出以第i個位置的山峰或是山谷。 例如: [1,4,3,7,4,5],可以畫出以下的圖 ![](https://hackmd.io/_uploads/ryqUZL7fT.png) 這邊可以發現,對index = 2 來說,如果以他為local minimal的subarray,可以得到。 ![](https://hackmd.io/_uploads/B1XBM8mf6.png) 同理,對index = 4來說,以他為local minimal的subarray,可以得到 ![](https://hackmd.io/_uploads/ryTAf8mMT.png) ### Example #### [1793. Maximum Score of a Good Subarray](https://leetcode.com/problems/maximum-score-of-a-good-subarray/description) Maximum score的定義是,subarray的最小值,乘上subarray的長度。另外Good subarray的定義是,必須包含index = k。 > 1. 因為Score的定義是,subarray的最小值乘上長度。所以算是找local minimal => 使用monotonic stack找出區域山谷。 > 2. 最後看每個index所構成的區域山谷,使否有包含index = k。 ```cpp= class Solution { public: int maximumScore(vector<int>& nums, int k) { int sz = nums.size(); vector<int> left(sz, -1), right(sz, sz), st; for(int i = 0; i < sz; ++i) { while(!st.empty() && nums[i] < nums[st.back()]) { right[st.back()] = i; st.pop_back(); } st.push_back(i); } st.clear(); for(int i = sz - 1; i >= 0; --i) { while(!st.empty() && nums[i] < nums[st.back()]) { left[st.back()] = i; st.pop_back(); } st.push_back(i); } int ans{}; for(int i = 0; i < sz; ++i) { if(left[i] < k && right[i] > k) ans = max(ans, nums[i] * (right[i] - left[i] - 1)); } return ans; } }; ``` #### [84. Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/) 找出histogram中最大面積的長方形。 > 1. 因為長方形的高度會被,最矮的數值決定。=> 找出以此index的區域山谷。 > 2. 找出以每個index為山谷之後,就可以依序找出每個面積,得到最大值。 ```cpp= class Solution { public: int largestRectangleArea(vector<int>& heights) { int sz = heights.size(); vector<int> fle(sz, sz), ble(sz, -1); stack<int> st; for(int i = 0; i < sz; ++i) { while(!st.empty() && heights[i] < heights[st.top()]) { fle[st.top()] = i; st.pop(); } st.push(i); } st = move(stack<int>()); for(int i = sz - 1; i >= 0; --i) { while(!st.empty() && heights[i] < heights[st.top()]) { ble[st.top()] = i; st.pop(); } st.push(i); } int ans{}; for(int i = 0; i < sz; ++i) { int left = i - ble[i]; int right = fle[i] - i; ans = max(ans, heights[i] * (left + right - 1)); } return ans; } }; ``` ## Problems ### [907. Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums/description/) 給你一個vector<int>找出所有subarray的組合中,每個subarray的最小值的和為多少? > + 這題參考了 [Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums/solutions/178876/stack-solution-with-very-detailed-explanation-step-by-step/?orderBy=most_votes) 對monotinic stack有更深一層的了解。 > + 另外參考了官神的[答案](https://github.com/wisdompeak/LeetCode/tree/master/Stack/907.Sum-of-Subarray-Minimums),因為官神對於計算個數比較直覺。 > 計算個數參考以下的註解。 > + 因為要知道subarray最小值,所以某個subarray的最小值取決於,這個subarray的左邊和右邊數值都是比目前的值還要大。 > + 找出自己前面和後面的最小值 ==> monotonic stack > + why two pass? 因為條件和自己前後都有關係。 ```cpp // [3, 1, 2, 4] // [3] --> ans += 3, 找出比自己小的左右兩邊的邊界 // [3, 1], [1], [1, 2], [1, 2, 4], [3, 1, 2], [3, 1, 2, 4] --> ans += 1 // [2], [2, 4] --> ans += 2 // [4] --> ans += 4 int sumSubarrayMins(vector<int>& arr) { int sz = arr.size(); vector<int> ple(sz), nle(sz); // PLE stack<int> st; for(int i = 0; i < sz; ++i) { while(!st.empty() && arr[st.top()] > arr[i]) st.pop(); ple[i] = st.empty() ? -1 : st.top(); st.push(i); } // clear the stack while(!st.empty()) st.pop(); // NLE // 為什麼是大於等於? // 因為等於的最小值也是和arr[i]一樣。 // 但是如果,兩邊都使用>= 會有重複問題,所以只要一邊就可以。 // ex : [71, 55, 82, 55], 如果ple和nle都使用>= // idx1 [71, 55], [55], // [82], [82, 55] // idx3 [71, 55, 82, 55] -->重複計算 for(int i = sz - 1; i >= 0; --i) { while(!st.empty() && arr[st.top()] >= arr[i]) st.pop(); nle[i] = st.empty() ? sz : st.top(); st.push(i); } // count the result // [3, 1, 2, 4] // -1, ,1 ,4 // i - ple[i] : 前面有幾個element : 2 --> [1], [3, 1] // nle[i] - i : 後面有幾個element : 3 --> [], [2], [2, 4] long rtn{0}; long mod = 1e9 + 7; for(int i = 0; i < sz; ++i) { long count = (i - ple[i]) * (nle[i] - i) % mod; rtn = (rtn + arr[i] * count) % mod; } return rtn; } ``` ### [316. Remove Duplicate Letters](https://leetcode.com/problems/remove-duplicate-letters/description/?envType=daily-question&envId=2023-09-26) ```cpp= class Solution { public: string removeDuplicateLetters(string s) { stack<char> st; unordered_set<char> seen; unordered_map<char, int> last; // 最後出現的位置 for(int i = 0; i < s.size(); ++i) last[s[i]] = i; for(int i = 0; i < s.size(); ++i) { if(seen.count(s[i])) continue; // 目前的char比s[i]還大,且後面還會有,就丟掉 while(!st.empty() && s[i] < st.top() && last[st.top()] > i) { seen.erase(st.top()); st.pop(); } seen.insert(s[i]); st.push(s[i]); } string rtn{}; while(!st.empty()) { rtn = st.top() + rtn; st.pop(); } return rtn; } }; ``` ### [2866. Beautiful Towers II](https://leetcode.com/problems/beautiful-towers-ii/description/) 給你一個vector<int> maxHeights,當用每個index當成mountain array的top,則兩邊勢必要配合top做修正,修正完之後才會成為mountain array,返回最大的mountain array sum。 > 1. 參考[官方答案](https://leetcode.cn/problems/beautiful-towers-ii/solutions/2563770/mei-li-ta-ii-by-leetcode-solution-2j4s/)。 > 2. 我們把每個index都當成mountain top。 > 3. 如果兩邊遇到比自己大的就會變成maxHeights[i]。所以可以容易計算出sum += (j - i) * maxHeights[i]; > 4. 遇到比自己小的(j),則會被j的左邊或是右邊的sum決定。 > 5. 所以問題變成找出比自己小的index。 > 6. 另外卡住的點是,以前使用monotonic stack會在pop之後更新資料,但是現在是pop完之後才處理,所以方向改變了。 ```cpp= class Solution { public: long long maximumSumOfHeights(vector<int>& maxHeights) { int sz = maxHeights.size(); vector<long long> right(sz), left(sz); stack<int> st; for(int i = 0; i < sz; ++i) { while(!st.empty() && maxHeights[i] < maxHeights[st.top()]) st.pop(); if(st.empty()) left[i] = (long long)(i + 1) * maxHeights[i]; else left[i] = left[st.top()] + (long long)(i - st.top()) * maxHeights[i]; st.push(i); } st = move(stack<int>()); long long res{}; for(int i = sz - 1; i >= 0; --i) { while(!st.empty() && maxHeights[i] < maxHeights[st.top()]) st.pop(); if(st.empty()) right[i] = (long long)(sz - i) * maxHeights[i]; else right[i] = right[st.top()] + (long long)(st.top() - i) * maxHeights[i]; st.push(i); res = max(res, left[i] + right[i] - maxHeights[i]); } return res; } }; ``` ### [1944.Number of Visible People In a Queue](https://leetcode.com/problems/number-of-visible-people-in-a-queue/description/) > 1. 這題感覺就是monotonic stack的題目,但是就是思考不出來怎麼處理中間比較矮的人。 > 2. 參考[lee215解答](https://leetcode.com/problems/number-of-visible-people-in-a-queue/solutions/1359707/java-c-python-stack-solution-next-greater-element/) ```cpp= class Solution { // 題目是往右看,可以看到幾個人 public: vector<int> canSeePersonsCount(vector<int>& heights) { int sz = heights.size(); vector<int> res(sz), st; for(int i = 0; i < sz; ++i) { // 前一個比自己小的(st.back()),因為會被我擋住(i), // 所以丟出來,不用在比了 while(!st.empty() && heights[st.back()] <= heights[i]) res[st.back()]++, st.pop_back(); // 前一個比自己大的(st.back())可以看到自己(i) if(!st.empty()) res[st.back()]++; st.push_back(i); } return res; } }; ``` ###### tags: `leetcode` `刷題`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully