// 演算法 / Algorithm:
// 用兩張大小 256 的查表記錄 s→t 與 t→s 的字元映射，掃描一次；
// 每對字元都要與已存在的映射一致，且映射是一對一的，否則不同構。
// Two 256-sized lookup tables record s→t and t→s mappings; single pass.
// Each pair must agree with existing mappings and stay one-to-one, else not isomorphic.

#include <stdbool.h>   // 提供 bool / true / false / gives us the bool type
#include <string.h>    // 提供 strlen / gives us strlen

bool isIsomorphic(char* s, char* t) {
    // 兩張查表，索引是字元的 ASCII 值（0~255）/ two tables indexed by ASCII value (0..255)
    // 初始化全為 0，代表「尚未建立映射」/ initialized to 0, meaning "no mapping yet"
    // unsigned char 範圍 0~255，剛好涵蓋所有 ASCII / unsigned char 0..255 covers all ASCII
    unsigned char mapST[256] = {0};   // s 的字元 -> 應對應到的 t 字元 / s-char -> required t-char
    unsigned char mapTS[256] = {0};   // t 的字元 -> 應對應到的 s 字元 / t-char -> required s-char

    // 逐字掃描；t 與 s 等長，所以用同一個索引 i / scan char by char; equal length, share index i
    for (int i = 0; s[i] != '\0'; i++) {
        // 取出這一對字元，轉成 unsigned 避免負數索引 / read the pair as unsigned to avoid negative index
        unsigned char a = (unsigned char)s[i];   // s 端的字元 / character from s
        unsigned char b = (unsigned char)t[i];   // t 端的字元 / character from t

        if (mapST[a] == 0 && mapTS[b] == 0) {
            // 兩個方向都還沒映射 -> 第一次見到，建立雙向映射 / both unseen -> create both directions
            mapST[a] = b;   // 記住 a 以後必須變成 b / a must always become b
            mapTS[b] = a;   // 記住 b 以後必須來自 a / b must always come from a
        } else if (mapST[a] != b || mapTS[b] != a) {
            // 任一方向與既有映射不符 -> 矛盾 -> 不同構 / either direction disagrees -> conflict -> not isomorphic
            // mapST[a]!=b：a 之前對應到別的字元 / a was mapped to a different char before
            // mapTS[b]!=a：b 之前來自別的字元（破壞一對一）/ b came from a different char (breaks one-to-one)
            return false;
        }
        // 否則兩個方向都已存在且一致，什麼都不用做 / otherwise both exist and agree, nothing to do
    }

    // 全部掃完都沒矛盾 -> 同構 / no conflict over the whole string -> isomorphic
    return true;
}
