// 演算法：滑動視窗 + 「字元 → 上次位置」查找表，與 C 版相同思路。
// Algorithm: same sliding window + "char -> last index" table as the C version.
// 右指標擴張視窗，左指標在遇到視窗內重複時向右收縮。
// Right pointer grows the window; left pointer shrinks it when a duplicate appears inside.

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // vector<int> 是會自動管理記憶體的動態陣列；這裡建 256 格、初值 -1。
        // vector<int> is a self-managing dynamic array; 256 slots all initialized to -1.
        // last[c] = 字元 c 上次出現的索引，-1 表示尚未出現 / last[c] = char c's last index, -1 = unseen.
        vector<int> last(256, -1);

        int best = 0;                    // 目前最長長度 / best length so far
        int left = 0;                    // 視窗左邊界（含）/ left edge of window (inclusive)

        // range 寫法配索引：用傳統 for 取得 right 索引 / classic for loop so we have the index `right`
        for (int right = 0; right < (int) s.size(); right++) {
            // 轉成 unsigned char 作索引，避免非 ASCII 變負數 / cast to unsigned char for a safe 0..255 index
            unsigned char c = (unsigned char) s[right];

            // c 上次位置在視窗內 → 視窗出現重複，左界跳到其後 / dup inside window -> jump left past it
            if (last[c] >= left)
                left = last[c] + 1;

            last[c] = right;             // 記錄 c 的最新出現位置 / update c's latest position

            // std::max 取兩數較大者，等價於 if 比較 / std::max returns the larger of the two values
            best = max(best, right - left + 1);  // right-left+1 是當前視窗長度 / current window length
        }
        return best;                     // 回傳結果 / return the answer
    }
};
