<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>liubang's blog</title><link>https://blog.liubang.cc/</link><description>刘邦的博客</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>Copyright © 2019-2026 LiuBang. All Rights Reserved.</copyright><lastBuildDate>Mon, 13 Apr 2026 18:24:16 +0200</lastBuildDate><atom:link href="https://blog.liubang.cc/index.xml" rel="self" type="application/rss+xml"/><item><title>一文讲透 AI 九大核心概念</title><link>https://blog.liubang.cc/posts/llm/2026-04-12-ai-ai-concepts-explained/</link><pubDate>Sun, 12 Apr 2026 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/llm/2026-04-12-ai-ai-concepts-explained/</guid><description>从工程视角拆解 LLM、Token、Context、RAG、Prompt、Tool、MCP、Agent 与 Agent Skill 这九个核心 AI 概念。</description></item><item><title>BloomFilter中的数学推导</title><link>https://blog.liubang.cc/posts/storage/2025-01-01-bloomfilter%E4%B8%AD%E7%9A%84%E6%95%B0%E5%AD%A6%E6%8E%A8%E5%AF%BC/</link><pubDate>Wed, 01 Jan 2025 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/storage/2025-01-01-bloomfilter%E4%B8%AD%E7%9A%84%E6%95%B0%E5%AD%A6%E6%8E%A8%E5%AF%BC/</guid><description>推导 Bloom Filter 的误判率公式，并给出最优哈希函数个数与位数组长度的数学结论。</description></item><item><title>使用LLVM的libFuzzer进行fuzzy test</title><link>https://blog.liubang.cc/posts/cpp/2023-05-23-%E4%BD%BF%E7%94%A8llvm%E7%9A%84libfuzzer%E8%BF%9B%E8%A1%8Cfuzzy-test/</link><pubDate>Tue, 23 May 2023 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2023-05-23-%E4%BD%BF%E7%94%A8llvm%E7%9A%84libfuzzer%E8%BF%9B%E8%A1%8Cfuzzy-test/</guid><description>通过一个最小示例介绍如何使用 LLVM libFuzzer 构建模糊测试，并定位程序中的崩溃问题。</description></item><item><title>322.零钱兑换</title><link>https://blog.liubang.cc/leetcode/dp/exercises/322.%E9%9B%B6%E9%92%B1%E5%85%91%E6%8D%A2/</link><pubDate>Wed, 19 Apr 2023 19:43:51 +0800</pubDate><guid>https://blog.liubang.cc/leetcode/dp/exercises/322.%E9%9B%B6%E9%92%B1%E5%85%91%E6%8D%A2/</guid><description>题目描述 给你一个整数数组 coins ，表示不同面额的硬币；以及一个整数 amount ，表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额，返回 -1 。 你可以认为每种硬币的数量是无限的。
题解 定义状态： $dp[i]$表示用所给的面值的硬币凑成金额$i$所需的最少的硬币个数。
设计状态转移方程： $$ \forall coin \in coins, 当 i \geqslant coin，且 dp[i - coin] \neq -1 时, dp[i] = std::min(dp[i], dp[i - coin] + 1) $$
初始化： 对于 amount 为 0 的情况，所需的硬币数也为 0，因此：$dp[0] = 0$
递推求解： 这里我们使用了一个小技巧，默认将$dp$的值都填充为INT_MAX，这样就可以避免对-1这个负数做特殊的判断和处理，相当于我们用INT_MAX 来代理了-1。
1#include &amp;lt;vector&amp;gt; 2#include &amp;lt;climits&amp;gt; 3 4class Solution { 5public: 6 int coinChange(const std::vector&amp;lt;int&amp;gt;&amp;amp; coins, int amount) { 7 std::vector&amp;lt;int&amp;gt; dp(amount + 1, INT_MAX); 8 dp[0] = 0; 9 for (int i = 1; i &amp;lt;= amount; ++i) { 10 for (int coin : coins) { 11 if (coin &amp;lt;= i &amp;amp;&amp;amp; dp[i - coin] != INT_MAX) { 12 dp[i] = std::min(dp[i], dp[i - coin] + 1); 13 } 14 } 15 } 16 return dp[amount] == INT_MAX ? -1 : dp[amount]; 17 } 18};</description></item><item><title>70.爬楼梯</title><link>https://blog.liubang.cc/leetcode/dp/exercises/70.%E7%88%AC%E6%A5%BC%E6%A2%AF/</link><pubDate>Wed, 19 Apr 2023 00:02:17 +0800</pubDate><guid>https://blog.liubang.cc/leetcode/dp/exercises/70.%E7%88%AC%E6%A5%BC%E6%A2%AF/</guid><description>题目描述 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢？
题解 这道题是一个非常典型而且很简单的动态规划题目。我们可以根据动态规划题目解题的一般思路来分析：
定义状态： $dp[i]$表示爬到第$i$级楼梯的不同方法数。由于每次可以选择爬 $1$ 级或者 $2$ 级楼梯， 所以爬到第 $i$ 级楼梯的方法数等于爬到第 $i-1$ 级楼梯和第 $i-2$ 级楼梯的方法数之和。 根据这个关系，我们可以使用动态规划的方式从 $1$ 级楼梯开始逐步计算到第 $n$ 级楼梯的方法数，最终返回 $dp[n]$即为结果。
设计状态转移方程： $$dp[i] = dp[i - 1] + dp[i - 2]$$
初始化： 由题目可知，$dp[0] = 0$; $dp[1] = 1$，这里需要特别注意的是，$dp[2] \ne dp[0] + dp[1]$，而是$dp[2] = 2$，所以$dp[2]$也应该作为初始值
递推求解： 1#include &amp;lt;vector&amp;gt; 2 3class Solution { 4public: 5 int climbStairs(int n) { 6 if (n &amp;lt;= 2) return n; 7 std::vector&amp;lt;int&amp;gt; dp(n + 1); 8 dp[1] = 1; 9 dp[2] = 2; 10 for (int i = 3; i &amp;lt;= n; ++i) { 11 dp[i] = dp[i - 1] + dp[i - 2]; 12 } 13 return dp[n]; 14 } 15}; 记忆优化： 从上面代码可以很容易发现，我们得出$dp[i]$只需要用到$dp[i - 1]$和$dp[i -2]$，其他的元素其实都用不到，所以上面的代码可以优化为：</description></item><item><title>416.分割等和子集</title><link>https://blog.liubang.cc/leetcode/dp/exercises/416/</link><pubDate>Sun, 16 Apr 2023 23:46:34 +0800</pubDate><guid>https://blog.liubang.cc/leetcode/dp/exercises/416/</guid><description>题目描述 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集，使得两个子集的元素和相等。
题解 由题可知，数组nums非空，所以分割后的两个子集也必然非空，由于都是正整数，所以nums中元素之和必然为偶数。
这道题是典型的 01 背包问题，假设$dp[i][j]$表示nums中前$i$个元素是否包含和为$j$的子集，那么：
当nums[i] = j的时候，dp[i][j] = true 当nums[i] &amp;gt; j的时候，dp[i][j] = dp[i - 1][j] 当nums[i] &amp;lt; j的时候，dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]] 1#include &amp;lt;vector&amp;gt; 2#include &amp;lt;numeric&amp;gt; 3 4class Solution { 5public: 6 bool canPartition(const std::vector&amp;lt;int&amp;gt;&amp;amp; nums) { 7 int size = nums.size(); 8 int sum = std::accumulate(nums.begin(), nums.end(), 0); 9 if (size == 1 || (sum &amp;amp; 1) == 1) return false; 10 int target = sum / 2; 11 std::vector&amp;lt;std::vector&amp;lt;bool&amp;gt;&amp;gt; dp(size + 1, std::vector&amp;lt;bool&amp;gt;(target + 1)); 12 for (int i = 1; i &amp;lt;= size; ++i) { 13 for (int j = 1; j &amp;lt;= target; ++j) { 14 int num = nums[i - 1]; 15 if (num == j) dp[i][j] = true; 16 else if (num &amp;gt; j) dp[i][j] = dp[i - 1][j]; 17 else dp[i][j] = dp[i - 1][j] | dp[i - 1][j - num]; 18 } 19 } 20 return dp[size][target]; 21 } 22};</description></item><item><title>155.最小栈</title><link>https://blog.liubang.cc/leetcode/stack/exercises/155/</link><pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/stack/exercises/155/</guid><description>题目描述 设计一个支持 push ，pop ，top 操作，并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化 void push(int val) 将元素推入堆栈 void pop() 删除堆栈顶部的元素 int pop() 获取堆栈顶部的元素 int getMin() 获取堆栈中的最小元素
题解： 这道题首先要满足堆栈的特性 LIFO，其次是能够在常数时间内获取当前栈中最小的元素，因此我们可以用堆栈保存 个二元组，二元组的第一个元素是存入栈中的值，第二个元素是当前元素作为栈顶元素的时候，栈中的最小值。有 了这个思路，代码实现起来就很简单了。
1class MinStack { 2public: 3 MinStack() = default; 4 5 void push(int val) { 6 stack_.emplace(val, std::min(val, getMin())); 7 } 8 9 void pop() { 10 stack_.pop(); 11 } 12 13 void top() { 14 return stack_.top().first; 15 } 16 17 int getMin() { 18 if (stack_.empty()) return INT_MAX; 19 return stack_.top().second; 20 } 21private: 22 std::stack&amp;lt;std::pair&amp;lt;int, int&amp;gt;&amp;gt; stack_; 23};</description></item><item><title>84. 柱状图中最大的矩形</title><link>https://blog.liubang.cc/leetcode/stack/exercises/84/</link><pubDate>Tue, 06 Dec 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/stack/exercises/84/</guid><description>题目描述 给定 n 个非负整数，用来表示柱状图中各个柱子的高度。每个柱子彼此相邻，且宽度为 1 。 求在该柱状图中，能够勾勒出来的矩形的最大面积。
解法一：暴力求解 主要思路是，遍历每个柱子，然后往柱子左右两边寻找比当前柱子矮的位置，从而计算出，以当前柱子为高度，所能围成的最大面积。 然后将这些面积中最大的值返回即可。暴力求解的时间复杂度为O(n^2)
不过我尝试过各种暴力求解，在 leetcode 中提交后都会超时。
1class Solution { 2public: 3 int largestRectangleInHistogram(const std::vector&amp;lt;int&amp;gt;&amp;amp; inputs) { 4 std::size_t n = inputs.size(); 5 int max_area = 0; 6 for (int i = 0; i &amp;lt; n; ++i) { 7 int min_height = INT_MAX; 8 for (int j = i; j &amp;lt; n; ++j) { 9 min_height = std::min(min_height, inputs[j]); 10 max_area = std::max(max_area, min_height * (j - i + 1)); 11 } 12 } 13 return max_area; 14 } 15}; 解法二：单调栈 1class Solution { 2public: 3 int largestRectangleInHistogram(const std::vector&amp;lt;int&amp;gt;&amp;amp; inputs) { 4 int n = inputs.size(); 5 std::stack&amp;lt;int&amp;gt; stk; 6 int ret = 0; 7 for (int i = 0; i &amp;lt; n; ++i) { 8 while (!stk.empty() &amp;amp;&amp;amp; inputs[stk.top()] &amp;gt; inputs[i]) { 9 int w = i; 10 int h = inputs[stk.top()]; 11 stk.pop(); 12 if (!stk.empty()) { 13 w = i - stk.top() - 1; 14 } 15 ret = std::max(ret, w * h); 16 } 17 stk.push(i); 18 } 19 while (!stk.empty()) { 20 int w = n; 21 int h = inputs[stk.top()]; 22 stk.pop(); 23 if (!stk.empty()) { 24 w = n - stk.top() - 1; 25 } 26 ret = std::max(ret, w * h); 27 } 28 29 return ret; 30 } 31};</description></item><item><title>141.环形链表</title><link>https://blog.liubang.cc/leetcode/linkedlist/exercises/141/</link><pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/linkedlist/exercises/141/</guid><description>题目描述 给你一个链表的头节点 head ，判断链表中是否有环。 如果链表中有某个节点，可以通过连续跟踪 next 指针再次到达，则链表中存在环。 为了表示给定链表中的环，评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置（索引从 0 开始）。注意：pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。 如果链表中存在环 ，则返回 true 。 否则，返回 false 。
解法一：hash 法 hash 法是我们在判断重复元素类问题中最常用的方法。针对链表是否有环来说，我们可以遍历链表，并用std::set 存放遍历过的元素，判断是否存在重复元素，如果存在则表示有环，如果遍历结束且不存在重复，则没有环。
1class Solution { 2public: 3 bool hasCycle(ListNode* head) { 4 std::set&amp;lt;ListNode*&amp;gt; set; 5 ListNode* cur = head; 6 while (cur) { 7 if (set.count(cur) &amp;gt; 0) return true; 8 set.insert(cur); 9 cur = cur-&amp;gt;next; 10 } 11 return false; 12 } 13}; 解法二：快慢指针 快慢指针就是用两个指针，一个一次移动一个位置，另一个一次移动两个位置，如果链表存在环，那么快的指针一定会 在某个地方和慢的指针重合，这个思路虽然很简单，但是具体的编码还是要多练习，不然也容易出错。</description></item><item><title>20.有效的括号</title><link>https://blog.liubang.cc/leetcode/stack/exercises/20/</link><pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/stack/exercises/20/</guid><description>题目描述 给定一个只包括 &amp;lsquo;(&amp;rsquo;，&amp;rsquo;)&amp;rsquo;，&amp;rsquo;{&amp;rsquo;，&amp;rsquo;}&amp;rsquo;，&amp;rsquo;[&amp;rsquo;，&amp;rsquo;]&amp;rsquo; 的字符串 s ，判断字符串是否有效。 有效字符串需满足： 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左括号。
解法一：stack 这道题目是典型的堆栈数据结构的应用，虽然思路很清晰，代码也很简单，但是要注意逻辑的严谨性。尤其是在判断 栈顶元素是否匹配之前，要先判断栈是否为空。
1class Solution { 2public: 3 bool isValid(const std::string&amp;amp; s) { 4 std::stack&amp;lt;char&amp;gt; st; 5 for (int i = 0; i &amp;lt; s.length(); ++i) { 6 char c = s[i]; 7 if (c == &amp;#39;(&amp;#39; || c == &amp;#39;{&amp;#39; || c == &amp;#39;[&amp;#39;) { 8 st.push(c); 9 } else { 10 if (st.empty()) return false; 11 if (c == &amp;#39;)&amp;#39; &amp;amp;&amp;amp; st.top() != &amp;#39;(&amp;#39;) return false; 12 if (c == &amp;#39;}&amp;#39; &amp;amp;&amp;amp; st.top() != &amp;#39;{&amp;#39;) return false; 13 if (c == &amp;#39;]&amp;#39; &amp;amp;&amp;amp; st.top() != &amp;#39;[&amp;#39;) return false; 14 st.pop(); 15 } 16 } 17 return st.empty(); 18 } 19};</description></item><item><title>206.反转链表</title><link>https://blog.liubang.cc/leetcode/linkedlist/exercises/206/</link><pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/linkedlist/exercises/206/</guid><description>题目描述 给你单链表的头节点 head ，请你反转链表，并返回反转后的链表。
解法一：迭代 迭代法应该是我们最容易想到的常规方法，也比较符合人的思维逻辑。其核心思想就是通过两个指针移动，来 一个一个的修改链表的指向方向。
1class Solution { 2public: 3 ListNode* reverseList(ListNode* head) { 4 if (!head || !head-&amp;gt;next) return head; 5 ListNode* prev = nullptr; 6 ListNode* cur = head; 7 while (cur) { 8 ListNode* tmp = cur-&amp;gt;next; 9 cur-&amp;gt;next = prev; 10 prev = cur; 11 cur = tmp; 12 } 13 return prev; 14 } 15}; 解法二：递归 第二个方法就是使用递归，递归这种方法虽然不太容易能够想到，但是代码却很简洁。</description></item><item><title>225.用队列实现栈</title><link>https://blog.liubang.cc/leetcode/queue/exercises/225/</link><pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/queue/exercises/225/</guid><description>题目描述 请你仅使用两个队列实现一个后入先出（LIFO）的栈，并支持普通栈的全部四种操作（push、top、pop 和 empty）。
实现 MyStack 类：
void push(int x) 将元素 x 压入栈顶。 int pop() 移除并返回栈顶元素。 int top() 返回栈顶元素。 boolean empty() 如果栈是空的，返回 true ；否则，返回 false 。 注意：
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。 你所使用的语言也许不支持队列。 你可以使用 list （列表）或者 deque（双端队列）来模拟一个队列 , 只要是标准的队列操作即可。
题解 队列是 FIFO 的，而堆栈是 LIFO，要想用队列模拟堆栈，就需要在取出元素的时候，将一个队列中的除了最后一个元素的其他移动到另一个队列中，然后返回最后一个元素即可。
1class MyStack { 2public: 3 MyStack() = default; 4 5 int push(int x) { 6 auto&amp;amp; q = q1_.size() &amp;gt; 0 : q1_ ? q2_; 7 q.push(x); 8 } 9 10 int pop() { 11 std::queue&amp;lt;int&amp;gt;&amp;amp; i = q1_.size() &amp;gt; 0 ? q1_ : q2_; 12 std::queue&amp;lt;int&amp;gt;&amp;amp; o = q1_.size() &amp;gt; 0 ? q2_ : q1_; 13 14 while (i.size() &amp;gt; 1) { 15 o.push(i.front()); 16 i.pop(); 17 } 18 int ret = i.front(); 19 i.pop(); 20 return ret; 21 } 22 23 int top() { 24 std::queue&amp;lt;int&amp;gt;&amp;amp; i = q1_.size() &amp;gt; 0 ? q1_ : q2_; 25 std::queue&amp;lt;int&amp;gt;&amp;amp; o = q1_.size() &amp;gt; 0 ? q2_ : q1_; 26 27 while (i.size() &amp;gt; 1) { 28 o.push(i.front()); 29 i.pop(); 30 } 31 int ret = i.front(); 32 i.pop(); 33 o.push(ret); 34 return ret; 35 } 36 37 bool empty() { 38 return q1_.empty() &amp;amp;&amp;amp; q2_.empty(); 39 } 40private: 41 std::queue&amp;lt;int&amp;gt; q1_; 42 std::queue&amp;lt;int&amp;gt; q2_; 43};</description></item><item><title>232.用栈实现队列</title><link>https://blog.liubang.cc/leetcode/stack/exercises/232/</link><pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/stack/exercises/232/</guid><description>题目描述 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作（push、pop、peek、empty）： 实现 MyQueue 类：
void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返回队列开头的元素 boolean empty() 如果队列为空，返回 true ；否则，返回 false 说明： 你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。 你所使用的语言也许不支持栈。你可以使用 list 或者 deque（双端队列）来模拟一个栈，只要是标准的栈操作即可。
题解 堆栈的特性是 LIFO，而队列则是 FIFO，因此想要用堆栈实现队列，需要用两个堆栈的 LIFO 叠加效果，来实现 FIFO。
1class MyQueue { 2public: 3 MyQueue() = default; 4 5 void push(int x) { 6 while (!output_.empty()) { 7 input_.push(output_.top()); 8 output_.pop(); 9 } 10 input_.push(x); 11 } 12 13 int pop() { 14 while (!input_.empty()) { 15 output_.push(input_.top()); 16 input_.pop(); 17 } 18 int ret = output_.top(); 19 output_.pop(); 20 return ret; 21 } 22 23 int peek() { 24 while (!input_.empty()) { 25 output_.push(input_.top()); 26 input_.pop(); 27 } 28 return output_.top(); 29 } 30 31 bool empty() { 32 return input_.empty() &amp;amp;&amp;amp; output_.empty(); 33 } 34private: 35 std::stack&amp;lt;int&amp;gt; input_; 36 std::stack&amp;lt;int&amp;gt; output_; 37};</description></item><item><title>24.两两交换链表中的节点</title><link>https://blog.liubang.cc/leetcode/linkedlist/exercises/24/</link><pubDate>Wed, 30 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/leetcode/linkedlist/exercises/24/</guid><description>题目描述 给你一个链表，两两交换其中相邻的节点，并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题（即，只能进行节点交换）。
方法一：递归 这道题，最最简洁的方法应该就是使用递归了。主要思路是，每两个一组，进行交换，然后递归执行。
1class Solution { 2public: 3 LinkedList* swapPairs(LinkedList* head) { 4 if (!head || !head-&amp;gt;next) return head; 5 // 当前组下的新的head 6 LinkedList* newHead = head-&amp;gt;next; 7 head-&amp;gt;next = swapPairs(newHead-&amp;gt;next); 8 newHead-&amp;gt;next = head; 9 return newHead; 10 } 11};</description></item><item><title>Rust和C++: 泛型和特例化</title><link>https://blog.liubang.cc/posts/rust/2022-11-13-rust%E5%92%8Cc++%E5%AF%B9%E6%AF%94%E4%B9%8B%E6%B3%9B%E5%9E%8B%E5%92%8C%E7%89%B9%E4%BE%8B%E5%8C%96/</link><pubDate>Sat, 12 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/rust/2022-11-13-rust%E5%92%8Cc++%E5%AF%B9%E6%AF%94%E4%B9%8B%E6%B3%9B%E5%9E%8B%E5%92%8C%E7%89%B9%E4%BE%8B%E5%8C%96/</guid><description>对比 Rust 与 C++ 在泛型、trait 约束和特例化机制上的异同与实践方式。</description></item><item><title>130.被围绕的区域</title><link>https://blog.liubang.cc/leetcode/union-find/exercises/130/</link><pubDate>Mon, 07 Nov 2022 19:56:00 +0800</pubDate><guid>https://blog.liubang.cc/leetcode/union-find/exercises/130/</guid><description>题目描述 给你一个 m x n 的矩阵 board ，由若干字符 &amp;lsquo;X&amp;rsquo; 和 &amp;lsquo;O&amp;rsquo; ，找到所有被 &amp;lsquo;X&amp;rsquo; 围绕的区域，并将这些区域里所有的 &amp;lsquo;O&amp;rsquo; 用 &amp;lsquo;X&amp;rsquo; 填充。
解法一：并查集 这道题通常会用DFS来解，但是也可以用并查集解：首先我们将四条边上的&amp;rsquo;O&amp;rsquo;合并成一个连通分量，然后再将圈内的所有相邻的 &amp;lsquo;O&amp;rsquo;连接起来，最后遍历整个表，将所有为&amp;rsquo;O&amp;rsquo;且不与四条边上的&amp;rsquo;O&amp;rsquo;所在的连通分量相连的节点设置为&amp;rsquo;X&amp;rsquo;即可。
1#include &amp;lt;vector&amp;gt; 2#include &amp;lt;unordered_map&amp;gt; 3 4class UnionFind { 5public: 6 UnionFind(int num) { 7 for (int i = 0; i &amp;lt; num; ++i) { 8 parent_.push_back(i); 9 } 10 } 11 12 void unite(int p, int q) { 13 int pRoot = find(p); 14 int qRoot = find(q); 15 if (pRoot == qRoot) { 16 return; 17 } 18 parent_[pRoot] = qRoot; 19 } 20 21 bool connected(int p, int q) { 22 return find(p) == find(q); 23 } 24 25 int find(int p) { 26 if (p != parent_[p]) { 27 parent_[p] = find(parent_[p]); 28 } 29 return parent_[p]; 30 } 31 32private: 33 std::vector&amp;lt;int&amp;gt; parent_; 34}; 35 36class Solution { 37public: 38 void solve(std::vector&amp;lt;std::vector&amp;lt;char&amp;gt;&amp;gt;&amp;amp; board) { 39 int m = board.size(); 40 int n = board[0].size(); 41 UnionFind uf(m * n + 1); 42 int dummy = m * n; 43 // 先将四条边上为&amp;#39;O&amp;#39;的节点连接起来 44 for (int i = 0; i &amp;lt; m; ++i) { 45 if (board[i][0] == &amp;#39;O&amp;#39;) { 46 uf.unite(dummy, i * n); 47 } 48 if (board[i][n - 1] == &amp;#39;O&amp;#39;) { 49 uf.unite(dummy, i * n + n - 1); 50 } 51 } 52 for (int j = 0; j &amp;lt; n; ++j) { 53 if (board[0][j] == &amp;#39;O&amp;#39;) { 54 uf.unite(dummy, j); 55 } 56 if (board[m - 1][j] == &amp;#39;O&amp;#39;) { 57 uf.unite(dummy, (m - 1) * n + j); 58 } 59 } 60 // 再将内部相邻的&amp;#39;O&amp;#39;连接起来 61 // 上 下 左 右 62 std::vector&amp;lt;std::vector&amp;lt;int&amp;gt;&amp;gt; directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 63 for (int i = 1; i &amp;lt; m - 1; ++i) { 64 for (int j = 1; j &amp;lt; n - 1; ++j) { 65 if (board[i][j] == &amp;#39;X&amp;#39;) continue; 66 for (const auto&amp;amp; dir : directions) { 67 if (board[i + dir[0]][j + dir[1]] == &amp;#39;X&amp;#39;) continue; 68 uf.unite(n * i + j, n * (i + dir[0]) + j + dir[1]); 69 } 70 } 71 } 72 73 // 最后将所有不与dummy连通的&amp;#39;O&amp;#39;设置为&amp;#39;X&amp;#39;即可 74 for (int i = 1; i &amp;lt; m; ++i) { 75 for (int j = 1; j &amp;lt; n; ++j) { 76 if (board[i][j] == &amp;#39;O&amp;#39; &amp;amp;&amp;amp; !uf.connected(dummy, n * i + j)) { 77 board[i][j] = &amp;#39;X&amp;#39;; 78 } 79 } 80 } 81 } 82};</description></item><item><title>990.等式方程的可满足性</title><link>https://blog.liubang.cc/leetcode/union-find/exercises/990/</link><pubDate>Sun, 06 Nov 2022 22:11:25 +0800</pubDate><guid>https://blog.liubang.cc/leetcode/union-find/exercises/990/</guid><description>题目描述 给定一个由表示变量之间关系的字符串方程组成的数组，每个字符串方程equations[i]的长度为 4，并采用两种不同的形式之一：&amp;quot;a==b&amp;quot; 或 &amp;quot;a!=b&amp;quot;。在这里，a 和 b 是小写字母（不一定不同），表示单字母变量名。 只有当可以将整数分配给变量名，以便满足所有给定的方程时才返回 true，否则返回 false。
题解 这一道题，显然是用并查集来解决，思路很简单，由于相等具有传递性，可以认为，一开始所有的字母变量都是独立的 集合，通过等式传递性，可以将这些相等的字母合并到同一个集合，最后看不等式中，是否存在连通的字母，如果存在 则表示等式方程不满足条件。
1#include &amp;lt;vector&amp;gt; 2#include &amp;lt;unordered_map&amp;gt; 3 4class UnionFind { 5public: 6 UnionFind(int num) { 7 for (int i = 0; i &amp;lt; num; ++i) { 8 parent_.push_back(i); 9 } 10 } 11 12 void unite(int p, int q) { 13 int pRoot = find(p); 14 int qRoot = find(q); 15 if (pRoot == qRoot) { 16 return; 17 } 18 parent_[pRoot] = qRoot; 19 } 20 21 int find(int p) { 22 if (p != parent_[p]) { 23 parent_[p] = find(parent_[p]); 24 } 25 return parent_[p]; 26 } 27 28private: 29 std::vector&amp;lt;int&amp;gt; parent_; 30}; 31 32class Solution { 33public: 34 bool equationsPossible(const std::vector&amp;lt;std::string&amp;gt;&amp;amp; equations) { 35 // 26个小写字母 36 UnionFind uf(26); 37 for (const auto&amp;amp; e : equations) { 38 if (e[1] == &amp;#39;!&amp;#39;) { 39 continue; 40 } 41 uf.unite(e[0] - &amp;#39;a&amp;#39;, e[3] - &amp;#39;a&amp;#39;); 42 } 43 for (const auto&amp;amp; e : equations) { 44 if (e[1] == &amp;#39;=&amp;#39;) { 45 continue; 46 } 47 if (uf.find(e[0] - &amp;#39;a&amp;#39;) == uf.find(e[3] - &amp;#39;a&amp;#39;)) { 48 return false; 49 } 50 } 51 return true; 52 } 53};</description></item><item><title>128.最长连续序列</title><link>https://blog.liubang.cc/leetcode/union-find/exercises/128/</link><pubDate>Sat, 05 Nov 2022 18:05:26 +0800</pubDate><guid>https://blog.liubang.cc/leetcode/union-find/exercises/128/</guid><description>题目描述 给定一个未排序的整数数nums，找出数字连续的最长序列（不要求序列元素在原数组中连续）的长度。 请你设计并实现时间复杂度O(n)的算法解决此问题。
解法一：并查集 这道题目可以用并查集来解决。初始状态下数组中的每个元素都是一个独立的集合，然后遍历数组，将当前元素相邻的 元素合并到一个集合，最后返回所有集合中元素个数最多的数量。这里要注意去重。
1#include &amp;lt;vector&amp;gt; 2#include &amp;lt;unordered_map&amp;gt; 3 4class UnionFind { 5public: 6 UnionFind(int num) { 7 for (int i = 0; i &amp;lt; num; ++i) { 8 parent_.push_back(i); 9 size_.push_back(1); 10 } 11 } 12 13 void unite(int p, int q) { 14 int pRoot = find(p); 15 int qRoot = find(q); 16 if (pRoot == qRoot) { 17 return; 18 } 19 parent_[pRoot] = qRoot; 20 size_[qRoot] += size_[pRoot]; 21 } 22 23 int find(int p) { 24 if (p != parent_[p]) { 25 parent_[p] = find(parent_[p]); 26 } 27 return parent_[p]; 28 } 29 30 int maxConnectedSize() { 31 int ret = 0; 32 for (int i = 0; i &amp;lt; parent_.size(); ++i) { 33 if (parent_[i] == i) { 34 ret = std::max(ret, size_[i]); 35 } 36 } 37 return ret; 38 } 39 40private: 41 std::vector&amp;lt;int&amp;gt; parent_; 42 std::vector&amp;lt;int&amp;gt; size_; 43}; 44 45class Solution { 46public: 47 int longestConsecutive(std::vector&amp;lt;int&amp;gt;&amp;amp; nums) { 48 49 // 用于记录元素和下标的对应关系，同时也用来去重 50 std::unordered_map map; 51 52 // 构造一个并查集实例，以下标来表示nums中的一个数字 53 // 初始状态下，每个元素都是独立的集合 54 UnionFind uf(nums.size()); 55 56 for (int i = 0; i &amp;lt; nums.size(); ++i) { 57 // 去重 58 if (map.find(nums[i]) != map.end()) { 59 continue; 60 } 61 62 // 将比当前元素小1的元素连接起来 63 if (map.find(nums[i] - 1) != map.end()) { 64 uf.unite(i, map[nums[i] - 1]); 65 } 66 67 // 将比当前元素大1的元素连接起来 68 if (map.find(nums[i] + 1) != map.end()) { 69 uf.unite(i, map[nums[i] + 1]); 70 } 71 72 // 记录元素和下标的对应关系 73 map[nums[i]] = i; 74 } 75 76 // 返回最终所有集合中，元素最多的集合的元素个数 77 return uf.maxConnectedSize(); 78 } 79};</description></item><item><title>Rust和C++: 可变性、移动和所有权</title><link>https://blog.liubang.cc/posts/rust/2022-11-01-rust%E5%92%8Cc++%E5%AF%B9%E6%AF%94%E4%B9%8B%E5%8F%AF%E5%8F%98%E6%80%A7%E7%A7%BB%E5%8A%A8%E5%92%8C%E6%89%80%E6%9C%89%E6%9D%83/</link><pubDate>Tue, 01 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/rust/2022-11-01-rust%E5%92%8Cc++%E5%AF%B9%E6%AF%94%E4%B9%8B%E5%8F%AF%E5%8F%98%E6%80%A7%E7%A7%BB%E5%8A%A8%E5%92%8C%E6%89%80%E6%9C%89%E6%9D%83/</guid><description>对比 Rust 与 C++ 在可变性、移动语义和所有权模型上的核心差异与设计取舍。</description></item><item><title>为什么c++中有了函数指针却还需要std::function</title><link>https://blog.liubang.cc/posts/cpp/2022-09-28-%E4%B8%BA%E4%BB%80%E4%B9%88c++%E4%B8%AD%E6%9C%89%E4%BA%86%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88%E5%8D%B4%E8%BF%98%E9%9C%80%E8%A6%81stdfunction/</link><pubDate>Wed, 28 Sep 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-09-28-%E4%B8%BA%E4%BB%80%E4%B9%88c++%E4%B8%AD%E6%9C%89%E4%BA%86%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88%E5%8D%B4%E8%BF%98%E9%9C%80%E8%A6%81stdfunction/</guid><description>在C/C++中，我们经常会像下面的代码那样使用一个指向函数的指针，我们称之为函数指针。</description></item><item><title>使用std::list的splice方法实现LRU Cache</title><link>https://blog.liubang.cc/posts/cpp/2022-05-15-%E4%BD%BF%E7%94%A8stdlist%E7%9A%84splice%E6%96%B9%E6%B3%95%E5%AE%9E%E7%8E%B0lru-cache/</link><pubDate>Sun, 15 May 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-05-15-%E4%BD%BF%E7%94%A8stdlist%E7%9A%84splice%E6%96%B9%E6%B3%95%E5%AE%9E%E7%8E%B0lru-cache/</guid><description>利用 std::list::splice 的常数时间节点移动能力，实现一个高效的 LRU Cache。</description></item><item><title>深入理解 enable_shared_from_this</title><link>https://blog.liubang.cc/posts/cpp/2022-05-03-%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3enable_shared_from_this/</link><pubDate>Tue, 03 May 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-05-03-%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3enable_shared_from_this/</guid><description>shared_ptr是一种共享所有权的智能指针，它允许我们安全地访问和管理对象的生命周期。shared_ptr的多个实例通过共享控制块结构来控制对象的生命周期。</description></item><item><title>c++ 中 unique_ptr 的一些使用技巧</title><link>https://blog.liubang.cc/posts/cpp/2022-04-20-c++%E4%B8%ADunique_ptr%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/</link><pubDate>Wed, 20 Apr 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-04-20-c++%E4%B8%ADunique_ptr%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7/</guid><description>c++11 对智能指针做了很大的优化，废弃了 c++98 中的auto_ptr，引入了三种新的智能指针：unique_ptr，shared_ptr，weak_ptr。</description></item><item><title>Expression Templates</title><link>https://blog.liubang.cc/posts/cpp/2022-04-06-expression-templates/</link><pubDate>Wed, 06 Apr 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-04-06-expression-templates/</guid><description>介绍 Expression Templates 的基本思路，以及它如何通过延迟求值减少中间对象和额外开销。</description></item><item><title>c++中的动态多态和静态多态</title><link>https://blog.liubang.cc/posts/cpp/2022-03-23-c++%E4%B8%AD%E7%9A%84%E5%8A%A8%E6%80%81%E5%A4%9A%E6%80%81%E5%92%8C%E9%9D%99%E6%80%81%E5%A4%9A%E6%80%81/</link><pubDate>Wed, 23 Mar 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-03-23-c++%E4%B8%AD%E7%9A%84%E5%8A%A8%E6%80%81%E5%A4%9A%E6%80%81%E5%92%8C%E9%9D%99%E6%80%81%E5%A4%9A%E6%80%81/</guid><description>对比 C++ 中基于虚函数表的动态多态与模板驱动的静态多态，理解两者的实现原理与取舍。</description></item><item><title>c++17:constexpr if</title><link>https://blog.liubang.cc/posts/cpp/2022-03-18-c++17-constexpr_if/</link><pubDate>Fri, 18 Mar 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-03-18-c++17-constexpr_if/</guid><description>constexpr 是 c++11 引入的关键字，用于编译时常量和常量表达式。而 c++17 将这一特性做了增强，引入了 constexpr if。</description></item><item><title>c++20:Designated Initializers</title><link>https://blog.liubang.cc/posts/cpp/2022-03-15-c++20-designated_initializers/</link><pubDate>Tue, 15 Mar 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-03-15-c++20-designated_initializers/</guid><description>对于熟悉 c99 的人来说，Designated Initializers 并不算是什么新鲜事物，然而 c++直到 c++20 才正式支持这一特性。</description></item><item><title>Linux磁盘IO</title><link>https://blog.liubang.cc/posts/linux/2022-02-25-linux%E7%A3%81%E7%9B%98io/</link><pubDate>Fri, 25 Feb 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/linux/2022-02-25-linux%E7%A3%81%E7%9B%98io/</guid><description>从块设备与页缓存讲起，梳理 Linux 磁盘 I/O 的核心路径、关键组件与工作机制。</description></item><item><title>c++元编程之遍历tuple</title><link>https://blog.liubang.cc/posts/cpp/2022-02-22-c++%E5%85%83%E7%BC%96%E7%A8%8B%E4%B9%8B%E9%81%8D%E5%8E%86tuple/</link><pubDate>Tue, 22 Feb 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-02-22-c++%E5%85%83%E7%BC%96%E7%A8%8B%E4%B9%8B%E9%81%8D%E5%8E%86tuple/</guid><description>对于一个标准的 c++容器来说，我们可以很容易在运行时使用迭代器和 range-based for。</description></item><item><title>c++17:string_view</title><link>https://blog.liubang.cc/posts/cpp/2022-02-14-c++17%E4%B9%8Bstring_view/</link><pubDate>Mon, 14 Feb 2022 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2022-02-14-c++17%E4%B9%8Bstring_view/</guid><description>std::string_view是 c++17 中新增的一种类型。其核心理念是，能够让我们在传统的 C++03 风格的具体性和泛型编程之间找到一个很好的折衷点。</description></item><item><title>LevelDB 源码阅读之 Compaction</title><link>https://blog.liubang.cc/posts/storage/2021-01-12-leveldb%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E4%B9%8Bcompaction/</link><pubDate>Tue, 12 Jan 2021 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/storage/2021-01-12-leveldb%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E4%B9%8Bcompaction/</guid><description>结合源码梳理 LevelDB Compaction 的触发条件、执行流程，以及它在 LSM 结构中的作用。</description></item><item><title>分布式协议</title><link>https://blog.liubang.cc/posts/inf/2020-05-25-%E5%88%86%E5%B8%83%E5%BC%8F%E5%8D%8F%E8%AE%AE/</link><pubDate>Mon, 25 May 2020 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/inf/2020-05-25-%E5%88%86%E5%B8%83%E5%BC%8F%E5%8D%8F%E8%AE%AE/</guid><description>从拜占庭将军问题讲起，梳理分布式系统中的共识模型，以及 Paxos 和 Raft 的基本思想。</description></item><item><title>基于公司私有gitlab的go module实践</title><link>https://blog.liubang.cc/posts/go/2019-10-17-%E5%9F%BA%E4%BA%8E%E5%85%AC%E5%8F%B8%E7%A7%81%E6%9C%89gitlab%E7%9A%84go-module%E5%AE%9E%E8%B7%B5/</link><pubDate>Thu, 17 Oct 2019 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/go/2019-10-17-%E5%9F%BA%E4%BA%8E%E5%85%AC%E5%8F%B8%E7%A7%81%E6%9C%89gitlab%E7%9A%84go-module%E5%AE%9E%E8%B7%B5/</guid><description>总结在私有 GitLab 环境中落地 Go module 时遇到的仓库、权限与版本管理问题及解决方案。</description></item><item><title>使用c语言模拟lisp语法</title><link>https://blog.liubang.cc/posts/sp/2019-08-18-c%E8%AF%AD%E8%A8%80%E6%A8%A1%E6%8B%9Flisp%E8%AF%AD%E6%B3%95/</link><pubDate>Sun, 18 Aug 2019 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/sp/2019-08-18-c%E8%AF%AD%E8%A8%80%E6%A8%A1%E6%8B%9Flisp%E8%AF%AD%E6%B3%95/</guid><description>使用 c 语言的 macro 操作，能够很简单的用 c 语言模拟 lisp 语法。</description></item><item><title>动态连接器技巧之使用LD_PRELOAD改变程序的行为</title><link>https://blog.liubang.cc/posts/sp/2019-07-18-%E5%8A%A8%E6%80%81%E8%BF%9E%E6%8E%A5%E5%99%A8%E6%8A%80%E5%B7%A7%E4%B9%8B%E4%BD%BF%E7%94%A8ld_preload%E6%94%B9%E5%8F%98%E7%A8%8B%E5%BA%8F%E7%9A%84%E8%A1%8C%E4%B8%BA/</link><pubDate>Thu, 18 Jul 2019 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/sp/2019-07-18-%E5%8A%A8%E6%80%81%E8%BF%9E%E6%8E%A5%E5%99%A8%E6%8A%80%E5%B7%A7%E4%B9%8B%E4%BD%BF%E7%94%A8ld_preload%E6%94%B9%E5%8F%98%E7%A8%8B%E5%BA%8F%E7%9A%84%E8%A1%8C%E4%B8%BA/</guid><description>我们有这样一段简单的代码，用来输出 10 个[0, 100)的随机数。</description></item><item><title>Spring Boot With BDD</title><link>https://blog.liubang.cc/posts/java/2019-03-15-spring_boot_with_bdd/</link><pubDate>Fri, 15 Mar 2019 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/java/2019-03-15-spring_boot_with_bdd/</guid><description>BDD(Behavior Driven Development)，行为驱动开发，是一种敏捷软件开发的技术，它鼓励软件项目中的开发者、QA 和非技术人员或商业参与者之间的协作。</description></item><item><title>多线程编程</title><link>https://blog.liubang.cc/posts/sp/2018-12-05-%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/</link><pubDate>Wed, 05 Dec 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/sp/2018-12-05-%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B/</guid><description>这篇文章主要是为了帮助大家熟悉 POSIX 线程库以及在实际开发中使用它的特性。我们会具体讲解如何利用这个线程库定义的不同工具。</description></item><item><title>使用正则表达式开发一个高性能路由</title><link>https://blog.liubang.cc/posts/php/2018-04-16-%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E9%AB%98%E6%80%A7%E8%83%BD%E8%B7%AF%E7%94%B1/</link><pubDate>Mon, 16 Apr 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2018-04-16-%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BC%80%E5%8F%91%E4%B8%80%E4%B8%AA%E9%AB%98%E6%80%A7%E8%83%BD%E8%B7%AF%E7%94%B1/</guid><description>介绍如何利用正则表达式构建高性能路由，并分析其背后的实现思路。</description></item><item><title>c++编程之标准库和STL</title><link>https://blog.liubang.cc/posts/cpp/2018-03-19-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%A0%87%E5%87%86%E5%BA%93%E5%92%8Cstl/</link><pubDate>Mon, 19 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-03-19-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%A0%87%E5%87%86%E5%BA%93%E5%92%8Cstl/</guid><description>梳理 C++ 标准库与 STL 的核心组成，并概览常见容器、算法与工具。</description></item><item><title>c++编程之字符和字符串</title><link>https://blog.liubang.cc/posts/cpp/2018-03-15-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E5%AD%97%E7%AC%A6%E5%92%8C%E5%AD%97%E7%AC%A6%E4%B8%B2/</link><pubDate>Thu, 15 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-03-15-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E5%AD%97%E7%AC%A6%E5%92%8C%E5%AD%97%E7%AC%A6%E4%B8%B2/</guid><description>梳理 C++ 中字符与字符串的常用处理方式，以及相关标准库能力。</description></item><item><title>c++编程之操作符重载</title><link>https://blog.liubang.cc/posts/cpp/2018-03-14-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%93%8D%E4%BD%9C%E7%AC%A6%E9%87%8D%E8%BD%BD/</link><pubDate>Wed, 14 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-03-14-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%93%8D%E4%BD%9C%E7%AC%A6%E9%87%8D%E8%BD%BD/</guid><description>介绍 C++ 操作符重载的基本规则、常见场景，以及运算符语义设计时需要注意的边界。</description></item><item><title>c++编程之模板和泛型编程</title><link>https://blog.liubang.cc/posts/cpp/2018-03-14-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%A8%A1%E6%9D%BF%E5%92%8C%E6%B3%9B%E5%9E%8B%E7%BC%96%E7%A8%8B/</link><pubDate>Wed, 14 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-03-14-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%A8%A1%E6%9D%BF%E5%92%8C%E6%B3%9B%E5%9E%8B%E7%BC%96%E7%A8%8B/</guid><description>介绍 C++ 模板与泛型编程的基本思想，并通过函数模板和类模板说明其使用方式。</description></item><item><title>c++编程之继承和多态</title><link>https://blog.liubang.cc/posts/cpp/2018-03-05-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BB%A7%E6%89%BF%E5%92%8C%E5%A4%9A%E6%80%81/</link><pubDate>Mon, 05 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-03-05-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BB%A7%E6%89%BF%E5%92%8C%E5%A4%9A%E6%80%81/</guid><description>超类（基类）和子类（派生类）：在面向对象程序设计中，我们通常使用继承来避免代码冗余。在 C++中，继承的语法规则如下。</description></item><item><title>c++编程之OOP示例</title><link>https://blog.liubang.cc/posts/cpp/2018-03-02-c++%E7%BC%96%E7%A8%8B%E4%B9%8Boop%E7%A4%BA%E4%BE%8B/</link><pubDate>Fri, 02 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-03-02-c++%E7%BC%96%E7%A8%8B%E4%B9%8Boop%E7%A4%BA%E4%BE%8B/</guid><description>通过一个 Time 类示例演示 C++ 面向对象设计、链式调用与接口演进。</description></item><item><title>c++编程之指针，引用和内存动态分配</title><link>https://blog.liubang.cc/posts/cpp/2018-02-23-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%8C%87%E9%92%88%E5%BC%95%E7%94%A8%E5%92%8C%E5%86%85%E5%AD%98%E5%8A%A8%E6%80%81%E5%88%86%E9%85%8D/</link><pubDate>Fri, 23 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-02-23-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%8C%87%E9%92%88%E5%BC%95%E7%94%A8%E5%92%8C%E5%86%85%E5%AD%98%E5%8A%A8%E6%80%81%E5%88%86%E9%85%8D/</guid><description>指针，引用和动态分配内存是 C/C++语言中最强大的特性，这些特性使得程序员能够直接操作计算机中非常珍贵的记忆体资源，进而对内存进行最大性能和高效的使用。</description></item><item><title>c++编程之面向对象</title><link>https://blog.liubang.cc/posts/cpp/2018-02-13-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/</link><pubDate>Tue, 13 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/cpp/2018-02-13-c++%E7%BC%96%E7%A8%8B%E4%B9%8B%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/</guid><description>假如你想组装一台电脑，你会去硬件商店购买主板、处理器、内存条、硬盘、机箱、电源，然后将它们组装在一起，然后打开电源，电脑就能运行。</description></item><item><title>PHP7虚拟机</title><link>https://blog.liubang.cc/posts/php/2017-11-29-php7%E8%99%9A%E6%8B%9F%E6%9C%BA/</link><pubDate>Wed, 29 Nov 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-11-29-php7%E8%99%9A%E6%8B%9F%E6%9C%BA/</guid><description>结合参考资料梳理 PHP 7 虚拟机的执行模型、核心结构与运行流程。</description></item><item><title>PHP和线程</title><link>https://blog.liubang.cc/posts/php/2017-10-12-php%E5%92%8C%E7%BA%BF%E7%A8%8B/</link><pubDate>Thu, 12 Oct 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-10-12-php%E5%92%8C%E7%BA%BF%E7%A8%8B/</guid><description>介绍 PHP 与线程模型之间的关系，并结合参考资料理解相关实现与限制。</description></item><item><title>理解c语言中的声明</title><link>https://blog.liubang.cc/posts/sp/2017-09-12-%E7%90%86%E8%A7%A3c%E8%AF%AD%E8%A8%80%E4%B8%AD%E7%9A%84%E5%A3%B0%E6%98%8E/</link><pubDate>Tue, 12 Sep 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/sp/2017-09-12-%E7%90%86%E8%A7%A3c%E8%AF%AD%E8%A8%80%E4%B8%AD%E7%9A%84%E5%A3%B0%E6%98%8E/</guid><description>梳理 C 语言中复杂声明的阅读方法，帮助理解指针、数组和函数声明的组合规则。</description></item><item><title>PHP扩展开发之迭代器</title><link>https://blog.liubang.cc/posts/php/2017-08-28-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E8%BF%AD%E4%BB%A3%E5%99%A8/</link><pubDate>Mon, 28 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-08-28-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E8%BF%AD%E4%BB%A3%E5%99%A8/</guid><description>介绍如何在 PHP 扩展中为自定义对象实现迭代器接口，提升可用性与语言集成度。</description></item><item><title>PHP扩展开发之对象处理器(Object Handlers)</title><link>https://blog.liubang.cc/posts/php/2017-08-27-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E5%AF%B9%E8%B1%A1%E5%A4%84%E7%90%86%E5%99%A8/</link><pubDate>Sun, 27 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-08-27-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E5%AF%B9%E8%B1%A1%E5%A4%84%E7%90%86%E5%99%A8/</guid><description>介绍 PHP 扩展中的 object handlers 机制，以及如何通过它定制对象行为。</description></item><item><title>PHP扩展开发之打造一个简易的ArrayBuffer</title><link>https://blog.liubang.cc/posts/php/2017-08-25-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E6%89%93%E9%80%A0%E4%B8%80%E4%B8%AA%E7%AE%80%E6%98%93%E7%9A%84arraybuffer/</link><pubDate>Fri, 25 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-08-25-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E6%89%93%E9%80%A0%E4%B8%80%E4%B8%AA%E7%AE%80%E6%98%93%E7%9A%84arraybuffer/</guid><description>ArrayBuffer 又叫二进制数组，是一个用来表示通用的，固定长度的二进制数据缓冲区。你不能直接操纵 ArrayBuffer 的内容。</description></item><item><title>PHP扩展开发之自定义对象的存储</title><link>https://blog.liubang.cc/posts/php/2017-08-24-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%AD%98%E5%82%A8/</link><pubDate>Thu, 24 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-08-24-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8B%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%AD%98%E5%82%A8/</guid><description>介绍在 PHP 扩展开发中如何设计和管理自定义对象的底层存储结构。</description></item><item><title>数据结构之hashtable</title><link>https://blog.liubang.cc/posts/ds/2017-08-22-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8Bhashtable/</link><pubDate>Tue, 22 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/ds/2017-08-22-%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B9%8Bhashtable/</guid><description>哈希表又叫散列表，是实现字典操作的中有效数据结构。通常来说，一个 hash table 包含了一个数据，其中的数据通过 index 来访问。</description></item><item><title>c语言之struct</title><link>https://blog.liubang.cc/posts/sp/2017-08-21-c%E8%AF%AD%E8%A8%80%E4%B9%8Bstruct/</link><pubDate>Mon, 21 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/sp/2017-08-21-c%E8%AF%AD%E8%A8%80%E4%B9%8Bstruct/</guid><description>系统介绍 C 语言 struct 的定义方式、内存布局与典型使用场景。</description></item><item><title>Java Native Interface（三）</title><link>https://blog.liubang.cc/posts/java/2017-03-20-java_native_interface%E4%B8%89/</link><pubDate>Mon, 20 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/java/2017-03-20-java_native_interface%E4%B8%89/</guid><description>前面系统研究了 JNI 的相关操作，下面就来小试牛刀，做一个实际的练习。</description></item><item><title>Java Native Interface（二）</title><link>https://blog.liubang.cc/posts/java/2017-03-20-java_native_interface%E4%BA%8C/</link><pubDate>Mon, 20 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/java/2017-03-20-java_native_interface%E4%BA%8C/</guid><description>JNI 中定义了一下类型来对应到相应的 Java 的数据类型。</description></item><item><title>Java Native Interface（一）</title><link>https://blog.liubang.cc/posts/java/2017-03-17-java_native_interface%E4%B8%80/</link><pubDate>Fri, 17 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/java/2017-03-17-java_native_interface%E4%B8%80/</guid><description>作为 JNI 系列第一篇，介绍 Java Native Interface 的基本概念、作用以及入门示例。</description></item><item><title>彻底掌握malloc</title><link>https://blog.liubang.cc/posts/sp/2017-03-17-%E5%BD%BB%E5%BA%95%E6%8E%8C%E6%8F%A1malloc/</link><pubDate>Fri, 17 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/sp/2017-03-17-%E5%BD%BB%E5%BA%95%E6%8E%8C%E6%8F%A1malloc/</guid><description>系统梳理 malloc 的工作机制、堆内存布局，以及常见分配策略与实现细节。</description></item><item><title>基于c语言的编程语言开发</title><link>https://blog.liubang.cc/posts/compiler/2017-03-15-%E5%9F%BA%E4%BA%8Ec%E8%AF%AD%E8%A8%80%E7%9A%84%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91/</link><pubDate>Wed, 15 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/compiler/2017-03-15-%E5%9F%BA%E4%BA%8Ec%E8%AF%AD%E8%A8%80%E7%9A%84%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91/</guid><description>从词法分析、语法分析到 AST 构建，介绍如何基于 C 语言一步步实现一个简单编程语言。</description></item><item><title>PHP扩展开发之call_user_func原理和回调函数的实现</title><link>https://blog.liubang.cc/posts/php/2017-03-09-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8Bcall-user-func%E5%8E%9F%E7%90%86%E5%92%8C%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9E%E7%8E%B0/</link><pubDate>Thu, 09 Mar 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/posts/php/2017-03-09-php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E4%B9%8Bcall-user-func%E5%8E%9F%E7%90%86%E5%92%8C%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E7%9A%84%E5%AE%9E%E7%8E%B0/</guid><description>从底层实现角度分析 PHP 中 call_user_func 与回调函数机制的工作原理。</description></item><item><title>关于</title><link>https://blog.liubang.cc/about/</link><pubDate>Sun, 01 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/about/</guid><description/></item><item><title>Offline</title><link>https://blog.liubang.cc/offline/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://blog.liubang.cc/offline/</guid><description/></item></channel></rss>