[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fBvfF8J0jOdigQ9UK2QBs3JFUuORGSJlzMlot69OLgpo":3,"$fJU-4tot_gC5fDkujNeoE-cGsdMy5V_KcdUXLuAnTFgw":15,"$fX48GwkoRd1prDuTppb4sKJLGgXq3Hunl8ijEytwgryM":423},{"slug":4,"title":5,"description":6,"content":7,"content_html":8,"pub_date":9,"tags":10,"draft":14},"algorithm-number-complement","整数的补数：位运算掩码解法","LeetCode 476 题，用掩码 XOR 实现整数补数，附 C++\u002FPython\u002FJava 三种实现及补数与补码的区别","# 整数的补数：位运算掩码解法\n\nLeetCode 476 号题\"数字的补数\"（Number Complement）是一道经典的位运算题，看似简单，却能引出多种思路和技巧。本文从朴素解法到位运算优化，逐步推导，并给出 Python、C++、JavaScript 三语言实现。\n\n## 题目描述\n\n给你一个**正整数** `num`，输出它的补数。补数是对该数的二进制表示取反（仅对有效位取反，不包含前导零）。\n\n**示例：**\n\n```\n输入：num = 5\n输出：2\n解释：5 的二进制是 101，取反得 010，即 2\n\n输入：num = 1\n输出：0\n解释：1 的二进制是 1，取反得 0\n\n输入：num = 7\n输出：0\n解释：7 的二进制是 111，取反得 000，即 0\n\n输入：num = 10\n输出：5\n解释：10 的二进制是 1010，取反得 0101，即 5\n```\n\n**约束**：`1 \u003C= num \u003C 2^31`\n\n## 朴素解法\n\n最直观的方法：逐位取反。\n\n```python\ndef findComplement_naive(num: int) -> int:\n    # 找到最高有效位的位置\n    bit = 1\n    temp = num\n    result = 0\n    pos = 0\n    \n    while temp > 0:\n        # 取当前最低位，取反后放到结果对应位置\n        current_bit = temp & 1\n        flipped = 1 - current_bit  # 0变1，1变0\n        result |= (flipped \u003C\u003C pos)\n        temp >>= 1\n        pos += 1\n    \n    return result\n```\n\n时间复杂度 O(log n)，空间复杂度 O(1)。\n\n## 位运算思路推导\n\n### 核心思想：XOR 取反\n\n对二进制数取反，等价于与全 1 掩码进行 XOR 运算：\n\n```\n  101  (5)\nXOR\n  111  (mask = 全1)\n= 010  (2，即结果)\n```\n\n问题转化为：如何构造一个与 `num` 等长的\"全 1 掩码\"？\n\n### 掩码的含义\n\n如果 `num` 有 `k` 位有效位，那么掩码 `mask = 2^k - 1`，即 k 个 1。\n\n```\nnum = 5 = 0b101  （3 位）\nmask    = 0b111  = 2^3 - 1 = 7\nresult  = 5 XOR 7 = 2\n```\n\n```\nnum = 10 = 0b1010  （4 位）\nmask     = 0b1111  = 2^4 - 1 = 15\nresult   = 10 XOR 15 = 5\n```\n\n## 掩码生成的三种方法\n\n### 方法一：循环移位\n\n```python\ndef get_mask_loop(num: int) -> int:\n    mask = 1\n    while mask \u003C= num:\n        mask \u003C\u003C= 1\n    return mask - 1\n```\n\n解析：\n- 从 `mask = 1` 开始，不断左移\n- 当 `mask > num` 时，`mask` 是 `2^k`（比 num 多一位）\n- `mask - 1` 就是 k 个 1 组成的掩码\n\n```\nnum = 5 (0b101):\nmask 迭代: 1 → 2 → 4 → 8 (8 > 5, 停止)\nmask - 1 = 7 = 0b111  ✓\n```\n\n### 方法二：bit_length()\n\nPython 的整数有 `bit_length()` 方法，返回二进制表示的有效位数：\n\n```python\ndef get_mask_bitlength(num: int) -> int:\n    k = num.bit_length()  # 有效位数\n    return (1 \u003C\u003C k) - 1   # 2^k - 1\n```\n\n```\n5.bit_length() = 3\n(1 \u003C\u003C 3) - 1 = 8 - 1 = 7 = 0b111  ✓\n```\n\n这是 Python 中最简洁的方法。\n\n### 方法三：log2 计算\n\n```python\nimport math\n\ndef get_mask_log(num: int) -> int:\n    k = math.floor(math.log2(num)) + 1  # 位数\n    return (1 \u003C\u003C k) - 1\n```\n\n注意：浮点数精度问题可能导致 `math.log2` 在某些特殊值（如 `2^k`）时返回不准确的结果，推荐使用 `bit_length()` 代替。\n\n```python\n# 安全版本（避免浮点问题）\ndef get_mask_safe(num: int) -> int:\n    k = int(math.log2(num)) + 1\n    # 验证并修正\n    if (1 \u003C\u003C (k-1)) > num:\n        k -= 1\n    return (1 \u003C\u003C k) - 1\n```\n\n## 完整解法\n\n### Python\n\n```python\nclass Solution:\n    def findComplement(self, num: int) -> int:\n        # 方法一：位移构造掩码\n        mask = 1\n        while mask \u003C= num:\n            mask \u003C\u003C= 1\n        return (mask - 1) ^ num\n    \n    # 方法二：bit_length（更Pythonic）\n    def findComplement_v2(self, num: int) -> int:\n        return ((1 \u003C\u003C num.bit_length()) - 1) ^ num\n    \n    # 方法三：一行版本\n    def findComplement_v3(self, num: int) -> int:\n        return num ^ (2 ** num.bit_length() - 1)\n```\n\n### C++\n\n```cpp\nclass Solution {\npublic:\n    int findComplement(int num) {\n        \u002F\u002F 构造掩码（使用 unsigned 避免溢出）\n        unsigned int mask = 1;\n        while (mask \u003C= (unsigned int)num) {\n            mask \u003C\u003C= 1;\n        }\n        return (mask - 1) ^ num;\n    }\n    \n    \u002F\u002F 使用内置函数（GCC）\n    int findComplement_v2(int num) {\n        \u002F\u002F __builtin_clz 计算前导零数\n        \u002F\u002F 32 位整数总位数 - 前导零数 = 有效位数\n        int k = 32 - __builtin_clz(num);\n        \u002F\u002F 构造 k 个 1 的掩码\n        \u002F\u002F 注意：当 k=32 时，(1 \u003C\u003C 32) 会溢出，需要特殊处理\n        if (k == 32) return ~num;\n        int mask = (1 \u003C\u003C k) - 1;\n        return mask ^ num;\n    }\n    \n    \u002F\u002F 更安全的版本（使用 long long 避免溢出）\n    int findComplement_v3(int num) {\n        long long mask = 1;\n        while (mask \u003C= num) {\n            mask \u003C\u003C= 1;\n        }\n        return (int)((mask - 1) ^ num);\n    }\n};\n```\n\n注意 C++ 中的溢出风险：\n- `int` 是有符号 32 位，左移到第 31 位会触发未定义行为\n- 使用 `unsigned int` 或 `long long` 更安全\n\n### JavaScript\n\n```javascript\n\u002F**\n * @param {number} num\n * @return {number}\n *\u002F\nvar findComplement = function(num) {\n    \u002F\u002F JavaScript 的位运算基于 32 位有符号整数\n    let mask = 1;\n    while (mask \u003C= num) {\n        mask \u003C\u003C= 1;\n    }\n    return (mask - 1) ^ num;\n};\n\n\u002F\u002F 使用 Math.clz32（计算 32 位前导零）\nvar findComplement_v2 = function(num) {\n    const k = 32 - Math.clz32(num);\n    const mask = (1 \u003C\u003C k) - 1;\n    return mask ^ num;\n};\n\n\u002F\u002F 注意：JavaScript 的位运算只支持 32 位整数\n\u002F\u002F 对于 num >= 2^30 时，(1 \u003C\u003C k) 可能出现符号位问题\n\u002F\u002F 使用 >>>0 转为无符号\nvar findComplement_safe = function(num) {\n    let mask = 1;\n    while ((mask >>> 0) \u003C= (num >>> 0)) {\n        mask = (mask \u003C\u003C 1) >>> 0;\n    }\n    return ((mask - 1) ^ num) >>> 0;\n};\n```\n\n## 复杂度分析\n\n所有方法的复杂度均为：\n\n- **时间复杂度**：O(log n)——需要处理 num 的每一位\n- **空间复杂度**：O(1)——仅使用常数个变量\n\n实际上，`bit_length()` \u002F `__builtin_clz` 是 O(1) 的硬件指令级操作，在这道题中完全等价，但概念上更接近 O(log n)。\n\n## 相关题目延伸\n\n### LeetCode 461：汉明距离\n\n汉明距离 = 两个整数 XOR 后 1 的个数：\n```python\ndef hammingDistance(x, y):\n    return bin(x ^ y).count('1')\n```\n\n### LeetCode 191：位 1 的个数（汉明重量）\n\n```python\ndef hammingWeight(n):\n    return bin(n).count('1')\n    # 或用 Brian Kernighan 算法\n    count = 0\n    while n:\n        n &= n - 1  # 清除最低位的 1\n        count += 1\n    return count\n```\n\n### LeetCode 338：比特位计数\n\n```python\ndef countBits(n):\n    dp = [0] * (n + 1)\n    for i in range(1, n + 1):\n        dp[i] = dp[i >> 1] + (i & 1)\n    return dp\n```\n\n### 延伸思考：负数的补码\n\n本题的\"补数\"（complement）与计算机底层的\"补码\"（two's complement）不同：\n- 本题补数 = 对有效位取反（无符号视角）\n- 补码 = 取反 + 1（有符号表示负数的方式）\n\n区分清楚这两个概念，有助于理解更复杂的位运算题。\n\n掌握了掩码构造技巧后，遇到类似的\"对有效位操作\"的题目，都可以套用这个思路。\n","\u003Ch1>整数的补数：位运算掩码解法\u003C\u002Fh1>\n\u003Cp>LeetCode 476 号题&quot;数字的补数&quot;（Number Complement）是一道经典的位运算题，看似简单，却能引出多种思路和技巧。本文从朴素解法到位运算优化，逐步推导，并给出 Python、C++、JavaScript 三语言实现。\u003C\u002Fp>\n\u003Ch2 id=\"题目描述\">题目描述\u003C\u002Fh2>\n\u003Cp>给你一个\u003Cstrong>正整数\u003C\u002Fstrong> \u003Ccode>num\u003C\u002Fcode>，输出它的补数。补数是对该数的二进制表示取反（仅对有效位取反，不包含前导零）。\u003C\u002Fp>\n\u003Cp>\u003Cstrong>示例：\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cpre>\u003Ccode>输入：num = 5\n输出：2\n解释：5 的二进制是 101，取反得 010，即 2\n\n输入：num = 1\n输出：0\n解释：1 的二进制是 1，取反得 0\n\n输入：num = 7\n输出：0\n解释：7 的二进制是 111，取反得 000，即 0\n\n输入：num = 10\n输出：5\n解释：10 的二进制是 1010，取反得 0101，即 5\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>约束\u003C\u002Fstrong>：\u003Ccode>1 &lt;= num &lt; 2^31\u003C\u002Fcode>\u003C\u002Fp>\n\u003Ch2 id=\"朴素解法\">朴素解法\u003C\u002Fh2>\n\u003Cp>最直观的方法：逐位取反。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-python\">def findComplement_naive(num: int) -&gt; int:\n    # 找到最高有效位的位置\n    bit = 1\n    temp = num\n    result = 0\n    pos = 0\n    \n    while temp &gt; 0:\n        # 取当前最低位，取反后放到结果对应位置\n        current_bit = temp &amp; 1\n        flipped = 1 - current_bit  # 0变1，1变0\n        result |= (flipped &lt;&lt; pos)\n        temp &gt;&gt;= 1\n        pos += 1\n    \n    return result\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>时间复杂度 O(log n)，空间复杂度 O(1)。\u003C\u002Fp>\n\u003Ch2 id=\"位运算思路推导\">位运算思路推导\u003C\u002Fh2>\n\u003Ch3 id=\"核心思想-xor-取反\">核心思想：XOR 取反\u003C\u002Fh3>\n\u003Cp>对二进制数取反，等价于与全 1 掩码进行 XOR 运算：\u003C\u002Fp>\n\u003Cpre>\u003Ccode>  101  (5)\nXOR\n  111  (mask = 全1)\n= 010  (2，即结果)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>问题转化为：如何构造一个与 \u003Ccode>num\u003C\u002Fcode> 等长的&quot;全 1 掩码&quot;？\u003C\u002Fp>\n\u003Ch3 id=\"掩码的含义\">掩码的含义\u003C\u002Fh3>\n\u003Cp>如果 \u003Ccode>num\u003C\u002Fcode> 有 \u003Ccode>k\u003C\u002Fcode> 位有效位，那么掩码 \u003Ccode>mask = 2^k - 1\u003C\u002Fcode>，即 k 个 1。\u003C\u002Fp>\n\u003Cpre>\u003Ccode>num = 5 = 0b101  （3 位）\nmask    = 0b111  = 2^3 - 1 = 7\nresult  = 5 XOR 7 = 2\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode>num = 10 = 0b1010  （4 位）\nmask     = 0b1111  = 2^4 - 1 = 15\nresult   = 10 XOR 15 = 5\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"掩码生成的三种方法\">掩码生成的三种方法\u003C\u002Fh2>\n\u003Ch3 id=\"方法一-循环移位\">方法一：循环移位\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-python\">def get_mask_loop(num: int) -&gt; int:\n    mask = 1\n    while mask &lt;= num:\n        mask &lt;&lt;= 1\n    return mask - 1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>解析：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>从 \u003Ccode>mask = 1\u003C\u002Fcode> 开始，不断左移\u003C\u002Fli>\n\u003Cli>当 \u003Ccode>mask &gt; num\u003C\u002Fcode> 时，\u003Ccode>mask\u003C\u002Fcode> 是 \u003Ccode>2^k\u003C\u002Fcode>（比 num 多一位）\u003C\u002Fli>\n\u003Cli>\u003Ccode>mask - 1\u003C\u002Fcode> 就是 k 个 1 组成的掩码\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode>num = 5 (0b101):\nmask 迭代: 1 → 2 → 4 → 8 (8 &gt; 5, 停止)\nmask - 1 = 7 = 0b111  ✓\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"方法二-bit_length\">方法二：bit_length()\u003C\u002Fh3>\n\u003Cp>Python 的整数有 \u003Ccode>bit_length()\u003C\u002Fcode> 方法，返回二进制表示的有效位数：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-python\">def get_mask_bitlength(num: int) -&gt; int:\n    k = num.bit_length()  # 有效位数\n    return (1 &lt;&lt; k) - 1   # 2^k - 1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre>\u003Ccode>5.bit_length() = 3\n(1 &lt;&lt; 3) - 1 = 8 - 1 = 7 = 0b111  ✓\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>这是 Python 中最简洁的方法。\u003C\u002Fp>\n\u003Ch3 id=\"方法三-log2-计算\">方法三：log2 计算\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-python\">import math\n\ndef get_mask_log(num: int) -&gt; int:\n    k = math.floor(math.log2(num)) + 1  # 位数\n    return (1 &lt;&lt; k) - 1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>注意：浮点数精度问题可能导致 \u003Ccode>math.log2\u003C\u002Fcode> 在某些特殊值（如 \u003Ccode>2^k\u003C\u002Fcode>）时返回不准确的结果，推荐使用 \u003Ccode>bit_length()\u003C\u002Fcode> 代替。\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-python\"># 安全版本（避免浮点问题）\ndef get_mask_safe(num: int) -&gt; int:\n    k = int(math.log2(num)) + 1\n    # 验证并修正\n    if (1 &lt;&lt; (k-1)) &gt; num:\n        k -= 1\n    return (1 &lt;&lt; k) - 1\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"完整解法\">完整解法\u003C\u002Fh2>\n\u003Ch3 id=\"python\">Python\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-python\">class Solution:\n    def findComplement(self, num: int) -&gt; int:\n        # 方法一：位移构造掩码\n        mask = 1\n        while mask &lt;= num:\n            mask &lt;&lt;= 1\n        return (mask - 1) ^ num\n    \n    # 方法二：bit_length（更Pythonic）\n    def findComplement_v2(self, num: int) -&gt; int:\n        return ((1 &lt;&lt; num.bit_length()) - 1) ^ num\n    \n    # 方法三：一行版本\n    def findComplement_v3(self, num: int) -&gt; int:\n        return num ^ (2 ** num.bit_length() - 1)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"c\">C++\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-cpp\">class Solution {\npublic:\n    int findComplement(int num) {\n        \u002F\u002F 构造掩码（使用 unsigned 避免溢出）\n        unsigned int mask = 1;\n        while (mask &lt;= (unsigned int)num) {\n            mask &lt;&lt;= 1;\n        }\n        return (mask - 1) ^ num;\n    }\n    \n    \u002F\u002F 使用内置函数（GCC）\n    int findComplement_v2(int num) {\n        \u002F\u002F __builtin_clz 计算前导零数\n        \u002F\u002F 32 位整数总位数 - 前导零数 = 有效位数\n        int k = 32 - __builtin_clz(num);\n        \u002F\u002F 构造 k 个 1 的掩码\n        \u002F\u002F 注意：当 k=32 时，(1 &lt;&lt; 32) 会溢出，需要特殊处理\n        if (k == 32) return ~num;\n        int mask = (1 &lt;&lt; k) - 1;\n        return mask ^ num;\n    }\n    \n    \u002F\u002F 更安全的版本（使用 long long 避免溢出）\n    int findComplement_v3(int num) {\n        long long mask = 1;\n        while (mask &lt;= num) {\n            mask &lt;&lt;= 1;\n        }\n        return (int)((mask - 1) ^ num);\n    }\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>注意 C++ 中的溢出风险：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>int\u003C\u002Fcode> 是有符号 32 位，左移到第 31 位会触发未定义行为\u003C\u002Fli>\n\u003Cli>使用 \u003Ccode>unsigned int\u003C\u002Fcode> 或 \u003Ccode>long long\u003C\u002Fcode> 更安全\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"javascript\">JavaScript\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-javascript\">\u002F**\n * @param {number} num\n * @return {number}\n *\u002F\nvar findComplement = function(num) {\n    \u002F\u002F JavaScript 的位运算基于 32 位有符号整数\n    let mask = 1;\n    while (mask &lt;= num) {\n        mask &lt;&lt;= 1;\n    }\n    return (mask - 1) ^ num;\n};\n\n\u002F\u002F 使用 Math.clz32（计算 32 位前导零）\nvar findComplement_v2 = function(num) {\n    const k = 32 - Math.clz32(num);\n    const mask = (1 &lt;&lt; k) - 1;\n    return mask ^ num;\n};\n\n\u002F\u002F 注意：JavaScript 的位运算只支持 32 位整数\n\u002F\u002F 对于 num &gt;= 2^30 时，(1 &lt;&lt; k) 可能出现符号位问题\n\u002F\u002F 使用 &gt;&gt;&gt;0 转为无符号\nvar findComplement_safe = function(num) {\n    let mask = 1;\n    while ((mask &gt;&gt;&gt; 0) &lt;= (num &gt;&gt;&gt; 0)) {\n        mask = (mask &lt;&lt; 1) &gt;&gt;&gt; 0;\n    }\n    return ((mask - 1) ^ num) &gt;&gt;&gt; 0;\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"复杂度分析\">复杂度分析\u003C\u002Fh2>\n\u003Cp>所有方法的复杂度均为：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>时间复杂度\u003C\u002Fstrong>：O(log n)——需要处理 num 的每一位\u003C\u002Fli>\n\u003Cli>\u003Cstrong>空间复杂度\u003C\u002Fstrong>：O(1)——仅使用常数个变量\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>实际上，\u003Ccode>bit_length()\u003C\u002Fcode> \u002F \u003Ccode>__builtin_clz\u003C\u002Fcode> 是 O(1) 的硬件指令级操作，在这道题中完全等价，但概念上更接近 O(log n)。\u003C\u002Fp>\n\u003Ch2 id=\"相关题目延伸\">相关题目延伸\u003C\u002Fh2>\n\u003Ch3 id=\"leetcode-461-汉明距离\">LeetCode 461：汉明距离\u003C\u002Fh3>\n\u003Cp>汉明距离 = 两个整数 XOR 后 1 的个数：\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-python\">def hammingDistance(x, y):\n    return bin(x ^ y).count('1')\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"leetcode-191-位-1-的个数-汉明重量\">LeetCode 191：位 1 的个数（汉明重量）\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-python\">def hammingWeight(n):\n    return bin(n).count('1')\n    # 或用 Brian Kernighan 算法\n    count = 0\n    while n:\n        n &amp;= n - 1  # 清除最低位的 1\n        count += 1\n    return count\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"leetcode-338-比特位计数\">LeetCode 338：比特位计数\u003C\u002Fh3>\n\u003Cpre>\u003Ccode class=\"language-python\">def countBits(n):\n    dp = [0] * (n + 1)\n    for i in range(1, n + 1):\n        dp[i] = dp[i &gt;&gt; 1] + (i &amp; 1)\n    return dp\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3 id=\"延伸思考-负数的补码\">延伸思考：负数的补码\u003C\u002Fh3>\n\u003Cp>本题的&quot;补数&quot;（complement）与计算机底层的&quot;补码&quot;（two’s complement）不同：\u003C\u002Fp>\n\u003Cul>\n\u003Cli>本题补数 = 对有效位取反（无符号视角）\u003C\u002Fli>\n\u003Cli>补码 = 取反 + 1（有符号表示负数的方式）\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>区分清楚这两个概念，有助于理解更复杂的位运算题。\u003C\u002Fp>\n\u003Cp>掌握了掩码构造技巧后，遇到类似的&quot;对有效位操作&quot;的题目，都可以套用这个思路。\u003C\u002Fp>\n","2021-03-08",[11,12,13],"算法","位运算","leetcode",false,[16,29,40,52,62,69,76,83,90,97,107,116,126,135,142,150,159,168,177,187,194,204,210,217,223,232,238,245,253,263,272,281,291,301,311,319,329,340,350,359,367,373,381,389,397,405,413,420],{"slug":17,"title":18,"description":19,"pub_date":20,"tags":21,"draft":14,"word_count":28},"ide-skills-guide","Agent Skills 完全指南：21 款第三方 Skill 深度评测与使用心得","全面评测 21 款第三方 Agent Skills，涵盖 Vue 生态、前端设计、构建工具、实用工具四大分类。从安装配置到实际使用场景，带你了解每个 Skill 的功能特点、最佳实践与使用心得。","2026-06-15",[22,23,24,25,26,27],"agent","skills","AI","效率工具","前端","Vue",4169,{"slug":30,"title":31,"description":32,"pub_date":33,"tags":34,"draft":14,"word_count":39},"linux-kernel-skeleton-struct-funcptr-container_of","Linux 内核骨架：struct、函数指针与 container_of","读懂 Linux 内核源码的三件套：巨大的 struct 组合代替继承、函数指针表实现虚派发、container_of 宏从嵌入成员找回完整对象。","2026-05-09",[35,36,37,38],"linux","kernel","C","container_of",1369,{"slug":41,"title":42,"description":43,"pub_date":44,"tags":45,"draft":14,"word_count":51},"astro-complete-guide-2025","Astro 5 深度剖析：Islands 架构原理、构建优化与 Cloudflare Workers 边缘部署","从编译器视角解析 Astro 5 的 Islands 架构实现原理，Content Layer API 的 Vite 插件机制，Server Islands 的流式渲染，以及如何在 Cloudflare Workers + D1 边缘环境下榨干性能。","2026-05-08",[46,47,48,49,50],"astro","frontend","cloudflare","performance","architecture",3663,{"slug":53,"title":54,"description":55,"pub_date":56,"tags":57,"draft":14,"word_count":61},"llm-prompt-engineering","Prompt Engineering 实战：让 LLM 真正听话的技巧","System prompt 怎么写、Few-shot 怎么设计、Chain-of-Thought 原理，以及常见失败模式和调试方法。","2026-05-03",[58,59,60],"ai","llm","工程实践",1723,{"slug":63,"title":64,"description":65,"pub_date":56,"tags":66,"draft":14,"word_count":68},"rag-system-design","RAG 系统设计：从 naive 到 production-ready","Retrieval-Augmented Generation 不只是「向量数据库 + LLM」，分块策略、召回质量、重排序、缓存才是工程核心。",[58,67,59,60],"rag",1613,{"slug":70,"title":71,"description":72,"pub_date":56,"tags":73,"draft":14,"word_count":75},"git-advanced-workflow","Git 进阶工作流：rebase、cherry-pick、bisect 的正确使用","merge 会了，但 rebase 总搞错？bisect 找 bug 提交？interactive rebase 整理历史？这篇一次说清楚。",[74,60],"git",1396,{"slug":77,"title":78,"description":79,"pub_date":56,"tags":80,"draft":14,"word_count":82},"docker-practical-guide","Docker 实战：从会用到用好","会 docker run 不够，Dockerfile 最佳实践、多阶段构建、Compose 编排、镜像瘦身才是日常真正需要的。",[81,35,60],"docker",1268,{"slug":84,"title":85,"description":86,"pub_date":56,"tags":87,"draft":14,"word_count":89},"anthropics-skills-guide","anthropics\u002Fskills：Anthropic 官方 Agent Skills 仓库解析","Anthropic 官方开源的 Agent Skills 标准仓库，127k stars，解析 SKILL.md 规范、17 个示例 skill 的设计模式，以及如何在 Claude Code \u002F Claude.ai \u002F API 中使用",[58,88,22,23],"Claude",2090,{"slug":91,"title":92,"description":93,"pub_date":56,"tags":94,"draft":14,"word_count":96},"karpathy-claude-code-guidelines","Karpathy 的 LLM 编码批评与 CLAUDE.md 最佳实践","基于 Andrej Karpathy 对 LLM 编程助手的观察，forrestchang 提炼出一个 CLAUDE.md 文件，4 条原则解决 AI 编码的典型失控问题：乱猜假设、过度设计、乱改代码、目标不清",[58,88,95,60],"Claude Code",2699,{"slug":98,"title":99,"description":100,"pub_date":56,"tags":101,"draft":14,"word_count":106},"typescript-advanced-patterns","TypeScript 高级模式：让类型系统为你工作","基础 TS 会了但类型总是 any？条件类型、映射类型、模板字面量类型、infer 关键字才是 TS 的真正威力。",[102,103,104,105],"typescript","类型系统","前端工程","高级模式",1419,{"slug":108,"title":109,"description":110,"pub_date":56,"tags":111,"draft":14,"word_count":115},"linux-performance-tuning","Linux 性能调优实战：从 top 到 perf 的完整工具链","遇到性能问题不知道从哪下手？这篇建立系统化的排查思路，从 CPU\u002F内存\u002FIO\u002F网络逐层分析。",[35,112,113,114],"性能","运维","系统编程",1524,{"slug":117,"title":118,"description":119,"pub_date":56,"tags":120,"draft":14,"word_count":125},"python-functional-programming","Python 函数式编程：map\u002Ffilter\u002Freduce 之外","Python 不是纯函数式语言，但 functools、itertools、偏函数、闭包这些工具用好了能让代码简洁一个量级。",[121,122,123,124],"python","函数式","闭包","装饰器",1867,{"slug":127,"title":128,"description":129,"pub_date":56,"tags":130,"draft":14,"word_count":134},"python-oop-guide","Python 面向对象：__init__ 之外你需要知道的","Python OOP 不只是 class + __init__，魔术方法、描述符、元类才是真正的武器。",[121,131,132,133],"OOP","面向对象","魔术方法",1792,{"slug":136,"title":137,"description":138,"pub_date":56,"tags":139,"draft":14,"word_count":141},"python-data-structures","Python 内置数据结构深度解析","list、dict、set、tuple 不只是数据容器，搞懂它们的底层实现和时间复杂度，才能写出高性能 Python。",[121,140,112,11],"数据结构",1517,{"slug":143,"title":144,"description":145,"pub_date":56,"tags":146,"draft":14,"word_count":149},"python-basics-quick-start","Python 快速上手：写给有编程基础的人","已经会其他语言，想快速掌握 Python 的语法特性和思维方式，这篇是捷径。",[121,147,148],"入门","基础",1607,{"slug":151,"title":152,"description":153,"pub_date":56,"tags":154,"draft":14,"word_count":158},"python-dataclass-pydantic","Python dataclass vs Pydantic：数据类选型指南","dataclass 是标准库的轻量选择，Pydantic v2 是带验证的重武器，什么时候用哪个，这篇说清楚。",[121,155,156,157],"dataclass","pydantic","数据验证",1323,{"slug":160,"title":161,"description":162,"pub_date":56,"tags":163,"draft":14,"word_count":167},"python-asyncio-practical","Python asyncio 实战：从回调地狱到协程优雅","asyncio 是 Python 异步编程的核心，搞懂 event loop、Task、gather 这些概念才能写出真正高效的异步代码。",[121,164,165,166],"asyncio","并发","网络编程",1258,{"slug":169,"title":170,"description":171,"pub_date":56,"tags":172,"draft":14,"word_count":176},"python-type-hints-guide","Python 类型注解完全指南：从入门到实践","Python 3.5+ 引入类型注解，配合 mypy\u002Fpyright 让 Python 也能享受静态类型检查的好处。",[121,173,174,175],"typescript-style","type-hints","工具链",1102,{"slug":178,"title":179,"description":180,"pub_date":181,"tags":182,"draft":14,"word_count":186},"pwa-install-update-button","PWA 踩坑：为什么安装按钮从来不出现","从 beforeinstallprompt 到 Service Worker waiting，把 PWA 的安装与更新提示真正做对","2026-05-02",[183,184,185],"pwa","javascript","web",1683,{"slug":188,"title":189,"description":190,"pub_date":191,"tags":192,"draft":14,"word_count":193},"openclaw-vs-hermes-agent","OpenClaw vs Hermes Agent：两个本地优先 Agent 的设计差异","OpenClaw（Novita AI）和 Hermes Agent（Nous Research）都是本地运行的个人 AI Agent，但在记忆系统、技能学习、运行环境和模型生态上走了不同的路。深入对比两种架构的核心差异。","2026-05-01",[58,22,59],1679,{"slug":195,"title":196,"description":197,"pub_date":191,"tags":198,"draft":14,"word_count":203},"cpp-random-design-patterns","C++ 设计模式实战：RAII、观察者、工厂","用现代 C++（C++17\u002F20）实现三种高频设计模式：RAII 资源管理、观察者模式事件系统、工厂模式插件架构。每种模式给出问题场景、实现代码和真实工程案例。",[199,200,201,202],"cpp","设计模式","c++17","工程",2613,{"slug":205,"title":206,"description":207,"pub_date":191,"tags":208,"draft":14,"word_count":209},"data-structures-fundamentals","数据结构基础：从数组到红黑树","系统梳理常用数据结构的核心原理、时间复杂度和适用场景。数组、链表、栈、队列、哈希表、二叉树、堆、图，每种结构附实现要点和 C++ 代码片段。",[140,11,199,148],3004,{"slug":211,"title":212,"description":213,"pub_date":214,"tags":215,"draft":14,"word_count":216},"ai-agent-what-is","什么是 AI Agent？从 LLM 到自主执行","LLM 本身是无状态问答机，Agent 是什么让它’动’起来的？本文深入解析 Agent 的四个核心能力、ReAct 框架、工具调用原理，以及主流框架横向对比。","2026-04-30",[58,22,59],2116,{"slug":218,"title":219,"description":220,"pub_date":214,"tags":221,"draft":14,"word_count":222},"ai-agent-memory","AI Agent 的记忆系统：从上下文窗口到长期记忆","深入拆解 AI Agent 的四种记忆类型、上下文窗口压缩策略、RAG 向量检索原理，以及三种典型失败模式和工程选型建议。",[58,22,67],2052,{"slug":224,"title":225,"description":226,"pub_date":214,"tags":227,"draft":14,"word_count":231},"network-proxy-vpn-guide","代理与翻墙技术原理：从 HTTP 代理到现代协议","深入解析代理与 VPN 的本质区别，梳理从 SOCKS5 到 Shadowsocks、V2Ray\u002FXray、Hysteria2 的协议演进，以及机场订阅的技术本质。",[228,229,230],"网络","代理","协议",2148,{"slug":233,"title":234,"description":235,"pub_date":214,"tags":236,"draft":14,"word_count":149},"algorithm-binary-search","二分查找：永远写不对？记住这个模板","彻底搞清楚二分查找的边界问题：闭区间和左闭右开两套模板、三道经典 LeetCode 题目完整 C++ 实现，以及二分答案的进阶思路。",[11,237,13,199],"二分查找",{"slug":239,"title":240,"description":241,"pub_date":214,"tags":242,"draft":14,"word_count":244},"algorithm-sliding-window","滑动窗口算法：从暴力到 O(n) 的思维跃迁","系统讲解滑动窗口算法的核心模板、适用题型，配合三道经典 LeetCode 题目的完整 C++ 实现，彻底理解双指针收缩思路。",[11,243,13,199],"滑动窗口",1943,{"slug":246,"title":247,"description":248,"pub_date":214,"tags":249,"draft":14,"word_count":252},"network-clash-config","Clash \u002F Mihomo 配置详解：规则、策略组与分流","深入解析 Clash\u002FMihomo 的核心配置结构，包括代理节点、策略组类型、规则优先级、DNS fake-ip 模式，以及一份实用的完整配置模板。",[228,250,229,251],"clash","配置",1292,{"slug":254,"title":255,"description":256,"pub_date":257,"tags":258,"draft":14,"word_count":262},"hid-hotplug","HID 设备热插拔检测：从 udev 到 node-hid","在 Linux 上用 node-hid + usb 库实现可靠的 USB HID 设备热插拔检测，踩坑记录","2026-04-28",[199,259,35,260,261],"hid","nodejs","electron",2039,{"slug":264,"title":265,"description":266,"pub_date":267,"tags":268,"draft":14,"word_count":271},"electron-ipc-types","Electron IPC 类型安全：从 any 到完全类型化","用 TypeScript 泛型封装 Electron IPC，彻底消灭 any，preload 契约集中管理","2026-04-25",[261,102,269,270],"ipc","vue",1446,{"slug":273,"title":274,"description":275,"pub_date":276,"tags":277,"draft":14,"word_count":280},"element-plus-popover-hide","手动关闭多个 el-popover（不用 v-model:visible）","通过 ref + Reflect.get 调用 hide() 方法手动关闭 Element Plus Popover，解释 Vue3 Proxy 导致无法直接调用实例方法的原因。","2024-10-25",[270,278,279],"element-plus","vue3",1321,{"slug":282,"title":283,"description":284,"pub_date":285,"tags":286,"draft":14,"word_count":290},"vite-vue3-ts-elementplus-pinia","用 Vite+（vp）从零搭建 Vue3 + TypeScript + Element Plus + Pinia + Vue Router","使用 Vite+ 统一工具链（vp）一条命令搭建 Vue3 全家桶，涵盖按需导入、Pinia store、路由配置，以及常见坑的解决方案。","2024-08-27",[270,287,102,278,288,289],"vite","pinia","vite-plus",1960,{"slug":292,"title":293,"description":294,"pub_date":295,"tags":296,"draft":14,"word_count":300},"cef-lnk2038-iterator-debug-level","CEF LNK2038：解决 _ITERATOR_DEBUG_LEVEL 不匹配错误","分析 CEF（Chromium Embedded Framework）集成时出现的 LNK2038 _ITERATOR_DEBUG_LEVEL 链接错误，从根本原因到解决方案的完整指南。","2024-05-07",[199,297,298,299],"CEF","Visual Studio","链接错误",1509,{"slug":302,"title":303,"description":304,"pub_date":305,"tags":306,"draft":14,"word_count":310},"npm-electron-install-fix","彻底解决 npm 安装 Electron 失败的问题","分析 npm install electron 失败的根本原因（下载二进制超时\u002F被墙），通过国内镜像（npmmirror）彻底解决，并介绍多种备选方案和常见错误排查。","2024-03-01",[261,307,308,309],"npm","前端工具链","国内镜像",1494,{"slug":312,"title":313,"description":314,"pub_date":315,"tags":316,"draft":14,"word_count":318},"git-out-of-memory","解决 git 报错：Fatal: Out of memory, malloc failed","分析 git 大仓库操作时出现 Out of memory malloc failed 的根本原因，通过调整 pack.windowMemory、http.postBuffer 和 git repack 彻底解决。","2024-01-31",[74,35,317],"工具",2244,{"slug":320,"title":321,"description":322,"pub_date":323,"tags":324,"draft":14,"word_count":328},"vmware-tools-install","在 VMware 虚拟机中安装 open-vm-tools 完整指南","详解 VMware Tools 的作用、open-vm-tools 与官方 VMware Tools 的区别，以及在 Ubuntu 虚拟机中安装并生效的完整步骤和常见问题排查。","2023-11-21",[325,35,326,327],"VMware","Ubuntu","虚拟机",2523,{"slug":330,"title":331,"description":332,"pub_date":333,"tags":334,"draft":14,"word_count":339},"load-balancing-algorithms","负载均衡算法完全指南：从轮询到一致性哈希","系统梳理静态与动态负载均衡算法，涵盖轮询、随机、权重、IP Hash、一致性 Hash、最少连接、最快响应等，并对比 Nginx、Dubbo、Spring Cloud LoadBalancer 的实现差异。","2023-11-15",[335,336,337,338],"分布式","负载均衡","Nginx","微服务",1764,{"slug":341,"title":342,"description":343,"pub_date":344,"tags":345,"draft":14,"word_count":349},"win-cw2a-ca2w","ATL 字符串转换：CW2A 与 CA2W 完全指南","详解 ATL 宏 CW2A\u002FCA2W 在 Unicode 与 ANSI 之间的字符串转换用法、头文件依赖、USES_CONVERSION 宏的作用与常见陷阱。","2023-06-09",[199,346,347,348],"windows","ATL","字符串",1665,{"slug":351,"title":352,"description":353,"pub_date":344,"tags":354,"draft":14,"word_count":358},"csharp-sendmessage-cpp","C# 通过 SendMessage 向 C++ 窗口发送消息与字符串","使用 P\u002FInvoke 调用 user32.dll 的 SendMessage，从 C# 发送自定义 WM_USER 消息及字符串指针给 C++ 原生窗口，并在 C++ 侧正确接收和转换。",[355,199,346,356,357],"C#","互操作","PInvoke",1554,{"slug":360,"title":361,"description":362,"pub_date":363,"tags":364,"draft":14,"word_count":366},"win-postmessage-vector","Windows PostMessage 跨线程传递 std::vector 指针","通过 PostMessage 在 Windows 消息队列中传递 std::vector 指针，使用 reinterpret_cast 将指针装入 LPARAM，并在接收方正确释放内存。","2023-05-26",[199,346,365],"WinAPI",1823,{"slug":368,"title":369,"description":370,"pub_date":363,"tags":371,"draft":14,"word_count":372},"exe-dll-single-package","将 EXE 和 DLL 打包成单一可执行文件","介绍两种将 exe 和依赖 dll 打包成单文件的方案：Enigma Virtual Box 和 WinRAR 自解压，适合发布 Windows 桌面程序时简化分发流程。",[346,199,317],1619,{"slug":374,"title":375,"description":376,"pub_date":363,"tags":377,"draft":14,"word_count":380},"cpp-random-mt19937","C++ 现代随机数生成：用 mt19937 彻底告别 rand()","深入讲解为什么 rand() 不够用，以及如何用 C++11 的 \u003Crandom> 库正确生成高质量随机数，涵盖 mt19937、各种分布和线程安全。",[199,378,379],"c++11","random",1549,{"slug":382,"title":383,"description":384,"pub_date":385,"tags":386,"draft":14,"word_count":388},"win-startup-registry","C++ 实现程序开机自启动：注册表方式详解","通过操作 Windows 注册表 Run 键实现程序开机自启动，包括 HKCU 与 HKLM 区别、完整封装代码、工作目录问题和 UAC 权限处理。","2022-12-26",[346,199,387],"registry",1201,{"slug":390,"title":391,"description":392,"pub_date":393,"tags":394,"draft":14,"word_count":396},"mfc-cstring-wparam","MFC 中 CString 与 WPARAM 之间的转换","详解 MFC 消息传递中 CString 无法直接强转为 WPARAM 的原因，以及两种正确的转换方案，并介绍结构体指针传递的正确姿势。","2022-11-25",[395,199,346],"mfc",1546,{"slug":398,"title":399,"description":400,"pub_date":401,"tags":402,"draft":14,"word_count":404},"duilib-static-build","正确编译 Duilib 静态库：避免 ATL 依赖和链接错误","详解如何用 DuiLib_Static.vcxproj 编译 Duilib 静态库，解决 VARIANT 未定义、Unicode 配置不匹配和 ATL 依赖等常见问题。","2022-08-24",[199,403,346,395],"duilib",2639,{"slug":406,"title":407,"description":408,"pub_date":409,"tags":410,"draft":14,"word_count":412},"mfc-dpi-adaptive","MFC 界面自适应不同分辨率","MFC 对话框程序实现控件和字体随分辨率自动缩放的完整方案，附 DPI Awareness 配置说明","2022-08-17",[395,199,346,411],"dpi",1414,{"slug":414,"title":415,"description":416,"pub_date":417,"tags":418,"draft":14,"word_count":419},"mfc-drag-window","MFC 无标题栏窗口客户区拖动：三种方法对比","MFC 对话框去掉标题栏后如何实现拖动移动窗口，三种方案完整实现与适用场景分析","2022-08-16",[395,199,346],1633,{"slug":4,"title":5,"description":6,"pub_date":9,"tags":421,"draft":14,"word_count":422},[11,12,13],1374,[]]