// 演算法：滑動視窗 + 「字元 → 上次位置」查找表。
// Algorithm: sliding window with a "char -> last index" lookup table.
// 右指標逐格擴張；遇到視窗內的重複字元就把左指標跳到其上次位置之後。
// Right pointer expands; on a duplicate inside the window, jump left past its prior spot.

int lengthOfLongestSubstring(char* s) {
    int last[256];                       // 查找表：last[c] = 字元 c 上次出現的索引 / lookup: last index of char c
                                         // 大小 256 涵蓋所有 ASCII（含符號、空格）/ size 256 covers all ASCII bytes
    for (int i = 0; i < 256; i++)        // 走訪每個格子做初始化 / loop over every slot to initialize
        last[i] = -1;                    // -1 代表「此字元尚未出現過」/ -1 means "this char not seen yet"

    int best = 0;                        // 目前找到的最長長度 / longest length found so far
    int left = 0;                        // 視窗左邊界（含）/ window's left edge (inclusive)

    // right 走訪每個字元，直到字串結尾 '\0' / right scans each char until the '\0' terminator
    for (int right = 0; s[right] != '\0'; right++) {
        // s[right] 是字元，轉成 unsigned char 當索引，避免負值 / cast to unsigned char so the index is 0..255
        unsigned char c = (unsigned char) s[right];

        // 若 c 上次出現位置仍在視窗內（>= left），代表視窗有重複 / if c's last spot is inside the window, it's a dup
        if (last[c] >= left)
            left = last[c] + 1;          // 左邊界跳到重複字元之後一格，踢掉舊的那份 / move left just past the old copy

        last[c] = right;                 // 更新 c 的最新位置為現在 / record c's newest position as right

        int len = right - left + 1;      // 目前視窗長度（兩端皆含）/ current window length (both ends inclusive)
        if (len > best)                  // 若更長就更新答案 / keep the maximum
            best = len;
    }
    return best;                         // 回傳最長不重複子字串的長度 / return the answer
}
