<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>sheep44044的小站</title><description>博客</description><link>https://sheep44044.github.io/</link><language>zh_CN</language><item><title>LeetCode-416. 分割等和子集</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-416-%E5%88%86%E5%89%B2%E7%AD%89%E5%92%8C%E5%AD%90%E9%9B%86/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-416-%E5%88%86%E5%89%B2%E7%AD%89%E5%92%8C%E5%AD%90%E9%9B%86/</guid><pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/partition-equal-subset-sum/&quot;&gt;&lt;strong&gt;416. 分割等和子集&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个 &lt;strong&gt;只包含正整数&lt;/strong&gt; 的 &lt;strong&gt;非空&lt;/strong&gt; 数组 &lt;code&gt;nums&lt;/code&gt; 。请你判断是否可以将这个数组分割成两个子集，使得两个子集的元素和相等。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,5,11,5]
输出：true
解释：数组可以分割成 [1, 5, 5] 和 [11] 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,3,5]
输出：false
解释：数组不能分割成两个元素和相等的子集。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题思路就是01背包。 第i个物品的容量和价值都是nums[i]，而背包总容量是sum/2（前面先判断sum是奇数还是偶数，奇数直接返回false了），因为容量和价值是相等的，所以动规后背包装下的最大价值如果恰是sum/2，就说明背包必须恰好装满了，此时就说明数组可以被分为两个相等子集。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func canPartition(nums []int) bool {
    sum := 0
    for _, num := range nums {
        sum += num
    }

    if sum % 2 != 0 {
        return false
    }

    target := sum / 2

    dp := make([]int, target+1)

    for i := 0; i &amp;lt; len(nums); i++ {
        for j := target; j &amp;gt;= nums[i]; j-- {
            dp[j] = max(dp[j], dp[j-nums[i]]+nums[i])
            
            if dp[target] == target {
                return true
            }
        }
    }

    return dp[target] == target
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-136. 只出现一次的数字</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-136-%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E6%95%B0%E5%AD%97/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-136-%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E6%95%B0%E5%AD%97/</guid><pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;技巧&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/single-number/&quot;&gt;&lt;strong&gt;136. 只出现一次的数字&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个 &lt;strong&gt;非空&lt;/strong&gt; 整数数组 &lt;code&gt;nums&lt;/code&gt; ，除了某个元素只出现一次以外，其余每个元素均出现两次。找出那个只出现了一次的元素。&lt;/p&gt;
&lt;p&gt;你必须设计并实现线性时间复杂度的算法来解决此问题，且该算法只使用常量额外空间。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1 ：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**nums = [2,2,1]&lt;/p&gt;
&lt;p&gt;**输出：**1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 2 ：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**nums = [4,1,2,1,2]&lt;/p&gt;
&lt;p&gt;**输出：**4&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 3 ：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**nums = [1]&lt;/p&gt;
&lt;p&gt;**输出：**1&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这就是技巧题吗，我去&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;异或运算性质&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;相同的数异或为0&lt;/li&gt;
&lt;li&gt;任何数和0异或，结果还是他自己&lt;/li&gt;
&lt;li&gt;异或运算满足交换律&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func singleNumber(nums []int) int {
    res := 0
    for _, num := range nums {
        res ^= num
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-169. 多数元素</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-169-%E5%A4%9A%E6%95%B0%E5%85%83%E7%B4%A0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-169-%E5%A4%9A%E6%95%B0%E5%85%83%E7%B4%A0/</guid><pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;技巧&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/majority-element/&quot;&gt;&lt;strong&gt;169. 多数元素&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个大小为 &lt;code&gt;n&lt;/code&gt; 的数组 &lt;code&gt;nums&lt;/code&gt; ，返回其中的多数元素。多数元素是指在数组中出现次数 &lt;strong&gt;大于&lt;/strong&gt; &lt;code&gt;⌊ n/2 ⌋&lt;/code&gt; 的元素。&lt;/p&gt;
&lt;p&gt;你可以假设数组是非空的，并且给定的数组总是存在多数元素。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [3,2,3]
输出：3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [2,2,1,1,1,2,2]
输出：2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;无需多言&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func majorityElement(nums []int) int {
    sort.Ints(nums)
    return nums[len(nums)/2]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;wow，interesting&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是我目前看到的最直观形象的解法，时间复杂度O(n)，空间复杂度O(1)。&lt;/p&gt;
&lt;p&gt;“同归于尽消杀法” ：&lt;/p&gt;
&lt;p&gt;由于多数超过50%, 比如100个数，那么多数至少51个，剩下少数是49个。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一个到来的士兵，直接插上自己阵营的旗帜占领这块高地，此时领主 winner 就是这个阵营的人，现存兵力 count = 1。&lt;/li&gt;
&lt;li&gt;如果新来的士兵和前一个士兵是同一阵营，则集合起来占领高地，领主不变，winner 依然是当前这个士兵所属阵营，现存兵力 count++；&lt;/li&gt;
&lt;li&gt;如果新来到的士兵不是同一阵营，则前方阵营派一个士兵和它同归于尽。 此时前方阵营兵力count --。（即使双方都死光，这块高地的旗帜 winner 依然不变，因为已经没有活着的士兵可以去换上自己的新旗帜）&lt;/li&gt;
&lt;li&gt;当下一个士兵到来，发现前方阵营已经没有兵力，新士兵就成了领主，winner 变成这个士兵所属阵营的旗帜，现存兵力 count ++。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;就这样各路军阀一直以这种以一敌一同归于尽的方式厮杀下去，直到少数阵营都死光，那么最后剩下的几个必然属于多数阵营，winner 就是多数阵营。（多数阵营 51个，少数阵营只有49个，死剩下的2个就是多数阵营的人）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func majorityElement(nums []int) int {
    winner := nums[0]
    count := 1

    for i := 1; i &amp;lt; len(nums); i++ {
        if nums[i] == winner {
            count++
        }else {
            count--
            if count == 0 {
                winner = nums[i]
                count = 1
            }
        }
    }

    return winner
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-31. 下一个排列</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-31-%E4%B8%8B%E4%B8%80%E4%B8%AA%E6%8E%92%E5%88%97/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-31-%E4%B8%8B%E4%B8%80%E4%B8%AA%E6%8E%92%E5%88%97/</guid><pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;技巧&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/next-permutation/&quot;&gt;&lt;strong&gt;31. 下一个排列&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;整数数组的一个 &lt;strong&gt;排列&lt;/strong&gt; 就是将其所有成员以序列或线性顺序排列。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;例如，&lt;code&gt;arr = [1,2,3]&lt;/code&gt; ，以下这些都可以视作 &lt;code&gt;arr&lt;/code&gt; 的排列：&lt;code&gt;[1,2,3]&lt;/code&gt;、&lt;code&gt;[1,3,2]&lt;/code&gt;、&lt;code&gt;[3,1,2]&lt;/code&gt;、&lt;code&gt;[2,3,1]&lt;/code&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;整数数组的 &lt;strong&gt;下一个排列&lt;/strong&gt; 是指其整数的下一个字典序更大的排列。更正式地，如果数组的所有排列根据其字典顺序从小到大排列在一个容器中，那么数组的 &lt;strong&gt;下一个排列&lt;/strong&gt; 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列，那么这个数组必须重排为字典序最小的排列（即，其元素按升序排列）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;例如，&lt;code&gt;arr = [1,2,3]&lt;/code&gt; 的下一个排列是 &lt;code&gt;[1,3,2]&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;类似地，&lt;code&gt;arr = [2,3,1]&lt;/code&gt; 的下一个排列是 &lt;code&gt;[3,1,2]&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;而 &lt;code&gt;arr = [3,2,1]&lt;/code&gt; 的下一个排列是 &lt;code&gt;[1,2,3]&lt;/code&gt; ，因为 &lt;code&gt;[3,2,1]&lt;/code&gt; 不存在一个字典序更大的排列。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，找出 &lt;code&gt;nums&lt;/code&gt; 的下一个排列。&lt;/p&gt;
&lt;p&gt;必须**&lt;a href=&quot;https://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95&quot;&gt; 原地 &lt;/a&gt;**修改，只允许使用额外常数空间。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,3]
输出：[1,3,2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [3,2,1]
输出：[1,2,3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,1,5]
输出：[1,5,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从后向前 查找第一个 相邻升序 的元素对 (i,j)，满足 A[i] &amp;lt; A[j]。此时 [j,end) 必然是降序&lt;/li&gt;
&lt;li&gt;在 [j,end) 从后向前 查找第一个满足 A[i] &amp;lt; A[k] 的 k。A[i]、A[k] 分别就是上文所说的「小数」、「大数」&lt;/li&gt;
&lt;li&gt;将 A[i] 与 A[k] 交换&lt;/li&gt;
&lt;li&gt;可以断定这时 [j,end) 必然是降序，逆置 [j,end)，使其升序&lt;/li&gt;
&lt;li&gt;如果在步骤 1 找不到符合的相邻元素对，说明当前 [begin,end) 为一个降序顺序，则直接跳到步骤 4&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func nextPermutation(nums []int)  {
    n := len(nums)
    if n &amp;lt;= 1 {
        return
    }

    i := n - 2
    for i &amp;gt;= 0 &amp;amp;&amp;amp; nums[i] &amp;gt;= nums[i+1] {
        i--
    }

    if i &amp;gt;= 0 {
        j := n - 1
        for nums[i] &amp;gt;= nums[j] {
            j--
        }

        nums[i], nums[j] = nums[j], nums[i]
    }

    reverse(nums, i+1, n-1)
}

func reverse (nums []int, left, right int) {
    for left &amp;lt;= right {
        nums[left] ,nums[right] = nums[right], nums[left]
        left++
        right--
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-75. 颜色分类</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-75-%E9%A2%9C%E8%89%B2%E5%88%86%E7%B1%BB/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%8A%80%E5%B7%A7/leetcode-75-%E9%A2%9C%E8%89%B2%E5%88%86%E7%B1%BB/</guid><pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;技巧&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/sort-colors/&quot;&gt;&lt;strong&gt;75. 颜色分类&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个包含红色、白色和蓝色、共 &lt;code&gt;n&lt;/code&gt; 个元素的数组 &lt;code&gt;nums&lt;/code&gt; ，&lt;strong&gt;&lt;a href=&quot;https://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95&quot;&gt;原地&lt;/a&gt;&lt;/strong&gt; 对它们进行排序，使得相同颜色的元素相邻，并按照红色、白色、蓝色顺序排列。&lt;/p&gt;
&lt;p&gt;我们使用整数 &lt;code&gt;0&lt;/code&gt;、 &lt;code&gt;1&lt;/code&gt; 和 &lt;code&gt;2&lt;/code&gt; 分别表示红色、白色和蓝色。&lt;/p&gt;
&lt;p&gt;必须在不使用库内置的 sort 函数的情况下解决这个问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [2,0,2,1,1,0]
输出：[0,0,1,1,2,2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [2,0,1]
输出：[0,1,2]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们可以把数组划分为三个区域：0 的区域在最左边，2 的区域在最右边，1 的区域在中间。 我们维护三个指针：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;p0&lt;/code&gt;：指向当前 0 应该存放的位置（初始为 0）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;p2&lt;/code&gt;：指向当前 2 应该存放的位置（初始为数组末尾）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curr&lt;/code&gt;：用于遍历数组的当前指针（初始为 0）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中为什么&lt;code&gt;p0&lt;/code&gt;可以变动&lt;code&gt;cur&lt;/code&gt;，&lt;code&gt;p2&lt;/code&gt;不行，因为原来 &lt;code&gt;p0&lt;/code&gt; 位置的那个 &lt;code&gt;1&lt;/code&gt;，被换到了 &lt;code&gt;curr&lt;/code&gt; 现在的位置。因为我们百分之百确信换过来的是 &lt;code&gt;1&lt;/code&gt;，所以 &lt;code&gt;curr&lt;/code&gt; 没必要再检查它一次，直接 &lt;code&gt;curr++&lt;/code&gt; 走向下一个目标即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func sortColors(nums []int)  {
    p0 := 0
    cur := 0
    p2 := len(nums) - 1

    for cur &amp;lt;= p2 {
        if nums[cur] == 0 {
            nums[p0], nums[cur] = nums[cur], nums[p0]
            p0++
            cur++
        }else if nums[cur] == 2 {
            nums[p2], nums[cur] = nums[cur], nums[p2]
            p2--
        }else {
            cur++
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-152. 乘积最大子数组</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-152-%E4%B9%98%E7%A7%AF%E6%9C%80%E5%A4%A7%E5%AD%90%E6%95%B0%E7%BB%84/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-152-%E4%B9%98%E7%A7%AF%E6%9C%80%E5%A4%A7%E5%AD%90%E6%95%B0%E7%BB%84/</guid><pubDate>Sat, 25 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/maximum-product-subarray/&quot;&gt;&lt;strong&gt;152. 乘积最大子数组&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，请你找出数组中乘积最大的非空连续 子数组（该子数组中至少包含一个数字），并返回该子数组所对应的乘积。&lt;/p&gt;
&lt;p&gt;测试用例的答案是一个 &lt;strong&gt;32-位&lt;/strong&gt; 整数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;请注意&lt;/strong&gt;，一个只包含一个元素的数组的乘积是这个元素的值。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题其实只需要解决掉负数这个问题即可。&lt;/p&gt;
&lt;p&gt;如果同时处理&lt;code&gt;curMax&lt;/code&gt;和&lt;code&gt;curMin&lt;/code&gt;和&lt;code&gt;nums[i]&lt;/code&gt;的正负性比较复杂，我们只需要利用&lt;code&gt;max&lt;/code&gt;和&lt;code&gt;min&lt;/code&gt;比较即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxProduct(nums []int) int {
    if len(nums) == 0 {
        return 0
    }

    curMax := nums[0]
    curMin := nums[0]
    res := nums[0]

    for i := 1; i &amp;lt; len(nums); i++ {
        tmpMax, tmpMin := curMax, curMin

        curMax = max(nums[i], max(tmpMax*nums[i], tmpMin*nums[i]))
        curMin = min(nums[i], min(tmpMax*nums[i], tmpMin*nums[i]))
        
        res = max(res, curMax)
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-300. 最长递增子序列</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-300-%E6%9C%80%E9%95%BF%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-300-%E6%9C%80%E9%95%BF%E9%80%92%E5%A2%9E%E5%AD%90%E5%BA%8F%E5%88%97/</guid><pubDate>Sat, 25 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/longest-increasing-subsequence/&quot;&gt;&lt;strong&gt;300. 最长递增子序列&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，找到其中最长严格递增子序列的长度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;子序列&lt;/strong&gt; 是由数组派生而来的序列，删除（或不删除）数组中的元素而不改变其余元素的顺序。例如，&lt;code&gt;[3,6,2,7]&lt;/code&gt; 是数组 &lt;code&gt;[0,3,1,6,2,2,7]&lt;/code&gt; 的子序列。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [10,9,2,5,3,7,101,18]
输出：4
解释：最长递增子序列是 [2,3,7,101]，因此长度为 4 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0,1,0,3,2,3]
输出：4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [7,7,7,7,7,7,7]
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;作为新手面对这种问题，如果我们把 &lt;code&gt;dp[i]&lt;/code&gt;定义为“前 i 个数中最长的递增子序列长度”，会发现状态转移方程写不出来，我们无法判断 i 是否能够添加上去。&lt;/p&gt;
&lt;p&gt;所以，判断为把 &lt;code&gt;dp[i]&lt;/code&gt;定义为“以&lt;code&gt;nums[i]&lt;/code&gt;结尾的前 i 个数中最长的递增子序列长度，这样就可以直观比较了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func lengthOfLIS(nums []int) int {
    n := len(nums)
    if n == 0 {
        return 0
    }
    
    dp := make([]int, n)
    for i := 0; i &amp;lt; n; i++ {
        dp[i] = 1
    }

    res := 1
    for i := 1; i &amp;lt; n; i++ {
        for j := 0; j &amp;lt; i; j++ {
            if nums[i] &amp;gt; nums[j] {
                dp[i] = max(dp[i], dp[j]+1)
            }
            res = max(res, dp[i])
        } 
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>2026-4-21-weekly7</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-4-21-weekly7/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-4-21-weekly7/</guid><pubDate>Tue, 21 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h4&gt;本周摘要&lt;/h4&gt;
&lt;p&gt;竟然都第七周了，时间过的好快。上周由于运动会放假，休息了几天，这周只做了十几道题。不过也累计刷到了八十多题，争取近两周内把hot100解决掉。把hot100解决掉后，可以开始准备分布式的项目了，加油。&lt;/p&gt;
&lt;h4&gt;一、具体完成事项&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;刷力扣&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完成贪心算法的hot100题目&lt;/li&gt;
&lt;li&gt;完成动态规划的一些hot100题目&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;二、复盘与反思&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;总感觉动态规划的背包问题不得其解，想不懂，需要多沉淀一下&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​&lt;/p&gt;
&lt;h4&gt;三、下周计划&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;继续力扣hot100，争取把动态规划部分解决掉&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>LeetCode-139. 单词拆分</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-139-%E5%8D%95%E8%AF%8D%E6%8B%86%E5%88%86/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-139-%E5%8D%95%E8%AF%8D%E6%8B%86%E5%88%86/</guid><pubDate>Sat, 18 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/word-break/&quot;&gt;&lt;strong&gt;139. 单词拆分&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个字符串 &lt;code&gt;s&lt;/code&gt; 和一个字符串列表 &lt;code&gt;wordDict&lt;/code&gt; 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 &lt;code&gt;s&lt;/code&gt; 则返回 &lt;code&gt;true&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;**注意：**不要求字典中出现的单词全部都使用，并且字典中的单词可以重复使用。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;leetcode&quot;, wordDict = [&quot;leet&quot;, &quot;code&quot;]
输出: true
解释: 返回 true 因为 &quot;leetcode&quot; 可以由 &quot;leet&quot; 和 &quot;code&quot; 拼接成。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;applepenapple&quot;, wordDict = [&quot;apple&quot;, &quot;pen&quot;]
输出: true
解释: 返回 true 因为 &quot;applepenapple&quot; 可以由 &quot;apple&quot; &quot;pen&quot; &quot;apple&quot; 拼接成。
     注意，你可以重复使用字典中的单词。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;catsandog&quot;, wordDict = [&quot;cats&quot;, &quot;dog&quot;, &quot;sand&quot;, &quot;and&quot;, &quot;cat&quot;]
输出: false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题也是完全背包问题，物品的重量就是他的长度，只关心是否能否恰好装满背包，不关心其价值。&lt;/p&gt;
&lt;p&gt;相较于 &lt;a href=&quot;https://leetcode.cn/problems/perfect-squares/&quot;&gt;&lt;strong&gt;279. 完全平方数&lt;/strong&gt;&lt;/a&gt;，这里只是多了一层字符串内容匹配的逻辑&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func wordBreak(s string, wordDict []string) bool {
    wordMap := make(map[string]bool)
    for _, word := range wordDict {
        wordMap[word] = true
    }

    dp := make([]bool, len(s)+1)
    dp[0] = true 

    for i := 1; i &amp;lt;= len(s); i++ {
        for j := 0; j &amp;lt; i; j++ {
            if dp[j] &amp;amp;&amp;amp; wordMap[s[j:i]] {
                dp[i] = true
                break 
            }
        }
    }

    return dp[len(s)]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-279. 完全平方数</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-279-%E5%AE%8C%E5%85%A8%E5%B9%B3%E6%96%B9%E6%95%B0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-279-%E5%AE%8C%E5%85%A8%E5%B9%B3%E6%96%B9%E6%95%B0/</guid><pubDate>Sat, 18 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/perfect-squares/&quot;&gt;&lt;strong&gt;279. 完全平方数&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数 &lt;code&gt;n&lt;/code&gt; ，返回 &lt;em&gt;和为 &lt;code&gt;n&lt;/code&gt; 的完全平方数的最少数量&lt;/em&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;完全平方数&lt;/strong&gt; 是一个整数，其值等于另一个整数的平方；换句话说，其值等于一个整数自乘的积。例如，&lt;code&gt;1&lt;/code&gt;、&lt;code&gt;4&lt;/code&gt;、&lt;code&gt;9&lt;/code&gt; 和 &lt;code&gt;16&lt;/code&gt; 都是完全平方数，而 &lt;code&gt;3&lt;/code&gt; 和 &lt;code&gt;11&lt;/code&gt; 不是。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 12
输出：3 
解释：12 = 4 + 4 + 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 13
输出：2
解释：13 = 4 + 9
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;初识背包问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是一个完全背包问题，每个数字的重量为1，价值也为1。&lt;/p&gt;
&lt;p&gt;这题的逻辑就是：&lt;code&gt;dp[i]&lt;/code&gt;储存每个数字的最小合成次数，对于&lt;code&gt;dp[9]&lt;/code&gt;来说，有 &lt;code&gt;dp[9] = dp[8] + 1&lt;/code&gt;和 &lt;code&gt;dp[9] = dp[8] + 4&lt;/code&gt;和其他可能。这样通过循环可以得到&lt;code&gt;dp[9]&lt;/code&gt;的最小值，而 &lt;code&gt;dp[0]&lt;/code&gt;、&lt;code&gt;dp[1]&lt;/code&gt; ......这样可以一直实现&lt;code&gt;dp[9]&lt;/code&gt;，从而完成本题。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func numSquares(n int) int {
    dp := make([]int, n+1)

    dp[0] = 0
    for i := 1; i &amp;lt;= n; i++ {
        dp[i] = math.MaxInt32
    }

    for i := 0; i &amp;lt;= n; i++ {
        for j := 0; j*j &amp;lt;= i; j++ {
            dp[i] = min(dp[i], dp[i-j*j]+1)
        }
    }

    return dp[n]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-322. 零钱兑换</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-322-%E9%9B%B6%E9%92%B1%E5%85%91%E6%8D%A2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-322-%E9%9B%B6%E9%92%B1%E5%85%91%E6%8D%A2/</guid><pubDate>Sat, 18 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/perfect-squares/&quot;&gt;&lt;strong&gt;279. 完全平方数&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;coins&lt;/code&gt; ，表示不同面额的硬币；以及一个整数 &lt;code&gt;amount&lt;/code&gt; ，表示总金额。&lt;/p&gt;
&lt;p&gt;计算并返回可以凑成总金额所需的 &lt;strong&gt;最少的硬币个数&lt;/strong&gt; 。如果没有任何一种硬币组合能组成总金额，返回 &lt;code&gt;-1&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;你可以认为每种硬币的数量是无限的。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：coins = [1, 2, 5], amount = 11
输出：3 
解释：11 = 5 + 5 + 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：coins = [2], amount = 3
输出：-1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：coins = [1], amount = 0
输出：0
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;相较于上题 &lt;a href=&quot;https://leetcode.cn/problems/perfect-squares/&quot;&gt;&lt;strong&gt;279. 完全平方数&lt;/strong&gt;&lt;/a&gt; ，这题对物品的选取作了限制，以及可能无法返回-1的要求。&lt;/p&gt;
&lt;p&gt;我们只需要最后&lt;code&gt;dp[amount] == math.MaxInt32&lt;/code&gt;进行校验即可，因为&lt;code&gt;dp[i]&lt;/code&gt;如果没有正常值，会因为&lt;code&gt;math.MaxInt32 &amp;lt; math.MaxInt32+1&lt;/code&gt;保持这个值。&lt;/p&gt;
&lt;p&gt;其他逻辑一样&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func coinChange(coins []int, amount int) int {
    dp := make([]int, amount+1)

    dp[0] = 0
    for i := 1; i &amp;lt;= amount; i++ {
        dp[i] = math.MaxInt32
    }

    for i := 0; i &amp;lt;= amount; i++ {
        for j := 0; j &amp;lt; len(coins); j++ {
            if coins[j] &amp;lt;= i {
                dp[i] = min(dp[i], dp[i-coins[j]]+1)
            } 
        }
    }

    if dp[amount] == math.MaxInt32 {
        return -1
    }
    return dp[amount]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;令一种写法先物品，后容量&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func coinChange(coins []int, amount int) int {
    // 1. 定义并初始化 dp 数组
    dp := make([]int, amount+1)
    dp[0] = 0
    for i := 1; i &amp;lt;= amount; i++ {
        dp[i] = math.MaxInt32
    }

    // 2. 完全背包标准遍历：外层遍历物品(硬币)，内层正序遍历背包(金额)
    for i := 0; i &amp;lt; len(coins); i++ {
        for j := coins[i]; j &amp;lt;= amount; j++ {
            // 3. 拦截溢出：只有当去掉了当前硬币的剩余金额是“可达的”，才进行计算
            if dp[j-coins[i]] != math.MaxInt32 {
                // 4. 状态转移
                dp[j] = min(dp[j], dp[j-coins[i]]+1)
            }
        }
    }

    // 5. 循环结束后，统一结算：如果最终目标金额还是极大值，说明彻底凑不出，返回 -1
    if dp[amount] == math.MaxInt32 {
        return -1
    }
    
    return dp[amount]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-118. 杨辉三角</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-118-%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-118-%E6%9D%A8%E8%BE%89%E4%B8%89%E8%A7%92/</guid><pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/pascals-triangle/&quot;&gt;&lt;strong&gt;118. 杨辉三角&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个非负整数 *&lt;code&gt;numRows&lt;/code&gt;，*生成「杨辉三角」的前 &lt;em&gt;&lt;code&gt;numRows&lt;/code&gt;&lt;/em&gt; 行。&lt;/p&gt;
&lt;p&gt;在**「杨辉三角」**中，每个数是它左上方和右上方的数的和。&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://pic.leetcode.cn/1626927345-DZmfxB-PascalTriangleAnimated2.gif&quot; alt=&quot;img&quot; style=&quot;zoom: 67%;&quot; /&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: numRows = 1
输出: [[1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路(手撕)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;与 &lt;a href=&quot;https://leetcode.cn/problems/climbing-stairs/&quot;&gt;&lt;strong&gt;70. 爬楼梯&lt;/strong&gt;&lt;/a&gt; 类似&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func generate(numRows int) [][]int {
    if numRows == 1 {
        return [][]int{{1}}
    }

    if numRows == 2 {
        return [][]int{{1},{1, 1}}
    }

    res := [][]int{{1}, {1, 1}}
    for i := 2; i &amp;lt; numRows; i++ {
        path := make([]int, i+1)
        path[0], path[len(path)-1] = 1, 1
        for j := 1; j &amp;lt; i; j++ {
            path[j] = res[i-1][j-1] + res[i-1][j]
        }
        res = append(res, path)
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-198. 打家劫舍</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-198-%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-198-%E6%89%93%E5%AE%B6%E5%8A%AB%E8%88%8D/</guid><pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/house-robber/&quot;&gt;&lt;strong&gt;198. 打家劫舍&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你是一个专业的小偷，计划偷窃沿街的房屋。每间房内都藏有一定的现金，影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统，&lt;strong&gt;如果两间相邻的房屋在同一晚上被小偷闯入，系统会自动报警&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;给定一个代表每个房屋存放金额的非负整数数组，计算你 &lt;strong&gt;不触动警报装置的情况下&lt;/strong&gt; ，一夜之内能够偷窃到的最高金额。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：[1,2,3,1]
输出：4
解释：偷窃 1 号房屋 (金额 = 1) ，然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：[2,7,9,3,1]
输出：12
解释：偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9)，接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;站在第 &lt;code&gt;i&lt;/code&gt; 个房间门前，只有两种选择：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;偷&lt;/strong&gt;：如果偷第 &lt;code&gt;i&lt;/code&gt; 个房间，那么根据报警规则，不能偷第 &lt;code&gt;i-1&lt;/code&gt; 个房间。你手里的钱就是“第 &lt;code&gt;i-2&lt;/code&gt; 个房间的最大收益”加上“当前房间里的钱”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不偷&lt;/strong&gt;：如果不偷第 &lt;code&gt;i&lt;/code&gt; 个房间，那么手里的钱，就等于“到第 &lt;code&gt;i-1&lt;/code&gt; 个房间为止的最大收益”。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func rob(nums []int) int {
    n := len(nums)
    dp := make([]int, n+1)

    dp[0] = nums[0]
    if n == 1 {
        return dp[0]
    }

    dp[1] = max(nums[0], nums[1])
    if n == 2 {
        return dp[1]
    }

    for i := 2; i &amp;lt; n; i++ {
        dp[i] = max(dp[i-2]+nums[i], dp[i-1])
    }

    return dp[n-1]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-70. 爬楼梯</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-70-%E7%88%AC%E6%A5%BC%E6%A2%AF/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/leetcode-70-%E7%88%AC%E6%A5%BC%E6%A2%AF/</guid><pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;动态规划&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/climbing-stairs/&quot;&gt;&lt;strong&gt;70. 爬楼梯&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;假设你正在爬楼梯。需要 &lt;code&gt;n&lt;/code&gt; 阶你才能到达楼顶。&lt;/p&gt;
&lt;p&gt;每次你可以爬 &lt;code&gt;1&lt;/code&gt; 或 &lt;code&gt;2&lt;/code&gt; 个台阶。你有多少种不同的方法可以爬到楼顶呢？&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 2
输出：2
解释：有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 3
输出：3
解释：有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;初识dp&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;爬到第 n 阶的方法总数，等于爬到第 n-1阶的方法数，加上爬到第 n-2 阶的方法数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func climbStairs(n int) int {
    if n &amp;lt;= 2 {
        return n
    }

    dp := make([]int, n+1)
    dp[1] = 1
    dp[2] = 2

    for i := 3; i &amp;lt;= n; i++ {
        dp[i] = dp[i-1] + dp[i-2]
    }

    return dp[n]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-435. 无重叠区间</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-435-%E6%97%A0%E9%87%8D%E5%8F%A0%E5%8C%BA%E9%97%B4/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-435-%E6%97%A0%E9%87%8D%E5%8F%A0%E5%8C%BA%E9%97%B4/</guid><pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/non-overlapping-intervals/&quot;&gt;&lt;strong&gt;435. 无重叠区间&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个区间的集合 &lt;code&gt;intervals&lt;/code&gt; ，其中 &lt;code&gt;intervals[i] = [starti, endi]&lt;/code&gt; 。返回 &lt;em&gt;需要移除区间的最小数量，使剩余区间互不重叠&lt;/em&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt; 只在一点上接触的区间是 &lt;strong&gt;不重叠的&lt;/strong&gt;。例如 &lt;code&gt;[1, 2]&lt;/code&gt; 和 &lt;code&gt;[2, 3]&lt;/code&gt; 是不重叠的。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后，剩下的区间没有重叠。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间，因为它们已经是无重叠的了。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路(自己完成)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本题要 求除区间的最小数量，就是连接最多的区间。所以，在按照左排序的情况下，为了右边尽可能的多，如果它的左边界在前一个元素的右边界之内那么发生了重叠，我们移除前一个元素还是移除当前元素是依据谁的右边界更小（因为右边界更长那么更有可能与后面的元素发生重叠）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func eraseOverlapIntervals(intervals [][]int) int {
    if len(intervals) &amp;lt;= 1 {
        return 0
    }

    sort.Slice(intervals, func(i, j int) bool {
        return intervals[i][0] &amp;lt; intervals[j][0]
    })

    count := 0
    for i, j := 0, 1; j &amp;lt; len(intervals); j++ {
        if intervals[i][1] &amp;lt;= intervals[j][0] {
            i = j
        }else {
             if intervals[i][1] &amp;gt; intervals[j][1] {
                i = j
            }   
            count++
        }  
    }
    return count
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是右边界排序的方法，和上面的思路差不多，只是少了一个判断的条件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func eraseOverlapIntervals(intervals [][]int) int {
    if len(intervals) &amp;lt;= 1 {
        return 0
    }

    sort.Slice(intervals, func(i, j int) bool {
        return intervals[i][1] &amp;lt; intervals[j][1] 
    })

    count := 0
    end := intervals[0][1]
    for i := 1; i &amp;lt; len(intervals); i++ {
        if intervals[i][0] &amp;lt; end { 
            count++                
        } else {                   
            end = intervals[i][1]  
        }
    }
    return count
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-452. 用最少数量的箭引爆气球</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-452-%E7%94%A8%E6%9C%80%E5%B0%91%E6%95%B0%E9%87%8F%E7%9A%84%E7%AE%AD%E5%BC%95%E7%88%86%E6%B0%94%E7%90%83/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-452-%E7%94%A8%E6%9C%80%E5%B0%91%E6%95%B0%E9%87%8F%E7%9A%84%E7%AE%AD%E5%BC%95%E7%88%86%E6%B0%94%E7%90%83/</guid><pubDate>Fri, 17 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/&quot;&gt;&lt;strong&gt;452. 用最少数量的箭引爆气球&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 &lt;code&gt;points&lt;/code&gt; ，其中&lt;code&gt;points[i] = [xstart, xend]&lt;/code&gt; 表示水平直径在 &lt;code&gt;xstart&lt;/code&gt; 和 &lt;code&gt;xend&lt;/code&gt;之间的气球。你不知道气球的确切 y 坐标。&lt;/p&gt;
&lt;p&gt;一支弓箭可以沿着 x 轴从不同点 &lt;strong&gt;完全垂直&lt;/strong&gt; 地射出。在坐标 &lt;code&gt;x&lt;/code&gt; 处射出一支箭，若有一个气球的直径的开始和结束坐标为 &lt;code&gt;xstart&lt;/code&gt;，&lt;code&gt;xend&lt;/code&gt;， 且满足  &lt;code&gt;xstart ≤ x ≤ xend&lt;/code&gt;，则该气球会被 &lt;strong&gt;引爆&lt;/strong&gt; 。可以射出的弓箭的数量 &lt;strong&gt;没有限制&lt;/strong&gt; 。 弓箭一旦被射出之后，可以无限地前进。&lt;/p&gt;
&lt;p&gt;给你一个数组 &lt;code&gt;points&lt;/code&gt; ，&lt;em&gt;返回引爆所有气球所必须射出的 &lt;strong&gt;最小&lt;/strong&gt; 弓箭数&lt;/em&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后，剩下的区间没有重叠。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间，因为它们已经是无重叠的了。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路(自己完成)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路和 &lt;a href=&quot;https://leetcode.cn/problems/non-overlapping-intervals/&quot;&gt;&lt;strong&gt;435. 无重叠区间&lt;/strong&gt;&lt;/a&gt; 类似，其中这段代码&lt;code&gt; else { end = points[i][1] }&lt;/code&gt;，确保&lt;code&gt;end&lt;/code&gt;的右边界最大，只要在end左侧即可重叠，箭的次数减一。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func findMinArrowShots(points [][]int) int {
    if len(points) &amp;lt;= 1 {
        return 1
    }

    sort.Slice(points, func(i, j int) bool {
        return points[i][1] &amp;lt; points[j][1] 
    })

    count := len(points)
    end := points[0][1]
    for i := 1; i &amp;lt; len(points); i++ {
        if points[i][0] &amp;lt;= end {
            count--

        }else {
            end = points[i][1]
        }
    }
    return count
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-121. 买卖股票的最佳时机</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-121-%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-121-%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BA/</guid><pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/&quot;&gt;&lt;strong&gt;121. 买卖股票的最佳时机&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个数组 &lt;code&gt;prices&lt;/code&gt; ，它的第 &lt;code&gt;i&lt;/code&gt; 个元素 &lt;code&gt;prices[i]&lt;/code&gt; 表示一支给定股票第 &lt;code&gt;i&lt;/code&gt; 天的价格。&lt;/p&gt;
&lt;p&gt;你只能选择 &lt;strong&gt;某一天&lt;/strong&gt; 买入这只股票，并选择在 &lt;strong&gt;未来的某一个不同的日子&lt;/strong&gt; 卖出该股票。设计一个算法来计算你所能获取的最大利润。&lt;/p&gt;
&lt;p&gt;返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润，返回 &lt;code&gt;0&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：[7,1,5,3,6,4]
输出：5
解释：在第 2 天（股票价格 = 1）的时候买入，在第 5 天（股票价格 = 6）的时候卖出，最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格；同时，你不能在买入前卖出股票。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：prices = [7,6,4,3,1]
输出：0
解释：在这种情况下, 没有交易完成, 所以最大利润为 0。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ai润色后的思路，就是之前用切片只关注栈顶元素，有点浪费空间(这里我有点理解最小栈不止访问上一个元素)，这里只需要一个变量即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxProfit(prices []int) int {
    minPrice := prices[0]
    profit := 0

    for _, price := range prices {
        minPrice = min(minPrice, price)
        profit = max(profit, price - minPrice)
    }

    return profit
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;手撕思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可能是之前刚做完最小栈的题目，这里我自然而然地想到了，就是用一个切片储存当前的最小值，&lt;code&gt;profit = price - minVal&lt;/code&gt;即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxProfit(prices []int) int {
    var stack []int
    profit := 0

    for _, v := range prices {
        minVal := v
        if len(stack) &amp;gt; 0 {
            if v &amp;gt; stack[len(stack)-1] {
                minVal = stack[len(stack)-1]
            }
        }

        profit = max(profit, v - minVal)
        stack = append(stack, minVal)
    }

    return profit
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-45. 跳跃游戏 II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-45-%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F-ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-45-%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F-ii/</guid><pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/jump-game-ii/&quot;&gt;&lt;strong&gt;45. 跳跃游戏 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个长度为 &lt;code&gt;n&lt;/code&gt; 的 &lt;strong&gt;0 索引&lt;/strong&gt;整数数组 &lt;code&gt;nums&lt;/code&gt;。初始位置在下标 0。&lt;/p&gt;
&lt;p&gt;每个元素 &lt;code&gt;nums[i]&lt;/code&gt; 表示从索引 &lt;code&gt;i&lt;/code&gt; 向后跳转的最大长度。换句话说，如果你在索引 &lt;code&gt;i&lt;/code&gt; 处，你可以跳转到任意 &lt;code&gt;(i + j)&lt;/code&gt; 处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0 &amp;lt;= j &amp;lt;= nums[i]&lt;/code&gt; 且&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i + j &amp;lt; n&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;返回到达 &lt;code&gt;n - 1&lt;/code&gt; 的最小跳跃次数。测试用例保证可以到达 &lt;code&gt;n - 1&lt;/code&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置，跳 1 步，然后跳 3 步到达数组的最后一个位置。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [2,3,0,1,4]
输出: 2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题我们很容易陷入逻辑定式“跳跃”中，到跳跃的地方是不是就需要&lt;code&gt;jump++&lt;/code&gt;了?（其实不需要，这层跳跃结束后统计的次数+1即可）&lt;/p&gt;
&lt;p&gt;本题我们只需要实现类似&lt;code&gt;queue&lt;/code&gt;的层序遍历即可，因为已经有数组&lt;code&gt;nums&lt;/code&gt;的存在，所以我们无需真创立一个&lt;code&gt;queue&lt;/code&gt;队列，只需要判断他们的&lt;code&gt;index&lt;/code&gt;即可。&lt;/p&gt;
&lt;p&gt;相较于 &lt;a href=&quot;https://leetcode.cn/problems/jump-game/&quot;&gt;&lt;strong&gt;55. 跳跃游戏&lt;/strong&gt;&lt;/a&gt; ，我们还需要变量&lt;code&gt;currentEnd&lt;/code&gt;，确定当前这一步的覆盖边界在哪里，&lt;code&gt;curEnd := 0&lt;/code&gt;和&lt;code&gt;if i == curEnd {}&lt;/code&gt;完美开始第一层跳跃。后面就和上一题类似了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func jump(nums []int) int {
    if len(nums) == 1 {
        return 0
    }

    jumps := 0
    curEnd := 0
    maxReach := 0
    
    for i := 0; i &amp;lt; len(nums)-1; i++ {
        maxReach = max(maxReach, i + nums[i])

        if i == curEnd {
            jumps++
            curEnd = maxReach
        }
    }
    return jumps
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-455. 分发饼干</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-455-%E5%88%86%E5%8F%91%E9%A5%BC%E5%B9%B2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-455-%E5%88%86%E5%8F%91%E9%A5%BC%E5%B9%B2/</guid><pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/assign-cookies/&quot;&gt;&lt;strong&gt;455. 分发饼干&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;假设你是一位很棒的家长，想要给你的孩子们一些小饼干。但是，每个孩子最多只能给一块饼干。&lt;/p&gt;
&lt;p&gt;对每个孩子 &lt;code&gt;i&lt;/code&gt;，都有一个胃口值 &lt;code&gt;g[i]&lt;/code&gt;，这是能让孩子们满足胃口的饼干的最小尺寸；并且每块饼干 &lt;code&gt;j&lt;/code&gt;，都有一个尺寸 &lt;code&gt;s[j]&lt;/code&gt; 。如果 &lt;code&gt;s[j] &amp;gt;= g[i]&lt;/code&gt;，我们可以将这个饼干 &lt;code&gt;j&lt;/code&gt; 分配给孩子 &lt;code&gt;i&lt;/code&gt; ，这个孩子会得到满足。你的目标是满足尽可能多的孩子，并输出这个最大数值。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干，3 个孩子的胃口值分别是：1,2,3。
虽然你有两块小饼干，由于他们的尺寸都是 1，你只能让胃口值是 1 的孩子满足。
所以你应该输出 1。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干，2 个孩子的胃口值分别是 1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出 2。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;手撕思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;就很直观，顺其自然&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func findContentChildren(g []int, s []int) int {
    sort.Ints(g)
    sort.Ints(s)

    left, right := 0, 0
    count := 0
    for left &amp;lt; len(g) &amp;amp;&amp;amp; right &amp;lt; len(s) {
        if g[left] &amp;lt;= s[right] {
            count++
            left++
        }

        right++
    }

    return count
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-55. 跳跃游戏</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-55-%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-55-%E8%B7%B3%E8%B7%83%E6%B8%B8%E6%88%8F/</guid><pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/jump-game/&quot;&gt;&lt;strong&gt;55. 跳跃游戏&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个非负整数数组 &lt;code&gt;nums&lt;/code&gt; ，你最初位于数组的 &lt;strong&gt;第一个下标&lt;/strong&gt; 。数组中的每个元素代表你在该位置可以跳跃的最大长度。&lt;/p&gt;
&lt;p&gt;判断你是否能够到达最后一个下标，如果可以，返回 &lt;code&gt;true&lt;/code&gt; ；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [2,3,1,1,4]
输出：true
解释：可以先跳 1 步，从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [3,2,1,0,4]
输出：false
解释：无论怎样，总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 ， 所以永远不可能到达最后一个下标。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我认为这题很有贪心算法的感觉。&lt;/p&gt;
&lt;p&gt;这题的思路就是：相较于去盯着那些会卡住我们的 &lt;code&gt;0&lt;/code&gt;，不如判断最远能走到哪里&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;维护一个变量 &lt;code&gt;maxReach&lt;/code&gt;，表示目前能跳到的最远距离。&lt;/li&gt;
&lt;li&gt;我们按顺序遍历每个格子 &lt;code&gt;i&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生死判定&lt;/strong&gt;：如果当前所在的格子 &lt;code&gt;i&lt;/code&gt; 已经超出了 &lt;code&gt;maxReach&lt;/code&gt;，说明我们连当前这个格子都走不到，更别提终点了，直接返回 &lt;code&gt;false&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;贪心更新&lt;/strong&gt;：如果能走到格子 &lt;code&gt;i&lt;/code&gt;，就计算覆盖的新边界是 &lt;code&gt;i + nums[i]&lt;/code&gt;。把 &lt;code&gt;maxReach&lt;/code&gt; 更新为历史最大值&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func canJump(nums []int) bool {
    maxReach := 0

    for i, num := range nums {
        if i &amp;gt; maxReach {
            return false
        }
        maxReach = max(maxReach, i + num)
    }
    return true
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-763. 划分字母区间</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-763-%E5%88%92%E5%88%86%E5%AD%97%E6%AF%8D%E5%8C%BA%E9%97%B4/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95/leetcode-763-%E5%88%92%E5%88%86%E5%AD%97%E6%AF%8D%E5%8C%BA%E9%97%B4/</guid><pubDate>Thu, 16 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/partition-labels/&quot;&gt;&lt;strong&gt;763. 划分字母区间&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个字符串 &lt;code&gt;s&lt;/code&gt; 。我们要把这个字符串划分为尽可能多的片段，同一字母最多出现在一个片段中。例如，字符串 &lt;code&gt;&quot;ababcc&quot;&lt;/code&gt; 能够被分为 &lt;code&gt;[&quot;abab&quot;, &quot;cc&quot;]&lt;/code&gt;，但类似 &lt;code&gt;[&quot;aba&quot;, &quot;bcc&quot;]&lt;/code&gt; 或 &lt;code&gt;[&quot;ab&quot;, &quot;ab&quot;, &quot;cc&quot;]&lt;/code&gt; 的划分是非法的。&lt;/p&gt;
&lt;p&gt;注意，划分结果需要满足：将所有划分结果按顺序连接，得到的字符串仍然是 &lt;code&gt;s&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;返回一个表示每个字符串片段的长度的列表。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;ababcbacadefegdehijhklij&quot;
输出：[9,7,8]
解释：
划分结果为 &quot;ababcbaca&quot;、&quot;defegde&quot;、&quot;hijhklij&quot; 。
每个字母最多出现在一个片段中。
像 &quot;ababcbacadefegde&quot;, &quot;hijhklij&quot; 这样的划分是错误的，因为划分的片段数较少。 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;eccbbbbdec&quot;
输出：[10]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题，我们的问题是如何确定一个片段？即如何判断所包含的字母是否全出现在这里。&lt;/p&gt;
&lt;p&gt;如果我们想用&lt;code&gt;[]int{}&lt;/code&gt;，每统计一次就减一直至为0判断，这样很难实现且麻烦。其实我们只需要关注每个字母的最后一个所在的&lt;code&gt;index&lt;/code&gt;即可，前面的并不重要，只需&lt;code&gt;right = max(right, index)&lt;/code&gt;，找到右边界的最大值即可确定整个片段。后面，&lt;code&gt;left = right + 1&lt;/code&gt;重复即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func partitionLabels(s string) []int {
    lastPos := [26]int{}
    for i := 0; i &amp;lt; len(s); i++ {
        lastPos[s[i]-&apos;a&apos;] = i
    }

    left, right := 0, 0
    res := []int{}
    for i := 0; i &amp;lt; len(s); i++ {
        index := lastPos[s[i]-&apos;a&apos;] 
        right = max(right, index)
        if i == right {
            res = append(res, right-left+1)
            left = right + 1
        }
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>力扣数据结构部分的一些笔记</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%9B%E6%89%A3%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E9%83%A8%E5%88%86%E7%9A%84%E4%B8%80%E4%BA%9B%E7%AC%94%E8%AE%B0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%9B%E6%89%A3%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E9%83%A8%E5%88%86%E7%9A%84%E4%B8%80%E4%BA%9B%E7%AC%94%E8%AE%B0/</guid><pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;用空间换时间&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;哈希表一般有三种：&lt;code&gt;数组&lt;/code&gt;、&lt;code&gt;set(map[T]struct{}模拟)&lt;/code&gt; 和 &lt;code&gt;map&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数组：&lt;/strong&gt; 数据规模较小 或者 有连续的要求.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;使用数组来做哈希的题目，是因为题目都限制了数值的大小。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**Set： **数据规模大、无序，或者跨度极大。&lt;strong&gt;只需判断元素“存不存在”&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;而且如果哈希值比较少、特别分散、跨度非常大，使用数组就造成空间的极大浪费。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**Map(最全面)： **不仅要判断元素存不存在，&lt;strong&gt;还需要记录该元素的附带信息&lt;/strong&gt;（如出现次数、数组下标等）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;一些哈希表的易错点：&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Map 未初始化直接使用&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var m map[int]int //此时 m 是 nil

m[1] = 1 //❌会panic崩溃
m := make(map[int]int) //✅

&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;切片类似&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;s[0] = 1不行，append可以&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;map遍历是无序的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;有序需要数组&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3&gt;矩阵&lt;/h3&gt;
&lt;p&gt;矩阵主要有三种类型的题目:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;边界收缩法（应对“复杂轨迹遍历”类题目）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;核心思想：&lt;/strong&gt; 遇到要在矩阵里绕圈圈、走蛇形、走对角线的题目，直接定义上、下、左、右四个物理边界（top, bottom, left, right），走完一条边，就把对应的边界往里缩一格。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 顺时针打印矩阵、逆时针打印矩阵、按对角线打印矩阵。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**易错点：**要记得判断“长方形矩阵”中，某一个维度提前耗尽的情况。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;就地标记法（应对“状态更新与空间压榨”类题目）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;核心思想：&lt;/strong&gt; 当题目要求你根据矩阵当前的状态，去大规模修改矩阵本身，且要求 O(1)空间复杂度时，直接拿矩阵的第一行、第一列，或者利用数字的特殊位（比如把状态存在二进制的高位里），当成你的“记事本”。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 矩阵置零、生命游戏等状态同步更新问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;易错点：&lt;/strong&gt; 拿第一行/列当记事本时，一定要记得&lt;strong&gt;最开始先单独记录&lt;/strong&gt;它们原本的状态，并且在&lt;strong&gt;最后&lt;/strong&gt;才去修改它们。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;降维组合翻转（应对“几何旋转/对称”类题目）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心思想：&lt;/strong&gt; 把“旋转”拆解成两次最简单的“翻转”（对角线翻转 + 水平/垂直翻转）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 顺时针旋转图像、逆时针旋转图像。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;易错点：&lt;/strong&gt; 翻转时，内层循环的边界控制极其重要。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;链表主要有这几个方法：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 虚拟头节点 (Dummy Head)：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;本质&lt;/strong&gt;：用一个毫无意义的假节点挡在真实数据前面，充当“前驱节点”。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：所有涉及&lt;strong&gt;头节点可能被修改、删除或重新分配&lt;/strong&gt;的题目（如：移除元素、合并两个有序链表）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 快慢指针（Fast &amp;amp; Slow Pointers)：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;利用两个指针的&lt;strong&gt;速度差&lt;/strong&gt;来探测链表的物理结构。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本质&lt;/strong&gt;：慢指针每次走 1 步，快指针每次走 2 步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：&lt;strong&gt;寻找中点、判断循环闭环&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;环形链表 I &amp;amp; II&lt;/strong&gt;（141、142题，判断有没有环）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;链表的中间结点&lt;/strong&gt;（876题，快指针走到 &lt;code&gt;nil&lt;/code&gt;，慢指针刚好停在正中间）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回文链表&lt;/strong&gt;（234题，O(1) 空间复杂度的核心，先找中点，再反转后半段）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;排序链表&lt;/strong&gt;（148题，归并排序“分而治之”里切断链表的那一刀）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;**3.双指针有距离差 **&lt;/p&gt;
&lt;p&gt;不改变速度，而是让两个指针在&lt;strong&gt;出发时间&lt;/strong&gt;或&lt;strong&gt;所走路径&lt;/strong&gt;上做文章。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本质&lt;/strong&gt;：让指针多走一段特定距离，或者互相走对方走过的路。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：找倒数节点、找两个无关链表的交点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;删除链表的倒数第 N 个结点&lt;/strong&gt;（19题，让 &lt;code&gt;fast&lt;/code&gt; 先跑 N 步，然后 &lt;code&gt;slow&lt;/code&gt; 和 &lt;code&gt;fast&lt;/code&gt; 齐头并进，&lt;code&gt;fast&lt;/code&gt; 到底时 &lt;code&gt;slow&lt;/code&gt; 刚好停在目标前面）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;相交链表&lt;/strong&gt;（160题，走你来时路）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4.指针重排 (反转/交换)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本质&lt;/strong&gt;：&lt;strong&gt;多指针协同 (pre, cur, next)。&lt;/strong&gt;&lt;code&gt;next := cur.Next; cur.Next = pre; pre = cur; cur = next&lt;/code&gt;。永远记住要先 暂存下一个节点，防止断链！&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：原地掉头、局部结构逆转。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;反转链表 I &amp;amp; II&lt;/strong&gt;（206题全量反转，92题局部反转）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;K 个一组翻转链表&lt;/strong&gt;（25题，内部反转配合外部 Dummy 头插法缝合）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h4&gt;二叉树&lt;/h4&gt;
&lt;p&gt;其实二叉树基本上都是用递归实现的，只不过是直接调用自身、还是重新设立一个辅助函数或设立一个包内全局变量，这就要看题目了。下面就简单地分类一下&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 后序遍历（大部分可以直接调用自身）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;本质：&lt;/strong&gt; 当前节点“做不了主”，必须等左子树和右子树把各自的结果算出来并“归还”给自己，自己才能整合出最终结果并向上一级汇报。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 求树的深度/高度、求最大路径和、寻找公共祖先。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适用题目：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;二叉树的最大深度（104题）：&lt;/strong&gt; 问左边有多深，问右边有多深，取两者的最大值 &lt;code&gt;+ 1&lt;/code&gt;（加上自己这一层）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;二叉树的最近公共祖先（236题）：&lt;/strong&gt; 如果左子树传来发现 &lt;code&gt;p&lt;/code&gt; 的信号，右子树传来发现 &lt;code&gt;q&lt;/code&gt; 的信号，那我（当前节点）绝对就是它俩的最近公共祖先！&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;二叉树的直径（543题）&amp;amp; 二叉树中的最大路径和（124题）：&lt;/strong&gt; 递归函数只负责向上汇报“单边最大收益”，但在当前节点内部，偷偷用一个全局变量记录 &lt;code&gt;左收益 + 右收益 + 自己&lt;/code&gt; 的最大值（暗度陈仓）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 前序遍历（大部分需要另设辅助函数）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本质：&lt;/strong&gt; 视角在“下去的路上”。父节点拿到数据后，先在自己身上动刀子（处理逻辑），或者把自己的状态当做参数传给子节点，然后再叫子节点去干活。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 修改/翻转树的物理结构、依据给定序列重构二叉树、路径匹配。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用题目：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;翻转二叉树（226题）：&lt;/strong&gt; 先把自己的左手和右手互换（&lt;code&gt;node.Left, node.Right = node.Right, node.Left&lt;/code&gt;），然后再让儿子们去换他们自己的手。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;从前序与中序遍历序列构造二叉树（105题）：&lt;/strong&gt; 前序数组的第一个必定是根！拿着这个根去中序数组里找一刀切开，左边就是左子树的全部节点，右边就是右子树的全部节点，然后递归切割。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;路径总和 III（437题）：&lt;/strong&gt; 配合前缀和思想，把当前一路走来累加的路径和作为参数，不断传给下一代去匹配目标值。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 二叉搜索树 (BST)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;本质：&lt;/strong&gt; 利用 BST “左 &amp;lt; 根 &amp;lt; 右” 的天然物理结构。&lt;strong&gt;BST 的中序遍历（左 -&amp;gt; 根 -&amp;gt; 右）必定输出一个严格递增的有序序列。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 所有带“二叉搜索树”字眼的题目（验证、查找第 K 小、转成有序结构）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用题目：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;验证二叉搜索树（98题）：&lt;/strong&gt; 核心就是中序遍历。用一个变量 &lt;code&gt;pre&lt;/code&gt; 记录上一个访问的节点值，必须保证每次访问的新节点值都严格大于 &lt;code&gt;pre&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二叉搜索树中第K小的元素（230题）：&lt;/strong&gt; 最直观的降维打击。顺着中序遍历走，搞个计数器，数到第 &lt;code&gt;K&lt;/code&gt; 个直接返回，这就是第 K 小。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;将有序数组转换为二叉搜索树（108题）：&lt;/strong&gt; 反向利用有序性。找数组最中间的数当根节点，左半段数组递归构建左子树，右半段递归构建右子树，天然保证高度平衡。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;4. 层序遍历 (BFS)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;**本质：**BFS的应用。 借助Queue 的先进先出特性。永远记住在每层开始前获取 &lt;code&gt;size := len(queue)&lt;/code&gt;，用这个 &lt;code&gt;size&lt;/code&gt; 把这一层的节点全掏出来，并把它们下一层的儿子们塞进去。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 按层处理、找最短层级、求各类“视图”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用题目：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;二叉树的层序遍历（102题）：&lt;/strong&gt; 纯正模板题，按 &lt;code&gt;size&lt;/code&gt; 分批次出队，将同一层的值收集进一个数组。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;二叉树的右视图（199题）：&lt;/strong&gt; 层序遍历的微调版。每一层有 &lt;code&gt;size&lt;/code&gt; 个节点，我只把 &lt;code&gt;i == size - 1&lt;/code&gt;（当前层的最后一个节点）抓出来塞进结果集里。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h4&gt;图论&lt;/h4&gt;
&lt;hr /&gt;
&lt;h4&gt;栈&lt;/h4&gt;
&lt;p&gt;栈的题目类型还是比较少的，大致有下面三类&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 消除与配对&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：[20. 有效的括号]、[1047. 删除字符串中的所有相邻重复项]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：题目包含“对称”、“消除”、“最近匹配”等字眼。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 嵌套与现场恢复&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：[394. 字符串解码]、[71. 简化路径]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：题目涉及括号嵌套、递归逻辑的迭代实现。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;逻辑特征&lt;/strong&gt;：遇到 &lt;code&gt;[&lt;/code&gt; 或进入子层级时，将当前状态（前缀、倍数等）压栈；遇到 &lt;code&gt;]&lt;/code&gt; 时，弹出栈顶状态与当前结果合并。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 单调栈&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：[739. 每日温度]、[84. 柱状图中最大的矩形]、[42. 接雨水]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：寻找“下一个更大/更小元素”、“左/右侧第一个极值”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;逻辑特征&lt;/strong&gt;：维护栈内元素单调递增或递减。新元素打破单调性时，触发“批量结算”。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>LeetCode-155. 最小栈</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-155-%E6%9C%80%E5%B0%8F%E6%A0%88/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-155-%E6%9C%80%E5%B0%8F%E6%A0%88/</guid><pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;栈&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/min-stack/&quot;&gt;&lt;strong&gt;155. 最小栈&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;设计一个支持 &lt;code&gt;push&lt;/code&gt; ，&lt;code&gt;pop&lt;/code&gt; ，&lt;code&gt;top&lt;/code&gt; 操作，并能在常数时间内检索到最小元素的栈。&lt;/p&gt;
&lt;p&gt;实现 &lt;code&gt;MinStack&lt;/code&gt; 类:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MinStack()&lt;/code&gt; 初始化堆栈对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void push(int val)&lt;/code&gt; 将元素val推入堆栈。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void pop()&lt;/code&gt; 删除堆栈顶部的元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int top()&lt;/code&gt; 获取堆栈顶部的元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int getMin()&lt;/code&gt; 获取堆栈中的最小元素。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：
[&quot;MinStack&quot;,&quot;push&quot;,&quot;push&quot;,&quot;push&quot;,&quot;getMin&quot;,&quot;pop&quot;,&quot;top&quot;,&quot;getMin&quot;]
[[],[-2],[0],[-3],[],[],[],[]]

输出：
[null,null,null,null,-3,null,0,-2]

解释：
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --&amp;gt; 返回 -3.
minStack.pop();
minStack.top();      --&amp;gt; 返回 0.
minStack.getMin();   --&amp;gt; 返回 -2.
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最小栈的问题就是如何在把最小值&lt;code&gt;pop&lt;/code&gt;后知道倒数第二小的值。&lt;/p&gt;
&lt;p&gt;这里的方法是在存储一个&lt;code&gt;val&lt;/code&gt;的同时存储一个目前为止的最小值，这样把最小值踢了后，还保留最小值存入前的最小值。其他的就没什么了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type item struct {
    val int
    min int
}

type MinStack struct {
    stack []item
}

func Constructor() MinStack {
    return MinStack{
			stack: make([]item, 0),
		}
}

func (this *MinStack) Push(val int)  {
    minVal := val

    if len(this.stack) &amp;gt; 0 {
        curMin := this.stack[len(this.stack)-1].min
        if val &amp;gt; curMin {
            minVal = curMin
        } 
    }

    this.stack = append(this.stack, item{val: val, min: minVal})
}


func (this *MinStack) Pop()  {
    if len(this.stack) &amp;gt; 0 {
        this.stack = this.stack[:len(this.stack)-1]
    }
}


func (this *MinStack) Top() int {
    return this.stack[len(this.stack)-1].val
}


func (this *MinStack) GetMin() int {
    return this.stack[len(this.stack)-1].min
}


/**
 * Your MinStack object will be instantiated and called as such:
 * obj := Constructor();
 * obj.Push(val);
 * obj.Pop();
 * param_3 := obj.Top();
 * param_4 := obj.GetMin();
 */
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>2026-4-13-weekly5&amp;6</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-4-13-weekly56/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-4-13-weekly56/</guid><pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h4&gt;本两周摘要&lt;/h4&gt;
&lt;p&gt;由于上个周一是清明节放假，我给整忘了，所以就把两周整合在一起做个总结。这两周主要是在完成hot100的回溯、二分查找和栈这三个部分。刷了多少题没什么印象，不过我博客上算法部分统计有100题了，hot100也刷了七十多题了，还是可喜可贺的。&lt;/p&gt;
&lt;h4&gt;一、具体完成事项&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;刷力扣&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完成回溯的hot100题目&lt;/li&gt;
&lt;li&gt;完成二分查找的hot100题目&lt;/li&gt;
&lt;li&gt;完成栈的hot100题目&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;二、复盘与反思&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;感觉这几部分没想象的那么难，看过代码后，很容易理解逻辑并独立写下代码&lt;/li&gt;
&lt;li&gt;不过距离手撕感觉还有不小的距离&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​&lt;/p&gt;
&lt;h4&gt;三、下周计划&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;继续力扣hot100&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>LeetCode-20. 有效的括号</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-20-%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-20-%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7/</guid><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;栈&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/valid-parentheses/&quot;&gt;&lt;strong&gt;20. 有效的括号&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个只包括 &lt;code&gt;&apos;(&apos;&lt;/code&gt;，&lt;code&gt;&apos;)&apos;&lt;/code&gt;，&lt;code&gt;&apos;{&apos;&lt;/code&gt;，&lt;code&gt;&apos;}&apos;&lt;/code&gt;，&lt;code&gt;&apos;[&apos;&lt;/code&gt;，&lt;code&gt;&apos;]&apos;&lt;/code&gt; 的字符串 &lt;code&gt;s&lt;/code&gt; ，判断字符串是否有效。&lt;/p&gt;
&lt;p&gt;有效字符串需满足：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;左括号必须用相同类型的右括号闭合。&lt;/li&gt;
&lt;li&gt;左括号必须以正确的顺序闭合。&lt;/li&gt;
&lt;li&gt;每个右括号都有一个对应的相同类型的左括号。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**s = &quot;()&quot;&lt;/p&gt;
&lt;p&gt;**输出：**true&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**s = &quot;()[]{}&quot;&lt;/p&gt;
&lt;p&gt;**输出：**true&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**s = &quot;(]&quot;&lt;/p&gt;
&lt;p&gt;**输出：**false&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 4：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**s = &quot;([])&quot;&lt;/p&gt;
&lt;p&gt;**输出：**true&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 5：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**s = &quot;([)]&quot;&lt;/p&gt;
&lt;p&gt;**输出：**false&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;初识栈，这题就是利用栈道对称性，思路挺简单的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func isValid(s string) bool {
    if len(s)%2 == 1 {
        return false
    }

    stack := make([]rune, 0)

    for _, v := range s {
        if v == &apos;(&apos; {
            stack = append(stack, &apos;)&apos;)
        }else if v == &apos;{&apos; {
            stack = append(stack, &apos;}&apos;)
        }else if v == &apos;[&apos; {
            stack = append(stack, &apos;]&apos;)
        }else {
            if len(stack) == 0 || stack[len(stack)-1] != v {
                return false
            }
            stack = stack[:len(stack)-1]
        }
    }

    if len(stack) == 0 {
        return true
    }else {
        return false
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-739. 每日温度</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-739-%E6%AF%8F%E6%97%A5%E6%B8%A9%E5%BA%A6/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-739-%E6%AF%8F%E6%97%A5%E6%B8%A9%E5%BA%A6/</guid><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;栈&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/daily-temperatures/&quot;&gt;&lt;strong&gt;739. 每日温度&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个整数数组 &lt;code&gt;temperatures&lt;/code&gt; ，表示每天的温度，返回一个数组 &lt;code&gt;answer&lt;/code&gt; ，其中 &lt;code&gt;answer[i]&lt;/code&gt; 是指对于第 &lt;code&gt;i&lt;/code&gt; 天，下一个更高温度出现在几天后。如果气温在这之后都不会升高，请在该位置用 &lt;code&gt;0&lt;/code&gt; 来代替。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: temperatures = [30,60,90]
输出: [1,1,0]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;尝试写一下逻辑为什么用单调栈&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;这题暴力法两个&lt;code&gt;for&lt;/code&gt;要重复扫描，所以需要数据结构存储数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;求&lt;strong&gt;最近&lt;/strong&gt;的较大值，所以需要栈&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;大的会挡住小的，小的没用了 ，所以 栈必须是单调的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以，这题可以得出需要单调栈&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func dailyTemperatures(temperatures []int) []int {
    n := len(temperatures)
    res := make([]int, n)
    stack := make([]int, 0)

    for i, v := range temperatures {
        for len(stack) &amp;gt; 0 &amp;amp;&amp;amp; v &amp;gt; temperatures[stack[len(stack)-1]] {
            index := stack[len(stack)-1]
            stack = stack[:len(stack)-1]
            res[index] = i - index
        }
        stack = append(stack, i)
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-394. 字符串解码</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-394-%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%A7%A3%E7%A0%81/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-394-%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%A7%A3%E7%A0%81/</guid><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;栈&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/decode-string/&quot;&gt;&lt;strong&gt;394. 字符串解码&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个经过编码的字符串，返回它解码后的字符串。&lt;/p&gt;
&lt;p&gt;编码规则为: &lt;code&gt;k[encoded_string]&lt;/code&gt;，表示其中方括号内部的 &lt;code&gt;encoded_string&lt;/code&gt; 正好重复 &lt;code&gt;k&lt;/code&gt; 次。注意 &lt;code&gt;k&lt;/code&gt; 保证为正整数。&lt;/p&gt;
&lt;p&gt;你可以认为输入字符串总是有效的；输入字符串中没有额外的空格，且输入的方括号总是符合格式要求的。&lt;/p&gt;
&lt;p&gt;此外，你可以认为原始数据不包含数字，所有的数字只表示重复的次数 &lt;code&gt;k&lt;/code&gt; ，例如不会出现像 &lt;code&gt;3a&lt;/code&gt; 或 &lt;code&gt;2[4]&lt;/code&gt; 的输入。&lt;/p&gt;
&lt;p&gt;测试用例保证输出的长度不会超过 &lt;code&gt;105&lt;/code&gt;。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;3[a]2[bc]&quot;
输出：&quot;aaabcbc&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;3[a2[c]]&quot;
输出：&quot;accaccacc&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;2[abc]3[cd]ef&quot;
输出：&quot;abcabccdcdcdef&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 4：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;abc3[cd]xyz&quot;
输出：&quot;abccdcdcdxyz&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;虽然看着很麻烦，其实逻辑挺简单的，和人脑想的顺序一样。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;遇到了字母，那拿一个普通变量&lt;code&gt;curStr&lt;/code&gt;储存&lt;/li&gt;
&lt;li&gt;遇到了数字，那再拿一个普通变量&lt;code&gt;curNum&lt;/code&gt;储存&lt;/li&gt;
&lt;li&gt;遇到了&lt;code&gt;[&lt;/code&gt;，需要暂存前面的字母和数字，那就存入栈了，继续处理括号里面的内容&lt;/li&gt;
&lt;li&gt;遇到了&lt;code&gt;]&lt;/code&gt;，可以组成一个&lt;code&gt;string&lt;/code&gt;了，那就从栈后进先出，获取前面对应的字母和数字，拼接&lt;/li&gt;
&lt;li&gt;重复操作&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ps：可能是golang中像队列、栈这些都是用切片实现的，所以对栈没有太多感受&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func decodeString(s string) string {
    strStack := []string{}
    numStack := []int{}

    curStr := &quot;&quot;
    curNum := 0

    for _, char := range s {
        if char &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; char &amp;lt;= &apos;9&apos; {
            curNum = curNum*10 + int(char-&apos;0&apos;)
        }else if char &amp;gt;= &apos;a&apos; &amp;amp;&amp;amp; char &amp;lt;= &apos;z&apos; || char &amp;gt;= &apos;A&apos; &amp;amp;&amp;amp; char &amp;lt;= &apos;Z&apos; {
            curStr += string(char) 
        }else if char == &apos;[&apos; {
            numStack = append(numStack, curNum)
            curNum = 0

            strStack = append(strStack, curStr)
            curStr = &quot;&quot;
        }else {
            num := numStack[len(numStack)-1]
            numStack = numStack[:len(numStack)-1]

            str := strStack[len(strStack)-1]
            strStack = strStack[:len(strStack)-1]

            curStr = str + strings.Repeat(curStr, num)
        }
    }
    return curStr
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-84. 柱状图中最大的矩形</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-84-%E6%9F%B1%E7%8A%B6%E5%9B%BE%E4%B8%AD%E6%9C%80%E5%A4%A7%E7%9A%84%E7%9F%A9%E5%BD%A2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%A0%88/leetcode-84-%E6%9F%B1%E7%8A%B6%E5%9B%BE%E4%B8%AD%E6%9C%80%E5%A4%A7%E7%9A%84%E7%9F%A9%E5%BD%A2/</guid><pubDate>Sun, 12 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;栈&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/largest-rectangle-in-histogram/&quot;&gt;&lt;strong&gt;84. 柱状图中最大的矩形&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定 &lt;em&gt;n&lt;/em&gt; 个非负整数，用来表示柱状图中各个柱子的高度。每个柱子彼此相邻，且宽度为 1 。&lt;/p&gt;
&lt;p&gt;求在该柱状图中，能够勾勒出来的矩形的最大面积。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/04/histogram.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：heights = [2,1,5,6,2,3]
输出：10
解释：最大的矩形为图中红色区域，面积为 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/04/histogram-1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入： heights = [2,4]
输出： 4
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题可以说是 &lt;a href=&quot;https://leetcode.cn/problems/daily-temperatures/&quot;&gt;&lt;strong&gt;739. 每日温度&lt;/strong&gt;&lt;/a&gt; 的升级版，这里有两个我遇到的难点&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;怎么确立左右边界？&lt;/p&gt;
&lt;p&gt;右边界与每日温度类似，都是&lt;code&gt;i&lt;/code&gt;，这里不多赘述。&lt;/p&gt;
&lt;p&gt;对于左边界，因为栈是单调递增的，新的栈顶元素下标&lt;code&gt;stack[len(stack)-1]&lt;/code&gt;就是离它最近且比他小的柱子，符合要求。面对&lt;code&gt;[1, 6, 3, 6]&lt;/code&gt;这种类似凹字也能处理，因为3把6pop后，虽然看着少了一个数变成了&lt;code&gt;[1, 3, 6]&lt;/code&gt;，但是&lt;code&gt;stack&lt;/code&gt;上对应的&lt;code&gt;index&lt;/code&gt;是不变的，&lt;code&gt;index&lt;/code&gt;是从0~4，包括了之前被弹出的距离的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果就是很极端，一直增，遇不到更小的柱子怎么办？&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​	在前后都加上0，ai叫这为哨兵。&lt;/p&gt;
&lt;p&gt;​	尾部的0就是做个保底，避免到边界了都没有遇到更小的柱子的情况。&lt;/p&gt;
&lt;p&gt;​	头部的0就是作为左边界的保底，保证了 &lt;code&gt;leftIndex&lt;/code&gt; 永远能取到一个合法的下标，并且计算出来	的宽度 &lt;code&gt;rightIndex - leftIndex - 1&lt;/code&gt; 绝对正确&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func largestRectangleArea(heights []int) int {
    newheights := make([]int, len(heights)+2)
    copy(newheights[1:], heights)
    stack := make([]int, 0)
    maxArea := 0

    for i, v := range newheights {
        for len(stack) &amp;gt; 0 &amp;amp;&amp;amp; v &amp;lt; newheights[stack[len(stack)-1]] {
            popindex := stack[len(stack)-1]
            height := newheights[popindex]
            stack = stack[:len(stack)-1]

            leftindex := stack[len(stack)-1]
            maxArea = max(maxArea, height*(i-leftindex-1))
        }
        stack = append(stack, i)
    }
    return maxArea
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>力扣算法部分的一些笔记</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%9B%E6%89%A3%E7%AE%97%E6%B3%95%E9%83%A8%E5%88%86%E7%9A%84%E4%B8%80%E4%BA%9B%E7%AC%94%E8%AE%B0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8A%9B%E6%89%A3%E7%AE%97%E6%B3%95%E9%83%A8%E5%88%86%E7%9A%84%E4%B8%80%E4%BA%9B%E7%AC%94%E8%AE%B0/</guid><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;双指针主要分为三大门派&lt;/p&gt;
&lt;h4&gt;1. 对撞指针（左右指针）&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;适用场景&lt;/strong&gt;：主要用于&lt;strong&gt;有序数组&lt;/strong&gt;或&lt;strong&gt;字符串&lt;/strong&gt;。常见于查找两数之和、反转字符串、判断回文串、以及像“盛最多水的容器”这种寻找边界极值的问题。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func collisionPointers(nums []int) {
    left := 0
    right := len(nums) - 1

    for left &amp;lt; right { // 根据题意，有时可能是 left &amp;lt;= right
        // 1. 计算当前左右指针组合的状态/结果
        // ...

        // 2. 根据状态决定移动哪个指针
        if /* 需要更大的值 */ {
            left++
        } else if /* 需要更小的值 */ {
            right--
        } else {
            // 找到目标，执行后续逻辑（如记录结果、去重或退出）
            // left++
            // right--
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. 快慢指针&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：处理链表问题（找中点、判断环）、数组原地去重、移除/移动特定元素（如“移动零”）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func fastSlowPointers(nums []int) int {
    slow := 0
    
    for fast := 0; fast &amp;lt; len(nums); fast++ {
        if /* 满足特定条件，需要保留当前 fast 指向的元素 */ {
            // 将 fast 的值赋给 slow（或进行交换）
            nums[slow] = nums[fast]
            slow++ // slow 推进，准备接收下一个有效元素
        }
    }
    // 返回有效元素的长度或最终 slow 的位置
    return slow
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. 同向指针(在下面滑动窗口说明)&lt;/h4&gt;
&lt;hr /&gt;
&lt;h3&gt;滑动窗口&lt;/h3&gt;
&lt;h4&gt;适用场景： &lt;strong&gt;“连续子数组/子串”&lt;/strong&gt; + 最值/满足条件&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;像「最大/最长」、「最小/最短」、「刚好满足某个条件（如和为 K，包含特定字符等）」&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;如果是“子序列”(Subsequence)，通常不用滑动窗口，因为子序列不要求连续。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;注意是否有负数，如果数组包含负数，滑动窗口通常会失效（因为窗口扩大时和不一定增加）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;滑动窗口主要分为两类：&lt;strong&gt;可变窗口&lt;/strong&gt;（求最长/最短）和&lt;strong&gt;固定窗口&lt;/strong&gt;。&lt;/p&gt;
&lt;h4&gt;1. 可变窗口（最通用）&lt;/h4&gt;
&lt;p&gt;核心思想：&lt;code&gt;right&lt;/code&gt; 主动扩张探索，&lt;code&gt;left&lt;/code&gt; 被动收缩调整。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func slidingWindowVariable(s string) int {
    // 1. 定义数据结构维护窗口内的状态 (通常是 map, slice, 计数器等)
    window := make(map[byte]int)
    left, right := 0, 0
    res := 0 // 或者 math.MaxInt32，取决于求最长还是最短

    for right &amp;lt; len(s) {
        // 2. 将 s[right] 加入窗口，更新状态
        c := s[right]
        window[c]++
        
        // 3. 判断当前窗口状态是否触发了“收缩”条件
        for /* 满足收缩条件 (例如窗口内出现了重复字符，或者和超出了限制) */ {
            // (可选) 在此处更新求【最短】子串的答案
            
            // 4. 准备将 s[left] 移出窗口，更新状态
            d := s[left]
            window[d]--
            left++ // left 右移，窗口收缩
        }
        
        // 5. 在此处更新求【最长】子串的答案 (因为此时窗口一定满足条件)
        // res = max(res, right - left + 1)
        
        right++ // right 右移，窗口继续扩张
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. 固定窗口&lt;/h4&gt;
&lt;p&gt;核心思想：窗口大小恒定为 k，每次 &lt;code&gt;right&lt;/code&gt; 进一个，&lt;code&gt;left&lt;/code&gt; 必须出一个。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func slidingWindowFixed(nums []int, k int) int {
    left, right := 0, 0
    // 定义状态变量...

    for right &amp;lt; len(nums) {
        // 1. 将 nums[right] 加入窗口，更新状态
        
        // 2. 如果窗口长度达到 k，说明窗口已经成型
        if right - left + 1 == k {
            // 3. 记录或更新答案
            
            // 4. 将 nums[left] 移出窗口，为下一个新元素腾位置
            left++
        }
        right++
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;前缀和&lt;/h3&gt;
&lt;h4&gt;适用场景：&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;“连续子数组” + 求和/积&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;区间查询&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[i, j] 内的元素之和，就是两个连续子数组相减&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;连续子数组的“特定数学关系”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;像子数组和等于 K...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意&lt;/p&gt;
&lt;p&gt;为了避免处理边界条件&lt;/p&gt;
&lt;p&gt;➕：在最前面补一个 0，即前缀和数组的长度为原数组长度 + 1&lt;/p&gt;
&lt;p&gt;✖️：令第一个为1&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;回溯&lt;/h3&gt;
&lt;hr /&gt;
&lt;h3&gt;二分查找&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;本质：&lt;/strong&gt; 二分查找的本质&lt;strong&gt;不是“全局有序”，而是“两段性”&lt;/strong&gt;。只要能找到一个判断条件，将当前的搜索空间一分为二（一半满足条件，另一半必定不满足），就可以使用二分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;时间复杂度：&lt;/strong&gt; O(log n)。&lt;/p&gt;
&lt;p&gt;根据题型特点，二分查找主要分为以下四种场景：&lt;/p&gt;
&lt;h4&gt;1. 标准精确查找&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 数组全局有序，且元素不重复。要求寻找某个确切的 &lt;code&gt;target&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 寻找左右边界&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 数组全局有序，但&lt;strong&gt;包含重复元素&lt;/strong&gt;。要求寻找 &lt;code&gt;target&lt;/code&gt; 第一次出现（左边界）或最后一次出现（右边界）的位置。（如 LeetCode 34）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;特征：&lt;/strong&gt; 找到 &lt;code&gt;target&lt;/code&gt; 时&lt;strong&gt;不停手&lt;/strong&gt;，而是记录当前位置，并强行收缩另一边的区间，继续向目标边界逼近。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;func binarySearchTemplate1(nums []int, target int) int {
    left, right := 0, len(nums)-1
    // 可选：ans := -1 // 如果是找边界/找极值，用外部变量记录最近一次符合条件的答案

    for left &amp;lt;= right {
        mid := left + (right - left)/2

        if nums[mid] == target {
            return mid 
            // 如果是找左边界：ans = mid; right = mid - 1
            // 如果是找右边界：ans = mid; left = mid + 1
        } else if nums[mid] &amp;lt; target {
            left = mid + 1 // target 在右侧，砍掉左半边
        } else {
            right = mid - 1 // target 在左侧，砍掉右半边
        }
    }
    
    return -1 // 或 return ans
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. 寻找极值（非全局有序）&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用场景：&lt;/strong&gt; 数组“局部有序”（如旋转数组）或者存在“高低起伏”（如寻找峰值）。（如 LeetCode 153、33）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;特征：&lt;/strong&gt; 通常没有明确的 &lt;code&gt;target&lt;/code&gt; 来匹配，而是通过比较 &lt;code&gt;nums[mid]&lt;/code&gt; 与 &lt;code&gt;nums[left]&lt;/code&gt; 或 &lt;code&gt;nums[right]&lt;/code&gt; 的相对大小，判断出哪里发生了“断层”或“转折”，从而决定收缩方向。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;func binarySearchTemplate2(nums []int) int {
    left, right := 0, len(nums)-1

    // 注意：这里绝对不能写等号，否则在某些收缩逻辑下必死循环
    for left &amp;lt; right {
        mid := left + (right - left)/2

        if nums[mid] &amp;lt; nums[right] { 
            // 举例：判断条件满足，说明右半边是平稳上坡，极值不可能在右边。
            // 但 mid 本身可能是极值，绝不能踢掉！
            right = mid 
        } else {
            // 举例：发生了断层跌落，极值必定在 mid 右侧的悬崖下。
            // mid 本身处于悬崖上方，已被洗脱嫌疑，果断跨过！
            left = mid + 1 
        }
    }
    
    // 循环结束时，left 和 right 撞在一起，就是那个唯一的极值
    return nums[left] 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;贪心算法&lt;/h3&gt;
&lt;h4&gt;1. 基础匹配&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：《分发饼干》(455)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术动作&lt;/strong&gt;：双数组排序 + 双指针单向匹配。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 覆盖范围&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：《跳跃游戏 I/II》(55, 45)、《划分字母区间》(763)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;特征&lt;/strong&gt;：别管每一步怎么跳，死死盯住“最远能覆盖到哪”。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;技术动作&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;维护一个动态的 &lt;code&gt;maxReach&lt;/code&gt;（未来最远潜力）和一个 &lt;code&gt;currentEnd&lt;/code&gt;（当前这一跳的边界）。&lt;/li&gt;
&lt;li&gt;遍历时不断扩张 &lt;code&gt;maxReach&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核心触发器&lt;/strong&gt;：当 &lt;code&gt;i == currentEnd&lt;/code&gt; 时，被迫结算（跳跃次数+1，或切分出一段区间），并将边界更新为新的 &lt;code&gt;maxReach&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 区间调度&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;适用题目&lt;/strong&gt;：《合并区间》(56)、《无重叠区间》(435)、《用最少数量的箭引爆气球》(452)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通关口诀&lt;/strong&gt;：求合并看左边界，求消减看右边界&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术动作&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;合并类（如 56 题）&lt;/strong&gt;：按&lt;strong&gt;左边界&lt;/strong&gt;排序。贪心策略是“能吞就吞”，右边界不断取最大值 &lt;code&gt;max(last[1], curr[1])&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消减/射箭类（如 435, 452 题）&lt;/strong&gt;：强烈建议按&lt;strong&gt;右边界&lt;/strong&gt;排序！这是降维打击。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;右边界排序的极简逻辑&lt;/strong&gt;：谁结束得早，就先安排谁。只要发生重叠（&lt;code&gt;left &amp;lt;= end&lt;/code&gt;），后来的那个必定是个累赘，直接干掉（&lt;code&gt;count++&lt;/code&gt;）；不重叠才更新安全边界 &lt;code&gt;end&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;/h3&gt;
</content:encoded></item><item><title>LeetCode-153. 寻找旋转排序数组中的最小值</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-153-%E5%AF%BB%E6%89%BE%E6%97%8B%E8%BD%AC%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%9C%80%E5%B0%8F%E5%80%BC/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-153-%E5%AF%BB%E6%89%BE%E6%97%8B%E8%BD%AC%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%9C%80%E5%B0%8F%E5%80%BC/</guid><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二分查找&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/&quot;&gt;&lt;strong&gt;153. 寻找旋转排序数组中的最小值&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;已知一个长度为 &lt;code&gt;n&lt;/code&gt; 的数组，预先按照升序排列，经由 &lt;code&gt;1&lt;/code&gt; 到 &lt;code&gt;n&lt;/code&gt; 次 &lt;strong&gt;旋转&lt;/strong&gt; 后，得到输入数组。例如，原数组 &lt;code&gt;nums = [0,1,2,4,5,6,7]&lt;/code&gt; 在变化后可能得到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若旋转 &lt;code&gt;4&lt;/code&gt; 次，则可以得到 &lt;code&gt;[4,5,6,7,0,1,2]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;若旋转 &lt;code&gt;7&lt;/code&gt; 次，则可以得到 &lt;code&gt;[0,1,2,4,5,6,7]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意，数组 &lt;code&gt;[a[0], a[1], a[2], ..., a[n-1]]&lt;/code&gt; &lt;strong&gt;旋转一次&lt;/strong&gt; 的结果为数组 &lt;code&gt;[a[n-1], a[0], a[1], a[2], ..., a[n-2]]&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;给你一个元素值 &lt;strong&gt;互不相同&lt;/strong&gt; 的数组 &lt;code&gt;nums&lt;/code&gt; ，它原来是一个升序排列的数组，并按上述情形进行了多次旋转。请你找出并返回数组中的 &lt;strong&gt;最小元素&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;你必须设计一个时间复杂度为 &lt;code&gt;O(log n)&lt;/code&gt; 的算法解决此问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [3,4,5,1,2]
输出：1
解释：原数组为 [1,2,3,4,5] ，旋转 3 次得到输入数组。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [4,5,6,7,0,1,2]
输出：0
解释：原数组为 [0,1,2,4,5,6,7] ，旋转 4 次得到输入数组。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [11,13,15,17]
输出：11
解释：原数组为 [11,13,15,17] ，旋转 4 次得到输入数组。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是个经典解法，关于它主要有两个令人疑惑的点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;他的输出最小值依靠left，所以他的循环条件是&lt;code&gt;left &amp;lt; right&lt;/code&gt;最终会停留在&lt;code&gt;left = mid = right&lt;/code&gt;的时候，而不是&lt;code&gt; &amp;lt;=&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;因为&lt;code&gt;mid&lt;/code&gt;这个值也有可能是答案，如果是&lt;code&gt;right = mid-1&lt;/code&gt;就会把这个值排除了，与平常求&lt;code&gt;target&lt;/code&gt;是已经与&lt;code&gt;target&lt;/code&gt;比较后被排除后才&lt;code&gt;right = mid-1&lt;/code&gt;，不是一个情况&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func findMin(nums []int) int {
    left, right := 0, len(nums)-1
    
    for left &amp;lt; right {
        mid := left + (right - left)/2
        
        if nums[mid] &amp;lt; nums[right] {
            right = mid 
        } else {
            left = mid + 1
        }
    }
    return nums[left] 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;手撕的思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;看到题目只对时间复杂度做了要求，就引入num储存最小值&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func findMin(nums []int) int {
    left, right := 0, len(nums)-1
    num := 5001

    for left &amp;lt;= right {
        mid := left + (right - left)/2

        if nums[left] &amp;lt;= nums[mid] {
            num = min(num, nums[left])
            left = mid + 1
        }else {
            num = min(num, nums[mid])
            right = mid - 1
        }
    }
    return num
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-33. 搜索旋转排序数组</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-33-%E6%90%9C%E7%B4%A2%E6%97%8B%E8%BD%AC%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-33-%E6%90%9C%E7%B4%A2%E6%97%8B%E8%BD%AC%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84/</guid><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二分查找&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/search-in-rotated-sorted-array/&quot;&gt;&lt;strong&gt;33. 搜索旋转排序数组&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;整数数组 &lt;code&gt;nums&lt;/code&gt; 按升序排列，数组中的值 &lt;strong&gt;互不相同&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;在传递给函数之前，&lt;code&gt;nums&lt;/code&gt; 在预先未知的某个下标 &lt;code&gt;k&lt;/code&gt;（&lt;code&gt;0 &amp;lt;= k &amp;lt; nums.length&lt;/code&gt;）上进行了 &lt;strong&gt;向左旋转&lt;/strong&gt;，使数组变为 &lt;code&gt;[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]&lt;/code&gt;（下标 &lt;strong&gt;从 0 开始&lt;/strong&gt; 计数）。例如， &lt;code&gt;[0,1,2,4,5,6,7]&lt;/code&gt; 下标 &lt;code&gt;3&lt;/code&gt; 上向左旋转后可能变为 &lt;code&gt;[4,5,6,7,0,1,2]&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;给你 &lt;strong&gt;旋转后&lt;/strong&gt; 的数组 &lt;code&gt;nums&lt;/code&gt; 和一个整数 &lt;code&gt;target&lt;/code&gt; ，如果 &lt;code&gt;nums&lt;/code&gt; 中存在这个目标值 &lt;code&gt;target&lt;/code&gt; ，则返回它的下标，否则返回 &lt;code&gt;-1&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;你必须设计一个时间复杂度为 &lt;code&gt;O(log n)&lt;/code&gt; 的算法解决此问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [4,5,6,7,0,1,2], target = 0
输出：4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [4,5,6,7,0,1,2], target = 3
输出：-1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1], target = 0
输出：-1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题的难点我认为是在强调时间复杂度为&lt;code&gt;O(log n)&lt;/code&gt;，必须用二分查找的情况下，普通数组全局有序不同的是，这里是部分有序&lt;/p&gt;
&lt;p&gt;所以我们要在原来的基础上多一个步骤，1. 先判断哪边是有序的，2. 其次才与&lt;code&gt;target&lt;/code&gt;比较进行&lt;code&gt;left&lt;/code&gt;或&lt;code&gt;right&lt;/code&gt;的移动&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func search(nums []int, target int) int {
    left, right := 0, len(nums)-1

    for left &amp;lt;= right {
        mid := left + (right - left)/2

        if nums[mid] == target {
            return mid
        }

        if nums[left] &amp;lt; nums[mid] {
            if nums[left] &amp;lt;= target &amp;amp;&amp;amp; target &amp;lt; nums[mid] {
                right = mid - 1
            }else {
                left = mid + 1
            }
        }else {
            if target &amp;gt; nums[mid] &amp;amp;&amp;amp; target &amp;lt;= nums[right] {
                left = mid + 1  
            } else {
                right = mid - 1
            }
        }
    }
    return -1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;时间复杂度为O(nlog n)的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;虽然这个思路简单，但时间复杂度不论是&lt;code&gt;for&lt;/code&gt;还是 &lt;code&gt;sort.Ints(nums)&lt;/code&gt;都超了好多&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;for&lt;/code&gt; 循环遍历数组，时间复杂度是 O(n)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用 &lt;code&gt;sort.Ints(nums)&lt;/code&gt;排序，时间复杂度是 O(n log n)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;二分查找： 时间复杂度是 O(log n)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func search(nums []int, target int) int {
    index := 0
    for i := 1; i &amp;lt; len(nums); i++ {
        if nums[i] &amp;lt; nums[i-1] {
            index = i
            break
        }
    }

    sort.Ints(nums)
    left, right := 0, len(nums)-1
    for left &amp;lt;= right {
        mid := left + (right - left)/2

        if nums[mid] == target {
            return (mid + index)%len(nums)
        }else if nums[mid] &amp;lt; target {
            left = mid + 1
        }else {
            right = mid - 1
        }
    }
    return -1
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-34. 在排序数组中查找元素的第一个和最后一个位置</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-34-%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%85%83%E7%B4%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%92%8C%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-34-%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%85%83%E7%B4%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%92%8C%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE/</guid><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二分查找&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/&quot;&gt;&lt;strong&gt;34. 在排序数组中查找元素的第一个和最后一个位置&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个按照非递减顺序排列的整数数组 &lt;code&gt;nums&lt;/code&gt;，和一个目标值 &lt;code&gt;target&lt;/code&gt;。请你找出给定目标值在数组中的开始位置和结束位置。&lt;/p&gt;
&lt;p&gt;如果数组中不存在目标值 &lt;code&gt;target&lt;/code&gt;，返回 &lt;code&gt;[-1, -1]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;你必须设计并实现时间复杂度为 &lt;code&gt;O(log n)&lt;/code&gt; 的算法解决此问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [5,7,7,8,8,10], target = 8
输出：[3,4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [5,7,7,8,8,10], target = 6
输出：[-1,-1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [], target = 0
输出：[-1,-1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题与前面只找一个数不同，这里需要寻找到第一个和最后一个数&lt;/p&gt;
&lt;p&gt;其实由于&lt;code&gt;for left &amp;lt;= right&lt;/code&gt;的循环结构，具备不断查找的功能，之前只寻找一个数的问题局限了我们的思维，只需要在找到&lt;code&gt;target&lt;/code&gt;后，继续执行找到左和右边界即可&lt;/p&gt;
&lt;p&gt;所以，我们只需要执行两次二分查找即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func searchRange(nums []int, target int) []int {
    first := findBound(nums, target, true)
    if first == -1 {
        return []int{-1, -1}
    }

    last := findBound(nums, target, false)

    return []int{first, last}
}

func findBound (nums []int, target int , isFirst bool) int {
    left, right := 0, len(nums)-1  
    bound := -1

    for left &amp;lt;= right {
        mid := left + (right - left)/2

        if nums[mid] == target {
            bound = mid
            if isFirst {
                right = mid - 1
            }else {
                left = mid + 1
            }
        }else if nums[mid] &amp;lt; target {
            left = mid + 1
        }else {
            right = mid - 1 
        }
    }
    return bound
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;时间复杂度为O(n)的思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;很直接的在查到对应的值后，向左和右用循环找到初始和最后的位置，但时间复杂度为&lt;code&gt;O(n)&lt;/code&gt;与题目要求的&lt;code&gt;O(log n)&lt;/code&gt; 不符&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func searchRange(nums []int, target int) []int {
    if len(nums) == 0 {
        return []int{-1, -1}
    }

    left, right := 0, len(nums)-1
    var mid int

    for left &amp;lt;= right {
        mid = left + (right - left)/2

        if nums[mid] == target {
            ans := mid 
            for mid-1 &amp;gt;= 0 &amp;amp;&amp;amp; nums[mid-1] == target {
                mid--
            }
            for ans+1 &amp;lt; len(nums) &amp;amp;&amp;amp; nums[ans+1] == target {
                ans++
            }
            return []int{mid, ans}
        }else if nums[mid] &amp;lt; target {
            left = mid + 1
        }else {
            right = mid - 1
        }
    }
    return []int{-1, -1}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-35. 搜索插入位置</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-35-%E6%90%9C%E7%B4%A2%E6%8F%92%E5%85%A5%E4%BD%8D%E7%BD%AE/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-35-%E6%90%9C%E7%B4%A2%E6%8F%92%E5%85%A5%E4%BD%8D%E7%BD%AE/</guid><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二分查找&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/search-insert-position/&quot;&gt;&lt;strong&gt;35. 搜索插入位置&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个排序数组和一个目标值，在数组中找到目标值，并返回其索引。如果目标值不存在于数组中，返回它将会被按顺序插入的位置。&lt;/p&gt;
&lt;p&gt;请必须使用时间复杂度为 &lt;code&gt;O(log n)&lt;/code&gt; 的算法。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [1,3,5,6], target = 5
输出: 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [1,3,5,6], target = 2
输出: 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [1,3,5,6], target = 7
输出: 4
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这题我感觉唯一需要思考的就是不存在时的插入位置&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;数组中插入位置有三种可能：最左侧和数列中间和最右侧，最左侧和最右侧很容易推倒出来可以&lt;code&gt;return left&lt;/code&gt;解决，就需要考虑数列中间的情况&lt;/li&gt;
&lt;li&gt;由于&lt;code&gt;left &amp;lt;= right&lt;/code&gt;和&lt;code&gt;mid+1&lt;/code&gt;，所以最后&lt;code&gt;left&lt;/code&gt;和&lt;code&gt;right&lt;/code&gt;和&lt;code&gt;mid&lt;/code&gt;必然重合，且&lt;code&gt;mid&lt;/code&gt;一定在他的左侧或右侧，距离为1&lt;/li&gt;
&lt;li&gt;所以最后无论是&lt;code&gt;target &amp;lt; mid&lt;/code&gt;导致&lt;code&gt;right - 1&lt;/code&gt;，还是&lt;code&gt;target &amp;gt; mid&lt;/code&gt;导致&lt;code&gt;left + 1&lt;/code&gt;，left必然是target的插入位置，所以最后&lt;code&gt;return left&lt;/code&gt;即可&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func searchInsert(nums []int, target int) int {
    left, right := 0, len(nums)-1
    mid := 0
    for left &amp;lt;= right {
        mid = left + (right - left)/2

        if nums[mid] == target {
            return mid
        }else if nums[mid] &amp;lt; target {
            left = mid + 1
        }else {
            right = mid - 1
        }
    }
    return left
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-4. 寻找两个正序数组的中位数</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-4-%E5%AF%BB%E6%89%BE%E4%B8%A4%E4%B8%AA%E6%AD%A3%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E4%B8%AD%E4%BD%8D%E6%95%B0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-4-%E5%AF%BB%E6%89%BE%E4%B8%A4%E4%B8%AA%E6%AD%A3%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E4%B8%AD%E4%BD%8D%E6%95%B0/</guid><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二分查找&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/median-of-two-sorted-arrays/&quot;&gt;&lt;strong&gt;4. 寻找两个正序数组的中位数&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个大小分别为 &lt;code&gt;m&lt;/code&gt; 和 &lt;code&gt;n&lt;/code&gt; 的正序（从小到大）数组 &lt;code&gt;nums1&lt;/code&gt; 和 &lt;code&gt;nums2&lt;/code&gt;。请你找出并返回这两个正序数组的 &lt;strong&gt;中位数&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;算法的时间复杂度应该为 &lt;code&gt;O(log (m+n))&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums1 = [1,3], nums2 = [2]
输出：2.00000
解释：合并数组 = [1,2,3] ，中位数 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums1 = [1,2], nums2 = [3,4]
输出：2.50000
解释：合并数组 = [1,2,3,4] ，中位数 (2 + 3) / 2 = 2.5
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这一题我认为最主要的难点就是在时间复杂度&lt;code&gt;O(log (m+n))&lt;/code&gt;，要求二分查找的情况下，如何在 A 里画一条分割线，在 B 里画一条分割线使得：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;左边的元素总个数&lt;/strong&gt; 等于 &lt;strong&gt;右边的元素总个数&lt;/strong&gt;（如果是奇数，让左边多一个）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;左半边所有的数&lt;/strong&gt; 都要 小于 &lt;strong&gt;右半边所有的数&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因为 A 和 B 本身就是有序的，所以 A 左边的数本来就 小于 右边的数。我们只需要保证的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;A 左边最大的数 &amp;lt;= B 右边最小的数&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;B 左边最大的数 &amp;lt;= A 右边最小的数&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，我们可以像提线木偶般，在短的那个数组进行二分，为了保证左右元素总数各占一半，B 中的切分位置 就自动确定了，最后检查十字交叉条件即可(知道了思路，还是挺简单的)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
    if  len(nums1) &amp;gt; len(nums2) {
        return findMedianSortedArrays(nums2, nums1)
    }

    m, n := len(nums1), len(nums2)
    left, right := 0, m
    totalLeft := (m + n + 1)/2

    for left &amp;lt;= right {
        i := left + (right - left)/2
        j := totalLeft - i

        nums1LeftMax := math.MinInt
        if i &amp;gt; 0 {
            nums1LeftMax = nums1[i-1]
        }

        nums1RightMin := math.MaxInt
        if i &amp;lt; m {
            nums1RightMin = nums1[i]
        }
        
        nums2LeftMax  := math.MinInt
        if j &amp;gt; 0 {
            nums2LeftMax = nums2[j-1]
        }

        nums2RightMin := math.MaxInt
        if j &amp;lt; n {
            nums2RightMin = nums2[j]
        }

        if nums1LeftMax &amp;lt;= nums2RightMin &amp;amp;&amp;amp; nums2LeftMax &amp;lt;= nums1RightMin {
            if (n + m) % 2 == 1 {
                return float64(max(nums1LeftMax, nums2LeftMax))
            }else {
                return float64(max(nums1LeftMax, nums2LeftMax) + min(nums1RightMin,nums2RightMin)) / 2.0
            }
        }else if nums1LeftMax &amp;gt; nums2RightMin {
            right = i - 1
        }else {
            left = i + 1
        }
    }
    return 0.0
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-74. 搜索二维矩阵</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-74-%E6%90%9C%E7%B4%A2%E4%BA%8C%E7%BB%B4%E7%9F%A9%E9%98%B5/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/leetcode-74-%E6%90%9C%E7%B4%A2%E4%BA%8C%E7%BB%B4%E7%9F%A9%E9%98%B5/</guid><pubDate>Sat, 11 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二分查找&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/search-a-2d-matrix/&quot;&gt;&lt;strong&gt;74. 搜索二维矩阵&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个满足下述两条属性的 &lt;code&gt;m x n&lt;/code&gt; 整数矩阵：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每行中的整数从左到右按非严格递增顺序排列。&lt;/li&gt;
&lt;li&gt;每行的第一个整数大于前一行的最后一个整数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;给你一个整数 &lt;code&gt;target&lt;/code&gt; ，如果 &lt;code&gt;target&lt;/code&gt; 在矩阵中，返回 &lt;code&gt;true&lt;/code&gt; ；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/05/mat.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2020/11/25/mat2.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;手撕&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路: 这题可以看作长度为 m*n 的数组，只需要把&lt;code&gt;mid&lt;/code&gt;转换为对应矩阵的&lt;code&gt;row&lt;/code&gt;和&lt;code&gt;col&lt;/code&gt;即可，其他与 &lt;a href=&quot;https://leetcode.cn/problems/search-insert-position/&quot;&gt;&lt;strong&gt;35. 搜索插入位置&lt;/strong&gt;&lt;/a&gt; 类似&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func searchMatrix(matrix [][]int, target int) bool {
    m, n := len(matrix), len(matrix[0])
    left, right := 0, m*n-1
    var mid, row, col int

    for left &amp;lt;= right {
        mid = left + (right - left)/2
        row = mid / n
        col = mid % n

        if matrix[row][col] == target {
            return true
        }else if matrix[row][col] &amp;lt; target {
            left = mid + 1
        }else {
            right = mid - 1
        }
    }
    return false
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-131. 分割回文串</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-131-%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-131-%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2/</guid><pubDate>Thu, 09 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/palindrome-partitioning/&quot;&gt;&lt;strong&gt;131. 分割回文串&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个字符串 &lt;code&gt;s&lt;/code&gt;，请你将 &lt;code&gt;s&lt;/code&gt; 分割成一些 子串，使每个子串都是 &lt;strong&gt;回文串&lt;/strong&gt; 。返回 &lt;code&gt;s&lt;/code&gt; 所有可能的分割方案。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;aab&quot;
输出：[[&quot;a&quot;,&quot;a&quot;,&quot;b&quot;],[&quot;aa&quot;,&quot;b&quot;]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;a&quot;
输出：[[&quot;a&quot;]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;看完代码后，思路感觉挺简单的...看到题干应该知道需要完成一个判断回文串的函数用于剪枝，然后就感觉是正常判断和&lt;code&gt;continue&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func partition(s string) [][]string {
    res := [][]string{}
    path := []string{}

    var backtrack func(start int)
    backtrack = func(start int) {
        if start == len(s) {
            temp := make([]string, len(path))
            copy(temp, path)
            res = append(res,temp)
        }

        for i := start; i &amp;lt; len(s); i++ {
            if isPalindrome(s,start,i) {
                path = append(path, s[start:i+1])
                backtrack(i+1)
                path = path[:len(path)-1]
            }else {
                continue
            }
        }
    }

    backtrack(0)
    return res
}

func isPalindrome(s string, left, right int) bool {
    for left &amp;lt; right {
        if s[left] != s[right] {
            return false
        }
        left++
        right--
    }
    return true
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-51. N 皇后</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-51-n-%E7%9A%87%E5%90%8E/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-51-n-%E7%9A%87%E5%90%8E/</guid><pubDate>Mon, 06 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/n-queens/&quot;&gt;&lt;strong&gt;51. N 皇后&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;按照国际象棋的规则，皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;n 皇后问题&lt;/strong&gt; 研究的是如何将 &lt;code&gt;n&lt;/code&gt; 个皇后放置在 &lt;code&gt;n×n&lt;/code&gt; 的棋盘上，并且使皇后彼此之间不能相互攻击。&lt;/p&gt;
&lt;p&gt;给你一个整数 &lt;code&gt;n&lt;/code&gt; ，返回所有不同的 &lt;strong&gt;n 皇后问题&lt;/strong&gt; 的解决方案。&lt;/p&gt;
&lt;p&gt;每一种解法包含一个不同的 &lt;strong&gt;n 皇后问题&lt;/strong&gt; 的棋子放置方案，该方案中 &lt;code&gt;&apos;Q&apos;&lt;/code&gt; 和 &lt;code&gt;&apos;.&apos;&lt;/code&gt; 分别代表了皇后和空位。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/11/13/queens.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 4
输出：[[&quot;.Q..&quot;,&quot;...Q&quot;,&quot;Q...&quot;,&quot;..Q.&quot;],[&quot;..Q.&quot;,&quot;Q...&quot;,&quot;...Q&quot;,&quot;.Q..&quot;]]
解释：如上图所示，4 皇后问题存在两个不同的解法。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 1
输出：[[&quot;Q&quot;]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这道题的难点我认为是这两个1.如何在剪枝中去掉行列和两个对角线的重复 2.避免思维惯性，用&lt;code&gt;board&lt;/code&gt;储存数据而非&lt;code&gt;path&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同行&lt;/strong&gt;：因为我们每次递归都会走向下一行（&lt;code&gt;row + 1&lt;/code&gt;），天生就保证了每行只有一个皇后。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同列&lt;/strong&gt;：需要一个 &lt;code&gt;cols&lt;/code&gt; 数组来记录哪一列已经被占用了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;主对角线&lt;/strong&gt;：它们的 &lt;strong&gt;&lt;code&gt;row - col&lt;/code&gt; 的差值是固定相等的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;副对角线&lt;/strong&gt;：同理，它们的 &lt;strong&gt;&lt;code&gt;row + col&lt;/code&gt; 的和是固定相等的&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func solveNQueens(n int) [][]string {
   board := make([][]byte, n)
   res := [][]string{}

   for i := 0; i &amp;lt; n; i++ {
        board[i] = make([]byte, n)
        for j := 0; j &amp;lt; n; j++ {
            board[i][j] = &apos;.&apos;
        }
    }

    cols := make([]bool, n)
    diag1 := make([]bool, 2*n)
    diag2 := make([]bool, 2*n)

    var backtrack func(row int)
    backtrack = func(row int) {
        if row == n {
            temp := make([]string, n)
            for i := 0; i &amp;lt; n; i++ {
                temp[i] = string(board[i])
            }
            res = append(res, temp)
            return
        }

        for col := 0; col &amp;lt; n; col++ {
            d1 := col - row + n
            d2 := col + row

            if cols[col] || diag1[d1] || diag2[d2] {
                continue
            }

            board[row][col] = &apos;Q&apos;
            cols[col] = true
            diag1[d1] = true
            diag2[d2] = true

            backtrack(row+1)

            board[row][col] = &apos;.&apos;
            cols[col] = false
            diag1[d1] = false
            diag2[d2] = false
        }
    }
    
    backtrack(0)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-90. 子集 II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-90-%E5%AD%90%E9%9B%86-ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-90-%E5%AD%90%E9%9B%86-ii/</guid><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/subsets-ii/&quot;&gt;&lt;strong&gt;90. 子集 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，其中可能包含重复元素，请你返回该数组所有可能的 子集（幂集）。&lt;/p&gt;
&lt;p&gt;解集 &lt;strong&gt;不能&lt;/strong&gt; 包含重复的子集。返回的解集中，子集可以按 &lt;strong&gt;任意顺序&lt;/strong&gt; 排列。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,2]
输出：[[],[1],[1,2],[1,2,2],[2],[2,2]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0]
输出：[[],[0]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;手撕&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路:这里很像 &lt;a href=&quot;https://leetcode.cn/problems/permutations-ii/&quot;&gt;&lt;strong&gt;47. 全排列 II&lt;/strong&gt;&lt;/a&gt; 的情况，本身不需要&lt;code&gt;used&lt;/code&gt;，但是需要判断不同的情况，像&lt;code&gt;1 2 2&lt;/code&gt;和&lt;code&gt;1 2&lt;/code&gt;的不同，所以需要判断前面的数是否使用，所以引入used&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func subsetsWithDup(nums []int) [][]int {
    sort.Ints(nums)

    res := [][]int{}
    path := []int{}
    used := make([]bool, len(nums))

    var backtrack func(index int) 
    backtrack = func(index int) {
        res = append(res, append([]int(nil), path...))     

        for i := index; i &amp;lt; len(nums); i++ {
            if i &amp;gt; 0 &amp;amp;&amp;amp; nums[i] == nums[i-1] &amp;amp;&amp;amp; !used[i-1] {
                continue
            }

            path = append(path, nums[i])
            used[i] = true
            backtrack(i+1)
            path = path[:len(path)-1]
            used[i] = false
        }
    }

    backtrack(0)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-22. 括号生成</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-22-%E6%8B%AC%E5%8F%B7%E7%94%9F%E6%88%90/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-22-%E6%8B%AC%E5%8F%B7%E7%94%9F%E6%88%90/</guid><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/generate-parentheses/&quot;&gt;&lt;strong&gt;22. 括号生成&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;数字 &lt;code&gt;n&lt;/code&gt; 代表生成括号的对数，请你设计一个函数，用于能够生成所有可能的并且 &lt;strong&gt;有效的&lt;/strong&gt; 括号组合。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 3
输出：[&quot;((()))&quot;,&quot;(()())&quot;,&quot;(())()&quot;,&quot;()(())&quot;,&quot;()()()&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 1
输出：[&quot;()&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func generateParenthesis(n int) []string {
    res := []string{}
    path := []byte{}

    var backtrack func(left, right int)
    backtrack = func(left, right int) {
        if len(path) == n * 2 {
            res = append(res, string(path))
            return
        }

        if left &amp;lt; n {
            path = append(path, &apos;(&apos;)
            backtrack(left+1,right)
            path = path[:len(path)-1]
        }

        if right &amp;lt; left {
            path = append(path, &apos;)&apos;)
            backtrack(left,right+1)
            path = path[:len(path)-1]
        }
    }

    backtrack(0,0)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-47. 全排列 II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-47-%E5%85%A8%E6%8E%92%E5%88%97-ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-47-%E5%85%A8%E6%8E%92%E5%88%97-ii/</guid><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/permutations-ii/&quot;&gt;&lt;strong&gt;47. 全排列 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个可包含重复数字的序列 &lt;code&gt;nums&lt;/code&gt; ，&lt;em&gt;&lt;strong&gt;按任意顺序&lt;/strong&gt;&lt;/em&gt; 返回所有不重复的全排列。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,1,2]
输出：
[[1,1,2],
 [1,2,1],
 [2,1,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,3]
输出：[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路:相较于 &lt;a href=&quot;https://leetcode.cn/problems/permutations/&quot;&gt;&lt;strong&gt;46. 全排列&lt;/strong&gt;&lt;/a&gt; 这里多了一步就是如何判断重复，通过&lt;code&gt;if i &amp;gt; 0 &amp;amp;&amp;amp; nums[i] == nums[i-1] &amp;amp;&amp;amp; !used[i-1]&lt;/code&gt;这个语句，能避免重复的情况直接跳过&lt;/p&gt;
&lt;p&gt;唯一需要注意的是&lt;code&gt;i &amp;gt; 0 &amp;amp;&amp;amp; nums[i] == nums[i-1]&lt;/code&gt;顺序不要写反了，不然会执行错误&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func permuteUnique(nums []int) [][]int {
    sort.Ints(nums)

    res := [][]int{}
    path := []int{}
    used := make([]bool, len(nums))

    var backtrack func()
    backtrack = func() {
        if len(path) == len(nums) {
            res = append(res, append([]int(nil), path...))
        }

        for i := 0; i &amp;lt; len(nums); i++ {
            if used[i] {
                continue
            }

            if i &amp;gt; 0 &amp;amp;&amp;amp; nums[i] == nums[i-1] &amp;amp;&amp;amp; !used[i-1] {
                continue
            }

            path = append(path, nums[i])
            used[i] = true
            backtrack()
            path = path[:len(path)-1]
            used[i] = false
        }
    }

    backtrack()
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-79. 单词搜索</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-79-%E5%8D%95%E8%AF%8D%E6%90%9C%E7%B4%A2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-79-%E5%8D%95%E8%AF%8D%E6%90%9C%E7%B4%A2/</guid><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/word-search/&quot;&gt;&lt;strong&gt;79. 单词搜索&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个 &lt;code&gt;m x n&lt;/code&gt; 二维字符网格 &lt;code&gt;board&lt;/code&gt; 和一个字符串单词 &lt;code&gt;word&lt;/code&gt; 。如果 &lt;code&gt;word&lt;/code&gt; 存在于网格中，返回 &lt;code&gt;true&lt;/code&gt; ；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;单词必须按照字母顺序，通过相邻的单元格内的字母构成，其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/11/04/word2.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：board = [[&apos;A&apos;,&apos;B&apos;,&apos;C&apos;,&apos;E&apos;],[&apos;S&apos;,&apos;F&apos;,&apos;C&apos;,&apos;S&apos;],[&apos;A&apos;,&apos;D&apos;,&apos;E&apos;,&apos;E&apos;]], word = &quot;ABCCED&quot;
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/11/04/word-1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：board = [[&apos;A&apos;,&apos;B&apos;,&apos;C&apos;,&apos;E&apos;],[&apos;S&apos;,&apos;F&apos;,&apos;C&apos;,&apos;S&apos;],[&apos;A&apos;,&apos;D&apos;,&apos;E&apos;,&apos;E&apos;]], word = &quot;SEE&quot;
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/15/word3.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：board = [[&apos;A&apos;,&apos;B&apos;,&apos;C&apos;,&apos;E&apos;],[&apos;S&apos;,&apos;F&apos;,&apos;C&apos;,&apos;S&apos;],[&apos;A&apos;,&apos;D&apos;,&apos;E&apos;,&apos;E&apos;]], word = &quot;ABCB&quot;
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;感觉这道题是 &lt;a href=&quot;https://leetcode.cn/problems/number-of-islands/&quot;&gt;&lt;strong&gt;200. 岛屿数量&lt;/strong&gt;&lt;/a&gt; 的进阶版，难点就是如何处理四个方向的递归？&lt;/p&gt;
&lt;p&gt;这里就给&lt;code&gt;backtrack&lt;/code&gt;引入了一个&lt;code&gt;bool&lt;/code&gt;返回值，这段代码&lt;code&gt;found := backtrack(row-1, col, index+1) || backtrack(row+1, col, index+1) || backtrack(row, col-1, index+1) || backtrack(row, col+1, index+1)&lt;/code&gt;是点精之笔&lt;/p&gt;
&lt;p&gt;并且这里对数据的存储和处理也是比较有意思的，&lt;code&gt;board[row][col] = &apos;#&apos;&lt;/code&gt;，不需要引入额外的数组，就可以避开这个数&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func exist(board [][]byte, word string) bool {
    m, n := len(board), len(board[0])
    
    var backtrack func(row, col, index int) bool
    backtrack = func(row, col, index int) bool {
        if index == len(word) {
            return true
        }

        if row &amp;lt; 0 || col &amp;lt; 0 || row &amp;gt;= m || col &amp;gt;= n || board[row][col] != word[index] {
            return false
        }
        
        temp := board[row][col]
        board[row][col] = &apos;#&apos;

        found := backtrack(row-1, col, index+1) || backtrack(row+1, col, index+1) || backtrack(row, col-1, index+1) || backtrack(row, col+1, index+1)
        
        board[row][col] = temp
        return found
    }
    
    for i := 0; i &amp;lt; m; i++ {
        for j := 0; j &amp;lt; n; j++ {
            if board[i][j] == word[0] {
                if backtrack(i, j, 0) {
                    return true
                }
            }
        }
    }
    return false
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-17. 电话号码的字母组合</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-17-%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%E7%9A%84%E5%AD%97%E6%AF%8D%E7%BB%84%E5%90%88/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-17-%E7%94%B5%E8%AF%9D%E5%8F%B7%E7%A0%81%E7%9A%84%E5%AD%97%E6%AF%8D%E7%BB%84%E5%90%88/</guid><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/letter-combinations-of-a-phone-number/&quot;&gt;&lt;strong&gt;17. 电话号码的字母组合&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个仅包含数字 &lt;code&gt;2-9&lt;/code&gt; 的字符串，返回所有它能表示的字母组合。答案可以按 &lt;strong&gt;任意顺序&lt;/strong&gt; 返回。&lt;/p&gt;
&lt;p&gt;给出数字到字母的映射如下（与电话按键相同）。注意 1 不对应任何字母。&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://pic.leetcode.cn/1752723054-mfIHZs-image.png&quot; alt=&quot;img&quot; style=&quot;zoom: 25%;&quot; /&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：digits = &quot;23&quot;
输出：[&quot;ad&quot;,&quot;ae&quot;,&quot;af&quot;,&quot;bd&quot;,&quot;be&quot;,&quot;bf&quot;,&quot;cd&quot;,&quot;ce&quot;,&quot;cf&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：digits = &quot;2&quot;
输出：[&quot;a&quot;,&quot;b&quot;,&quot;c&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func letterCombinations(digits string) []string {
    if len(digits) == 0 {
        return nil
    }

    m := []string{&quot;&quot;,&quot;&quot;,&quot;abc&quot;, &quot;def&quot;, &quot;ghi&quot;, &quot;jkl&quot;, &quot;mno&quot;, &quot;pqrs&quot;, &quot;tuv&quot;, &quot;wxyz&quot;}

    res := []string{}
    path:= []byte{}

    var backtrack func(index int)
    backtrack = func(index int) {
        if index == len(digits) {
            res = append(res, string(path))
            return
        }

        digit := digits[index] - &apos;0&apos;
        letters := m[digit]
        for i := 0; i &amp;lt; len(letters); i++ {
            path = append(path, letters[i])
            backtrack(index+1)
            path = path[:len(path)-1]
        }
    }
    
    backtrack(0)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-216. 组合总和 III</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-216-%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C-iii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-216-%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C-iii/</guid><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/combination-sum-iii/&quot;&gt;&lt;strong&gt;216. 组合总和 III&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;找出所有相加之和为 &lt;code&gt;n&lt;/code&gt; 的 &lt;code&gt;k&lt;/code&gt; 个数的组合，且满足下列条件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只使用数字1到9&lt;/li&gt;
&lt;li&gt;每个数字 &lt;strong&gt;最多使用一次&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;返回 &lt;em&gt;所有可能的有效组合的列表&lt;/em&gt; 。该列表不能包含相同的组合两次，组合可以以任何顺序返回。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;**
示例 1:**&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释:
1 + 2 + 6 = 9
1 + 3 + 5 = 9
2 + 3 + 4 = 9
没有其他符合的组合了。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。
在[1,9]范围内使用4个不同的数字，我们可以得到的最小和是1+2+3+4 = 10，因为10 &amp;gt; 1，没有有效的组合。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;手撕&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func combinationSum3(k int, n int) [][]int {
    res := [][]int{}
    path := []int{}

    var end int
    if n &amp;gt; 9 {
        end = 9
    }else {
        end = n
    }

    var sum int
    var backtrack func(int)
    backtrack = func(index int) {
        if len(path) == k {
            if sum == n {
                res = append(res, append([]int(nil), path...))
                return
            }
            return
        }

        for i := index; i &amp;lt;= end; i++ {
            path = append(path, i)
            sum += i
            backtrack(i+1)
            path = path[:len(path)-1]
            sum -= i
        }
    }

    backtrack(1)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;剪枝优化版&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func combinationSum3(k int, n int) [][]int {
    var res [][]int
    var path []int
    var sum int

    var backtrack func(int)
    backtrack = func(startIndex int) {
        if sum &amp;gt; n {
            return
        }
      
        if len(path) == k {
            if sum == n {
                res = append(res, append([]int(nil), path...))
            }
            return
        }

        maxStart := 9 - (k - len(path)) + 1 
        
        for i := startIndex; i &amp;lt;= maxStart; i++ {
            if sum + i &amp;gt; n {
                break
            }

            path = append(path, i)
            sum += i
            backtrack(i + 1)      
            sum -= i              
            path = path[:len(path)-1] 
        }
    }

    backtrack(1)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-46. 全排列</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-46-%E5%85%A8%E6%8E%92%E5%88%97/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-46-%E5%85%A8%E6%8E%92%E5%88%97/</guid><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/permutations/&quot;&gt;&lt;strong&gt;46. 全排列&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个不含重复数字的数组 &lt;code&gt;nums&lt;/code&gt; ，返回其 &lt;em&gt;所有可能的全排列&lt;/em&gt; 。你可以 &lt;strong&gt;按任意顺序&lt;/strong&gt; 返回答案。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,3]
输出：[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0,1]
输出：[[0,1],[1,0]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1]
输出：[[1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func permute(nums []int) [][]int {
    if len(nums) == 0 {
        return nil
    }

    res := [][]int{}
    path := []int{}
    used := make([]bool, len(nums))

    var backtrack func()
    backtrack = func() {
        if len(path) == len(nums) {
            res = append(res, append([]int(nil), path...))
			return
        }

        for i := 0; i &amp;lt; len(nums); i++ {
            if used[i] {
                continue
            }

            path = append(path, nums[i])
            used[i] = true
            backtrack()
            path = path[:len(path)-1]
            used[i] = false
        }
    }

    backtrack()
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-39. 组合总和</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-39-%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-39-%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C/</guid><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/combination-sum/&quot;&gt;&lt;strong&gt;39. 组合总和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个 &lt;strong&gt;无重复元素&lt;/strong&gt; 的整数数组 &lt;code&gt;candidates&lt;/code&gt; 和一个目标整数 &lt;code&gt;target&lt;/code&gt; ，找出 &lt;code&gt;candidates&lt;/code&gt; 中可以使数字和为目标数 &lt;code&gt;target&lt;/code&gt; 的 所有 &lt;strong&gt;不同组合&lt;/strong&gt; ，并以列表形式返回。你可以按 &lt;strong&gt;任意顺序&lt;/strong&gt; 返回这些组合。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;candidates&lt;/code&gt; 中的 &lt;strong&gt;同一个&lt;/strong&gt; 数字可以 &lt;strong&gt;无限制重复被选取&lt;/strong&gt; 。如果至少一个数字的被选数量不同，则两种组合是不同的。&lt;/p&gt;
&lt;p&gt;对于给定的输入，保证和为 &lt;code&gt;target&lt;/code&gt; 的不同组合数少于 &lt;code&gt;150&lt;/code&gt; 个。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：candidates = [2,3,6,7], target = 7
输出：[[2,2,3],[7]]
解释：
2 和 3 可以形成一组候选，2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选， 7 = 7 。
仅有这两种组合。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: candidates = [2], target = 1
输出: []
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;手撕版&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func combinationSum(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    res := [][]int{}
    path := []int{}

    var sum int
    var backtrack func(int)
    backtrack = func(index int) {
        if sum &amp;gt; target {
            return
        }
        
        if sum == target {
            res = append(res, append([]int(nil), path...))
            return
        }    

        for i := index; i &amp;lt; len(candidates); i++ {
            path = append(path, candidates[i])
            sum += candidates[i]
            backtrack(i)
            path = path[:len(path)-1]
            sum -= candidates[i]
        }
    }

    backtrack(0)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;剪枝优化版&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func combinationSum(candidates []int, target int) [][]int {
    sort.Ints(candidates)
    res := [][]int{}
    path := []int{}

    var sum int
    var backtrack func(int)
    backtrack = func(index int) { 
        if sum == target {
            res = append(res, append([]int(nil), path...))
            return
        }    

        for i := index; i &amp;lt; len(candidates); i++ {
        		if sum + candidates[i] &amp;gt; target {
            		break	
          	}
            path = append(path, candidates[i])
            sum += candidates[i]
            backtrack(i)
            path = path[:len(path)-1]
            sum -= candidates[i]
        }
    }

    backtrack(0)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-77. 组合</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-77-%E7%BB%84%E5%90%88/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-77-%E7%BB%84%E5%90%88/</guid><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/combinations/&quot;&gt;&lt;strong&gt;77. 组合&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个整数 &lt;code&gt;n&lt;/code&gt; 和 &lt;code&gt;k&lt;/code&gt;，返回范围 &lt;code&gt;[1, n]&lt;/code&gt; 中所有可能的 &lt;code&gt;k&lt;/code&gt; 个数的组合。&lt;/p&gt;
&lt;p&gt;你可以按 &lt;strong&gt;任何顺序&lt;/strong&gt; 返回答案。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 4, k = 2
输出：
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 1, k = 1
输出：[[1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func combine(n int, k int) [][]int {
    res := [][]int{}
    path := []int{}

    var backtrack func(int)
    backtrack = func(index int) {
        if len(path) == k {
            res = append(res, append([]int(nil), path...))
            return
        }
        
        for i := index; i &amp;lt;= n; i++ {
            path = append(path, i)
            backtrack(i+1)
            path = path[:len(path)-1]
        }
    }

    backtrack(1)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-78. 子集</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-78-%E5%AD%90%E9%9B%86/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%9E%E6%BA%AF/leetcode-78-%E5%AD%90%E9%9B%86/</guid><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;回溯&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/subsets/&quot;&gt;&lt;strong&gt;78. 子集&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，数组中的元素 &lt;strong&gt;互不相同&lt;/strong&gt; 。返回该数组所有可能的子集（幂集）。&lt;/p&gt;
&lt;p&gt;解集 &lt;strong&gt;不能&lt;/strong&gt; 包含重复的子集。你可以按 &lt;strong&gt;任意顺序&lt;/strong&gt; 返回解集。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,3]
输出：[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0]
输出：[[],[0]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func subsets(nums []int) [][]int {
    if len(nums) == 0 {
        return nil
    }

    res := [][]int{}
    path := []int{}

    var backtrack func(int)
    backtrack = func(start int) {
        res = append(res, append([]int(nil), path...))
        
        for i:= start; i &amp;lt; len(nums); i++ {
            path = append(path, nums[i])
            backtrack(i+1)
            path = path[:len(path)-1]
        }
    }

    backtrack(0)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>2026-3-31-weekly4</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-31-weekly4/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-31-weekly4/</guid><pubDate>Tue, 31 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h4&gt;本周摘要&lt;/h4&gt;
&lt;p&gt;本周主要是完成了力扣的图论部分和初步了解了hertz的使用，感觉当个性能更好的gin是可以无缝衔接的，这个idl和tag还需要研究和学习一下&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;洛克王国真好玩😊&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;一、具体完成事项&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;刷力扣&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完成图论的hot100题目&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;学习hertz的框架&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实践了hertz的hello_hertz的入门教程&lt;/li&gt;
&lt;li&gt;了解和使用hertz的idl的代码生成功能&lt;/li&gt;
&lt;li&gt;了解了一些tag相关&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;二、复盘与反思&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;图论感觉比较抽象，岛屿部分的DFS和BFS方法在经历二叉树的洗礼后感觉还ok，但与有向图、入度相关理论与题目结合题掌握一般&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;并查集理解的一般，很套路，但感觉不得其解&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hertz中相较于gin，新增的特性掌握不够&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;​&lt;/p&gt;
&lt;h4&gt;三、下周计划(可能的几个方向)&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;继续力扣hot100&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>LeetCode-547. 省份数量</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-547-%E7%9C%81%E4%BB%BD%E6%95%B0%E9%87%8F/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-547-%E7%9C%81%E4%BB%BD%E6%95%B0%E9%87%8F/</guid><pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/number-of-provinces/&quot;&gt;&lt;strong&gt;547. 省份数量&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有 &lt;code&gt;n&lt;/code&gt; 个城市，其中一些彼此相连，另一些没有相连。如果城市 &lt;code&gt;a&lt;/code&gt; 与城市 &lt;code&gt;b&lt;/code&gt; 直接相连，且城市 &lt;code&gt;b&lt;/code&gt; 与城市 &lt;code&gt;c&lt;/code&gt; 直接相连，那么城市 &lt;code&gt;a&lt;/code&gt; 与城市 &lt;code&gt;c&lt;/code&gt; 间接相连。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;省份&lt;/strong&gt; 是一组直接或间接相连的城市，组内不含其他没有相连的城市。&lt;/p&gt;
&lt;p&gt;给你一个 &lt;code&gt;n x n&lt;/code&gt; 的矩阵 &lt;code&gt;isConnected&lt;/code&gt; ，其中 &lt;code&gt;isConnected[i][j] = 1&lt;/code&gt; 表示第 &lt;code&gt;i&lt;/code&gt; 个城市和第 &lt;code&gt;j&lt;/code&gt; 个城市直接相连，而 &lt;code&gt;isConnected[i][j] = 0&lt;/code&gt; 表示二者不直接相连。&lt;/p&gt;
&lt;p&gt;返回矩阵中 &lt;strong&gt;省份&lt;/strong&gt; 的数量。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/12/24/graph1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：isConnected = [[1,1,0],[1,1,0],[0,0,1]]
输出：2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/12/24/graph2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：isConnected = [[1,0,0],[0,1,0],[0,0,1]]
输出：3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;并查集的方法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;感觉是一个很神奇的方法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func findCircleNum(isConnected [][]int) int {
    n := len(isConnected)

    parent := make([]int, n)
    for i := 0; i &amp;lt; n; i++ {
        parent[i] = i
    }

    var find func(i int) int
    find = func(i int) int{
        if parent[i] != i {
            parent[i] = find(parent[i])
        } 
        return parent[i]
    }

    count := n
    for i := 0; i &amp;lt; n; i++ {
        for j := i+1; j &amp;lt; n; j++ {
            if isConnected[i][j] == 1 {
                rootI := find(i)
                rootJ := find(j)
                if rootI != rootJ {
                    parent[rootI] = rootJ
                    count--
                }
            }
        }
    }
    return count
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-684. 冗余连接</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-684-%E5%86%97%E4%BD%99%E8%BF%9E%E6%8E%A5/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-684-%E5%86%97%E4%BD%99%E8%BF%9E%E6%8E%A5/</guid><pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/redundant-connection/&quot;&gt;&lt;strong&gt;684. 冗余连接&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;树可以看成是一个连通且 &lt;strong&gt;无环&lt;/strong&gt; 的 &lt;strong&gt;无向&lt;/strong&gt; 图。&lt;/p&gt;
&lt;p&gt;给定一个图，该图从一棵 &lt;code&gt;n&lt;/code&gt; 个节点 (节点值 &lt;code&gt;1～n&lt;/code&gt;) 的树中添加一条边后获得。添加的边的两个不同顶点编号在 &lt;code&gt;1&lt;/code&gt; 到 &lt;code&gt;n&lt;/code&gt; 中间，且这条附加的边不属于树中已存在的边。图的信息记录于长度为 &lt;code&gt;n&lt;/code&gt; 的二维数组 &lt;code&gt;edges&lt;/code&gt; ，&lt;code&gt;edges[i] = [ai, bi]&lt;/code&gt; 表示图中在 &lt;code&gt;ai&lt;/code&gt; 和 &lt;code&gt;bi&lt;/code&gt; 之间存在一条边。&lt;/p&gt;
&lt;p&gt;请找出一条可以删去的边，删除后可使得剩余部分是一个有着 &lt;code&gt;n&lt;/code&gt; 个节点的树。如果有多个答案，则返回数组 &lt;code&gt;edges&lt;/code&gt; 中最后出现的那个。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://pic.leetcode.cn/1626676174-hOEVUL-image.png&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: edges = [[1,2], [1,3], [2,3]]
输出: [2,3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://pic.leetcode.cn/1626676179-kGxcmu-image.png&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: edges = [[1,2], [2,3], [3,4], [1,4], [1,5]]
输出: [1,4]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;并查集的方法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;做了两题感觉比较公式🫤？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func findRedundantConnection(edges [][]int) []int {
    n := len(edges)

    parent := make([]int, n+1)
    for i := 1; i &amp;lt;= n; i++ {
        parent[i] = i
    }

    var find func(i int) int
    find = func(i int) int {
        if parent[i] != i {
            parent[i] = find(parent[i])
        }
        return parent[i]
    }

    for i := 0; i &amp;lt; n; i++ {
        a, b := edges[i][0], edges[i][1]
        rootA := find(a)
        rootB := find(b)
        if rootA == rootB {
            return edges[i]
        }else {
            parent[rootA] = rootB
        }
    }
    return nil
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-210.课程表 II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-210%E8%AF%BE%E7%A8%8B%E8%A1%A8-ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-210%E8%AF%BE%E7%A8%8B%E8%A1%A8-ii/</guid><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/course-schedule-ii/&quot;&gt;&lt;strong&gt;210. 课程表 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;现在你总共有 &lt;code&gt;numCourses&lt;/code&gt; 门课需要选，记为 &lt;code&gt;0&lt;/code&gt; 到 &lt;code&gt;numCourses - 1&lt;/code&gt;。给你一个数组 &lt;code&gt;prerequisites&lt;/code&gt; ，其中 &lt;code&gt;prerequisites[i] = [ai, bi]&lt;/code&gt; ，表示在选修课程 &lt;code&gt;ai&lt;/code&gt; 前 &lt;strong&gt;必须&lt;/strong&gt; 先选修 &lt;code&gt;bi&lt;/code&gt; 。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;例如，想要学习课程 &lt;code&gt;0&lt;/code&gt; ，你需要先完成课程 &lt;code&gt;1&lt;/code&gt; ，我们用一个匹配来表示：&lt;code&gt;[0,1]&lt;/code&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序，你只要返回 &lt;strong&gt;任意一种&lt;/strong&gt; 就可以了。如果不可能完成所有课程，返回 &lt;strong&gt;一个空数组&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：numCourses = 2, prerequisites = [[1,0]]
输出：[0,1]
解释：总共有 2 门课程。要学习课程 1，你需要先完成课程 0。因此，正确的课程顺序为 [0,1] 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
输出：[0,2,1,3]
解释：总共有 4 门课程。要学习课程 3，你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
因此，一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3] 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：numCourses = 1, prerequisites = []
输出：[0]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;BFS的方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路:和 &lt;a href=&quot;https://leetcode.cn/problems/course-schedule/&quot;&gt;&lt;strong&gt;207. 课程表&lt;/strong&gt;&lt;/a&gt; 类似，只是要求成功时输出&lt;code&gt;数组&lt;/code&gt;而不是&lt;code&gt;true&lt;/code&gt;。所以，把count换成res即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func findOrder(numCourses int, prerequisites [][]int) []int {
    graph := make([][]int, numCourses)
    indegree := make([]int, numCourses)

    for  _, v := range prerequisites {
        to, from := v[0], v[1]
        graph[from] = append(graph[from], to)
        indegree[to]++
    }

    queue := []int{}
    for i := 0; i &amp;lt; numCourses; i++ {
        if indegree[i] == 0 {
            queue = append(queue, i)
        }
    }

    res := []int{}
    for len(queue) &amp;gt; 0 {
        cur := queue[0]
        queue = queue[1:]
        res = append(res, cur)

        for _, v := range graph[cur] {
            indegree[v]--
            if indegree[v] == 0 {
                queue = append(queue, v)
            }
        }
    }

    if len(res) != numCourses {
        return []int{}
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-207.课程表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-207%E8%AF%BE%E7%A8%8B%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-207%E8%AF%BE%E7%A8%8B%E8%A1%A8/</guid><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/course-schedule/&quot;&gt;&lt;strong&gt;207. 课程表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你这个学期必须选修 &lt;code&gt;numCourses&lt;/code&gt; 门课程，记为 &lt;code&gt;0&lt;/code&gt; 到 &lt;code&gt;numCourses - 1&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;在选修某些课程之前需要一些先修课程。 先修课程按数组 &lt;code&gt;prerequisites&lt;/code&gt; 给出，其中 &lt;code&gt;prerequisites[i] = [ai, bi]&lt;/code&gt; ，表示如果要学习课程 &lt;code&gt;ai&lt;/code&gt; 则 &lt;strong&gt;必须&lt;/strong&gt; 先学习课程 &lt;code&gt;bi&lt;/code&gt; 。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;例如，先修课程对 &lt;code&gt;[0, 1]&lt;/code&gt; 表示：想要学习课程 &lt;code&gt;0&lt;/code&gt; ，你需要先完成课程 &lt;code&gt;1&lt;/code&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;请你判断是否可能完成所有课程的学习？如果可以，返回 &lt;code&gt;true&lt;/code&gt; ；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：numCourses = 2, prerequisites = [[1,0]]
输出：true
解释：总共有 2 门课程。学习课程 1 之前，你需要完成课程 0 。这是可能的。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：numCourses = 2, prerequisites = [[1,0],[0,1]]
输出：false
解释：总共有 2 门课程。学习课程 1 之前，你需要先完成课程 0 ；并且学习课程 0 之前，你还应先完成课程 1 。这是不可能的。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;BFS的方法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func canFinish(numCourses int, prerequisites [][]int) bool {
    graph := make([][]int, numCourses)
    indegree := make([]int, numCourses)

    for  _, v := range prerequisites {
        to, from := v[0], v[1]
        graph[from] = append(graph[from], to)
        indegree[to]++
    }

    queue := []int{}
    for i := 0; i &amp;lt; numCourses; i++ {
        if indegree[i] == 0 {
            queue = append(queue, i)
        }
    }

    count := 0
    for len(queue) &amp;gt; 0 {
        cur := queue[0]
        queue = queue[1:]
        count++

        for _, v := range graph[cur] {
            indegree[v]--
            if indegree[v] == 0 {
                queue = append(queue, v)
            }
        }
    }

    return count == numCourses
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-208. 实现 Trie (前缀树)</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-208-%E5%AE%9E%E7%8E%B0-trie-%E5%89%8D%E7%BC%80%E6%A0%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-208-%E5%AE%9E%E7%8E%B0-trie-%E5%89%8D%E7%BC%80%E6%A0%91/</guid><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/implement-trie-prefix-tree/&quot;&gt;&lt;strong&gt;208. 实现 Trie (前缀树)&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://baike.baidu.com/item/%E5%AD%97%E5%85%B8%E6%A0%91/9825209?fr=aladdin&quot;&gt;Trie&lt;/a&gt;&lt;/strong&gt;（发音类似 &quot;try&quot;）或者说 &lt;strong&gt;前缀树&lt;/strong&gt; 是一种树形数据结构，用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景，例如自动补全和拼写检查。&lt;/p&gt;
&lt;p&gt;请你实现 Trie 类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Trie()&lt;/code&gt; 初始化前缀树对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void insert(String word)&lt;/code&gt; 向前缀树中插入字符串 &lt;code&gt;word&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;boolean search(String word)&lt;/code&gt; 如果字符串 &lt;code&gt;word&lt;/code&gt; 在前缀树中，返回 &lt;code&gt;true&lt;/code&gt;（即，在检索之前已经插入）；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;boolean startsWith(String prefix)&lt;/code&gt; 如果之前已经插入的字符串 &lt;code&gt;word&lt;/code&gt; 的前缀之一为 &lt;code&gt;prefix&lt;/code&gt; ，返回 &lt;code&gt;true&lt;/code&gt; ；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入
[&quot;Trie&quot;, &quot;insert&quot;, &quot;search&quot;, &quot;search&quot;, &quot;startsWith&quot;, &quot;insert&quot;, &quot;search&quot;]
[[], [&quot;apple&quot;], [&quot;apple&quot;], [&quot;app&quot;], [&quot;app&quot;], [&quot;app&quot;], [&quot;app&quot;]]
输出
[null, null, true, false, true, null, true]

解释
Trie trie = new Trie();
trie.insert(&quot;apple&quot;);
trie.search(&quot;apple&quot;);   // 返回 True
trie.search(&quot;app&quot;);     // 返回 False
trie.startsWith(&quot;app&quot;); // 返回 True
trie.insert(&quot;app&quot;);
trie.search(&quot;app&quot;);     // 返回 True
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;BFS的方法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Trie struct {
    children [26]*Trie 
    isEnd    bool      
}

func Constructor() Trie {
    return Trie{}
}

func (this *Trie) Insert(word string) {
    node := this 
    for _, ch := range word {
        idx := ch - &apos;a&apos; 
        if node.children[idx] == nil {
            node.children[idx] = &amp;amp;Trie{}
        }

        node = node.children[idx]
    }

    node.isEnd = true
}

func (this *Trie) Search(word string) bool {
    node := this
    for _, ch := range word {
        idx := ch - &apos;a&apos;
        if node.children[idx] == nil {
            return false 
        }
        node = node.children[idx]
    }

    return node.isEnd
}

func (this *Trie) StartsWith(prefix string) bool {
    node := this
    for _, ch := range prefix {
        idx := ch - &apos;a&apos;
        if node.children[idx] == nil {
            return false
        }
        node = node.children[idx]
    }
    return true
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-417.太平洋大西洋水流问题</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-417%E5%A4%AA%E5%B9%B3%E6%B4%8B%E5%A4%A7%E8%A5%BF%E6%B4%8B%E6%B0%B4%E6%B5%81%E9%97%AE%E9%A2%98/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-417%E5%A4%AA%E5%B9%B3%E6%B4%8B%E5%A4%A7%E8%A5%BF%E6%B4%8B%E6%B0%B4%E6%B5%81%E9%97%AE%E9%A2%98/</guid><pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/pacific-atlantic-water-flow/&quot;&gt;&lt;strong&gt;417. 太平洋大西洋水流问题&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有一个 &lt;code&gt;m × n&lt;/code&gt; 的矩形岛屿，与 &lt;strong&gt;太平洋&lt;/strong&gt; 和 &lt;strong&gt;大西洋&lt;/strong&gt; 相邻。 &lt;strong&gt;“太平洋”&lt;/strong&gt; 处于大陆的左边界和上边界，而 &lt;strong&gt;“大西洋”&lt;/strong&gt; 处于大陆的右边界和下边界。&lt;/p&gt;
&lt;p&gt;这个岛被分割成一个由若干方形单元格组成的网格。给定一个 &lt;code&gt;m x n&lt;/code&gt; 的整数矩阵 &lt;code&gt;heights&lt;/code&gt; ， &lt;code&gt;heights[r][c]&lt;/code&gt; 表示坐标 &lt;code&gt;(r, c)&lt;/code&gt; 上单元格 &lt;strong&gt;高于海平面的高度&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;岛上雨水较多，如果相邻单元格的高度 &lt;strong&gt;小于或等于&lt;/strong&gt; 当前单元格的高度，雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。&lt;/p&gt;
&lt;p&gt;返回网格坐标 &lt;code&gt;result&lt;/code&gt; 的 &lt;strong&gt;2D 列表&lt;/strong&gt; ，其中 &lt;code&gt;result[i] = [ri, ci]&lt;/code&gt; 表示雨水从单元格 &lt;code&gt;(ri, ci)&lt;/code&gt; 流动 &lt;strong&gt;既可流向太平洋也可流向大西洋&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/06/08/waterflow-grid.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
输出: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: heights = [[2,1],[1,2]]
输出: [[0,0],[0,1],[1,0],[1,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DFS的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：&lt;/p&gt;
&lt;p&gt;这道题最容易让我们陷入的误区是“正向思维”：遍历每一个格子，分别做 DFS 看它能不能一路走到太平洋和大西洋。这种做法会产生大量重复计算，时间复杂度直接爆炸到 O((M * N)^2)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;所以我们逆向思维，太平洋和大西洋倒灌，用表记录能到达的地方，最后比较一下即可，思路不是很复杂&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;但是有几个注意点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;这个矩阵需要用循环初始化，不然内部的切片没有初始化，无法使用&lt;code&gt;visited[row][col]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;DFS的边界条件注意下，逆着来可能会出错&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;func pacificAtlantic(heights [][]int) [][]int {
    if len(heights) == 0 || len(heights[0]) == 0 {
        return nil
    }

    m, n := len(heights), len(heights[0])
    pacific := make([][]bool, m)
    atlantic := make([][]bool, m)
    for i := 0; i &amp;lt; m; i++ {
        pacific[i] = make([]bool, n)
        atlantic[i] = make([]bool, n)
    }

    var dfs func(row, col int, visited [][]bool, pre int)
    dfs = func(row, col int, visited [][]bool, pre int) {
        if row &amp;lt; 0 || col &amp;lt; 0 || row &amp;gt;= m || col &amp;gt;= n || visited[row][col] || heights[row][col] &amp;lt; pre {
            return
        }

        visited[row][col] = true

        dfs(row-1, col, visited, heights[row][col])
        dfs(row+1, col, visited, heights[row][col])
        dfs(row, col-1, visited, heights[row][col])
        dfs(row, col+1, visited, heights[row][col])
    }

    for i := 0; i &amp;lt; m; i++ {
        dfs(i, 0, pacific, heights[i][0])
        dfs(i, n-1, atlantic, heights[i][n-1])
    }

    for j := 0; j &amp;lt; n; j++ {
        dfs(0, j, pacific, heights[0][j])
        dfs(m-1, j, atlantic, heights[m-1][j])
    }

    res := [][]int{}
    for i:= 0; i &amp;lt; m; i++ {
        for j := 0; j &amp;lt; n; j++ {
            if atlantic[i][j] &amp;amp;&amp;amp; pacific[i][j] {
                res = append(res, []int{i, j})
            }
        }
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>第三周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-23-weekly3/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-23-weekly3/</guid><pubDate>Mon, 23 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h4&gt;本周摘要&lt;/h4&gt;
&lt;p&gt;本周感觉对hot100有点失去热情了，可能也有图论比较难的原因，没有一开始那般豁然开朗的感觉。所以，这周勉强过关二叉树、初识图论，只完成了19题（其中hot100站8题）。所以，去学习了一下kitex微服务框架，换换脑子。&lt;/p&gt;
&lt;h4&gt;一、具体完成事项&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;刷力扣&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完成二叉树的hot100题目&lt;/li&gt;
&lt;li&gt;初识图论及其相关DFS和BFS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;学习kitex微服务框架&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;看蓝山的课件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实践kitex的example-shop的进阶教程&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尝试阅读easy-note的代码&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;二、复盘与反思&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;不足之处&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;目前对题解的依赖度较高，大部分题目不能独立手撕。&lt;/p&gt;
&lt;p&gt;rpc相关还不太理解&lt;/p&gt;
&lt;p&gt;​&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;三、下周计划(可能的几个方向)&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;继续学习kitex&lt;/li&gt;
&lt;li&gt;算法&lt;/li&gt;
&lt;li&gt;了解一下hertz&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>LeetCode-200.岛屿数量</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-200%E5%B2%9B%E5%B1%BF%E6%95%B0%E9%87%8F/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-200%E5%B2%9B%E5%B1%BF%E6%95%B0%E9%87%8F/</guid><pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/number-of-islands/&quot;&gt;&lt;strong&gt;200. 岛屿数量&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个由 &lt;code&gt;&apos;1&apos;&lt;/code&gt;（陆地）和 &lt;code&gt;&apos;0&apos;&lt;/code&gt;（水）组成的的二维网格，请你计算网格中岛屿的数量。&lt;/p&gt;
&lt;p&gt;岛屿总是被水包围，并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。&lt;/p&gt;
&lt;p&gt;此外，你可以假设该网格的四条边均被水包围。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：grid = [
  [&apos;1&apos;,&apos;1&apos;,&apos;1&apos;,&apos;1&apos;,&apos;0&apos;],
  [&apos;1&apos;,&apos;1&apos;,&apos;0&apos;,&apos;1&apos;,&apos;0&apos;],
  [&apos;1&apos;,&apos;1&apos;,&apos;0&apos;,&apos;0&apos;,&apos;0&apos;],
  [&apos;0&apos;,&apos;0&apos;,&apos;0&apos;,&apos;0&apos;,&apos;0&apos;]
]
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：grid = [
  [&apos;1&apos;,&apos;1&apos;,&apos;0&apos;,&apos;0&apos;,&apos;0&apos;],
  [&apos;1&apos;,&apos;1&apos;,&apos;0&apos;,&apos;0&apos;,&apos;0&apos;],
  [&apos;0&apos;,&apos;0&apos;,&apos;1&apos;,&apos;0&apos;,&apos;0&apos;],
  [&apos;0&apos;,&apos;0&apos;,&apos;0&apos;,&apos;1&apos;,&apos;1&apos;]
]
输出：3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DFS的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;初次接触图论&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func numIslands(grid [][]byte) int {
    if len(grid) == 0 {
        return 0
    }
    count := 0

    var dfs func(r, c int)
    dfs = func(r, c int) {
        if r &amp;lt; 0 || c &amp;lt; 0 || r &amp;gt;= len(grid) || c &amp;gt;= len(grid[0]) || grid[r][c] == &apos;0&apos; {
            return
        }

        grid[r][c] = &apos;0&apos;

        dfs(r-1, c)
        dfs(r+1, c)
        dfs(r, c-1)
        dfs(r, c+1)
    }

    for i := 0; i &amp;lt; len(grid); i++ {
        for j := 0; j &amp;lt; len(grid[0]); j++ {
            if grid[i][j] == &apos;1&apos; {
                count++
                dfs(i, j)
            }
        }
    }

    return count
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;BFS的解法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func numIslands(grid [][]byte) int {
    if len(grid) == 0 {
        return 0
    }

    count := 0
    dirs := [][]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}

    var bfs func(r, c int)
    bfs = func(r, c int) {
        queue := [][]int{{r, c}}
        grid[r][c] = &apos;0&apos;

        for len(queue) &amp;gt; 0 {
            cur := queue[0]
            queue = queue[1:]
            row, col := cur[0], cur[1]
            
            for _, d := range dirs {
                nr, nc := row+d[0], col+d[1]
                if nr &amp;gt;= 0 &amp;amp;&amp;amp; nc &amp;gt;= 0 &amp;amp;&amp;amp; nr &amp;lt; len(grid) &amp;amp;&amp;amp; nc &amp;lt; len(grid[0]) &amp;amp;&amp;amp; grid[nr][nc] ==&apos;1&apos;{
                    grid[nr][nc] = &apos;0&apos;
                    queue = append(queue, []int{nr, nc})
                }
            }
        }

    }

    for i := 0; i &amp;lt; len(grid); i++ {
        for j := 0; j &amp;lt; len(grid[0]); j++ {
            if grid[i][j] == &apos;1&apos; {
                count++
                bfs(i, j)
            }
        }
    }

    return count
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-695.岛屿的最大面积</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-695%E5%B2%9B%E5%B1%BF%E7%9A%84%E6%9C%80%E5%A4%A7%E9%9D%A2%E7%A7%AF/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-695%E5%B2%9B%E5%B1%BF%E7%9A%84%E6%9C%80%E5%A4%A7%E9%9D%A2%E7%A7%AF/</guid><pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/max-area-of-island/&quot;&gt;&lt;strong&gt;695. 岛屿的最大面积&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个大小为 &lt;code&gt;m x n&lt;/code&gt; 的二进制矩阵 &lt;code&gt;grid&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;岛屿&lt;/strong&gt; 是由一些相邻的 &lt;code&gt;1&lt;/code&gt; (代表土地) 构成的组合，这里的「相邻」要求两个 &lt;code&gt;1&lt;/code&gt; 必须在 &lt;strong&gt;水平或者竖直的四个方向上&lt;/strong&gt; 相邻。你可以假设 &lt;code&gt;grid&lt;/code&gt; 的四个边缘都被 &lt;code&gt;0&lt;/code&gt;（代表水）包围着。&lt;/p&gt;
&lt;p&gt;岛屿的面积是岛上值为 &lt;code&gt;1&lt;/code&gt; 的单元格的数目。&lt;/p&gt;
&lt;p&gt;计算并返回 &lt;code&gt;grid&lt;/code&gt; 中最大的岛屿面积。如果没有岛屿，则返回面积为 &lt;code&gt;0&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/05/01/maxarea1-grid.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：grid = [[0,0,1,0,0,0,0,1,0,0,0,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,1,1,0,1,0,0,0,0,0,0,0,0],[0,1,0,0,1,1,0,0,1,0,1,0,0],[0,1,0,0,1,1,0,0,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,0,0,0,0,1,1,0,0,0,0]]
输出：6
解释：答案不应该是 11 ，因为岛屿只能包含水平或垂直这四个方向上的 1 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：grid = [[0,0,0,0,0,0,0,0]]
输出：0
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法(DFS)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我靠，怎么你和 &lt;a href=&quot;https://leetcode.cn/problems/number-of-islands/&quot;&gt;200. 岛屿数量&lt;/a&gt; 的数组类型不一样的，害我看了好一会儿没看出来哪里有问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：我认为是 &lt;a href=&quot;https://leetcode.cn/problems/number-of-islands/&quot;&gt;&lt;strong&gt;200. 岛屿数量&lt;/strong&gt;&lt;/a&gt; + &lt;a href=&quot;https://leetcode.cn/problems/diameter-of-binary-tree/&quot;&gt;&lt;strong&gt;543. 二叉树的直径&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxAreaOfIsland(grid [][]int) int {
    if len(grid) == 0 {
        return 0
    }
    maxcount := 0

    var dfs func(r,c int) int
    dfs = func(r, c int) int {
        if r &amp;lt; 0 || c &amp;lt; 0 || r &amp;gt;= len(grid) || c &amp;gt;= len(grid[0]) || grid[r][c] == 0 {
            return 0
        }

        grid[r][c] = 0

        up := dfs(r-1, c)
        down := dfs(r+1, c)
        left := dfs(r, c-1)
        right := dfs(r, c+1)

        if up + down + left + right + 1 &amp;gt; maxcount {
            maxcount = up + down + left + right + 1
        }

        return up + down + left + right + 1
    }

    for i := 0; i &amp;lt; len(grid); i++ {
        for j := 0; j &amp;lt; len(grid[0]); j++ {
            if grid[i][j] == 1 {
                dfs(i, j)
            }
        }
    }

    return maxcount
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;稍微优化一下&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxAreaOfIsland(grid [][]int) int {
    if len(grid) == 0 {
        return 0
    }
    maxcount := 0

    var dfs func(r, c int) int
    dfs = func(r, c int) int {
        if r &amp;lt; 0 || c &amp;lt; 0 || r &amp;gt;= len(grid) || c &amp;gt;= len(grid[0]) || grid[r][c] == 0 {
            return 0
        }
        grid[r][c] = 0 
        return 1 + dfs(r-1, c) + dfs(r+1, c) + dfs(r, c-1) + dfs(r, c+1)
    }

    for i := 0; i &amp;lt; len(grid); i++ {
        for j := 0; j &amp;lt; len(grid[0]); j++ {
            if grid[i][j] == 1 {
                area := dfs(i, j)
                if area &amp;gt; maxcount {
                    maxcount = area
                }
            }
        }
    }
    return maxcount
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-994.腐烂的橘子</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-994%E8%85%90%E7%83%82%E7%9A%84%E6%A9%98%E5%AD%90/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%9B%BE%E8%AE%BA/leetcode-994%E8%85%90%E7%83%82%E7%9A%84%E6%A9%98%E5%AD%90/</guid><pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;图论&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/rotting-oranges/&quot;&gt;&lt;strong&gt;994. 腐烂的橘子&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在给定的 &lt;code&gt;m x n&lt;/code&gt; 网格 &lt;code&gt;grid&lt;/code&gt; 中，每个单元格可以有以下三个值之一：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;值 &lt;code&gt;0&lt;/code&gt; 代表空单元格；&lt;/li&gt;
&lt;li&gt;值 &lt;code&gt;1&lt;/code&gt; 代表新鲜橘子；&lt;/li&gt;
&lt;li&gt;值 &lt;code&gt;2&lt;/code&gt; 代表腐烂的橘子。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每分钟，腐烂的橘子 &lt;strong&gt;周围 4 个方向上相邻&lt;/strong&gt; 的新鲜橘子都会腐烂。&lt;/p&gt;
&lt;p&gt;返回 &lt;em&gt;直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能，返回 &lt;code&gt;-1&lt;/code&gt;&lt;/em&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2019/02/16/oranges.png&quot; alt=&quot;img&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：grid = [[2,1,1],[1,1,0],[0,1,1]]
输出：4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：grid = [[2,1,1],[0,1,1],[1,0,1]]
输出：-1
解释：左下角的橘子（第 2 行， 第 0 列）永远不会腐烂，因为腐烂只会发生在 4 个方向上。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：grid = [[0,2]]
输出：0
解释：因为 0 分钟时已经没有新鲜橘子了，所以答案就是 0 。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;BFS的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;容易被题目示例误导的一点是：这里的烂橘子是可以不止一个的，这就与 &lt;a href=&quot;https://leetcode.cn/problems/number-of-islands/&quot;&gt;&lt;strong&gt;200. 岛屿数量&lt;/strong&gt;&lt;/a&gt; 有所不同，从“单源”改为“多源”，所以需要先遍历一次网格，把所有初始状态就是 &lt;code&gt;2&lt;/code&gt; 的烂橘子&lt;strong&gt;全部&lt;/strong&gt;塞进初始队列中。它们处于同一“层”，地位平等，会像水波纹一样同时向外扩散。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;就是&lt;code&gt;rottedThisMinute = true&lt;/code&gt;的作用，我们会疑惑时间不是一直在增加的吗，为什么需要这个？&lt;/p&gt;
&lt;p&gt;这是因为会遇到像&lt;code&gt;示例3&lt;/code&gt;的状况，它们被从 &lt;code&gt;queue&lt;/code&gt; 中取出来，此时，它们周围已经没有任何新鲜橘子了（或者被墙挡住了），但程序还会检查，所以这段时间是不需要或者说是没意义的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func orangesRotting(grid [][]int) int {
    if len(grid) == 0 {
        return 0
    }

    m, n := len(grid), len(grid[0])
   
    queue := [][]int{}
    fresh := 0
    for i := 0; i &amp;lt; m; i++ {
        for j := 0; j &amp;lt; n; j++ {
            if grid[i][j] == 2 {
                queue = append(queue, []int{i, j})
            }
            if grid[i][j] == 1 {
                fresh++
            }
        }
    }

    if fresh == 0 {
        return 0
    }

    time := 0
    dirs := [][]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}
    for len(queue) != 0 {
        size := len(queue)
        rottedThisMinute := false
        for i := 0; i &amp;lt; size; i++ {
            cur := queue[0]
            queue = queue[1:]
            row, col := cur[0], cur[1]

            for _, v := range dirs {
                nr, nc := v[0]+row, v[1]+col
                if nr &amp;gt;= 0 &amp;amp;&amp;amp; nr &amp;lt; m &amp;amp;&amp;amp; nc &amp;gt;= 0 &amp;amp;&amp;amp; nc &amp;lt; n &amp;amp;&amp;amp; grid[nr][nc] == 1 {
                    grid[nr][nc] = 2
                    queue = append(queue, []int{nr, nc})
                    fresh--
                    rottedThisMinute = true
                }
            }
        }

        if rottedThisMinute == true {
            time++
        }
    }

    if fresh != 0 {
        return -1
    }

    return time
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-113. 路径总和 II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-113-%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C-ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-113-%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C-ii/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/path-sum-ii/&quot;&gt;&lt;strong&gt;113. 路径总和 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你二叉树的根节点 &lt;code&gt;root&lt;/code&gt; 和一个整数目标和 &lt;code&gt;targetSum&lt;/code&gt; ，找出所有 &lt;strong&gt;从根节点到叶子节点&lt;/strong&gt; 路径总和等于给定目标和的路径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;叶子节点&lt;/strong&gt; 是指没有子节点的节点。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/18/pathsumii1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出：[[5,4,11,2],[5,8,4,5]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/18/pathsum2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,3], targetSum = 5
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2], targetSum = 0
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原本只是想先做一下路径总和 I 和 路径总和 II，为路径总和 III铺垫一下的，没想到还涉及到了回溯，更不会做了☹️，不过最终还是理解了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func pathSum(root *TreeNode, targetSum int) [][]int {
    var res [][]int
    var path []int

    var dfs func(*TreeNode, int)
    dfs = func(node *TreeNode, sum int) {
        if node == nil {
            return
        }

        path = append(path, node.Val)
        sum -= node.Val

        if node.Left == nil &amp;amp;&amp;amp; node.Right == nil &amp;amp;&amp;amp; sum == 0 {
            tmp := make([]int, len(path))
            copy(tmp, path)
            res = append(res, tmp)
        } else {
            dfs(node.Left, sum)
            dfs(node.Right, sum)
        }

        path = path[:len(path)-1]
    }

    dfs(root, targetSum)
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-124.二叉树中的最大路径和</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-124%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E7%9A%84%E6%9C%80%E5%A4%A7%E8%B7%AF%E5%BE%84%E5%92%8C/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-124%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E7%9A%84%E6%9C%80%E5%A4%A7%E8%B7%AF%E5%BE%84%E5%92%8C/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-maximum-path-sum/&quot;&gt;&lt;strong&gt;124. 二叉树中的最大路径和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;二叉树中的 &lt;strong&gt;路径&lt;/strong&gt; 被定义为一条节点序列，序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 &lt;strong&gt;至多出现一次&lt;/strong&gt; 。该路径 &lt;strong&gt;至少包含一个&lt;/strong&gt; 节点，且不一定经过根节点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;路径和&lt;/strong&gt; 是路径中各节点值的总和。&lt;/p&gt;
&lt;p&gt;给你一个二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ，返回其 &lt;strong&gt;最大路径和&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/13/exx1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,3]
输出：6
解释：最优路径是 2 -&amp;gt; 1 -&amp;gt; 3 ，路径和为 2 + 1 + 3 = 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/13/exx2.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [-10,9,20,null,null,15,7]
输出：42
解释：最优路径是 15 -&amp;gt; 20 -&amp;gt; 7 ，路径和为 15 + 20 + 7 = 42
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;作为困难题，其实还是挺简单的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：和 &lt;a href=&quot;https://leetcode.cn/problems/diameter-of-binary-tree/&quot;&gt;&lt;strong&gt;543. 二叉树的直径&lt;/strong&gt;&lt;/a&gt; 类似，不过数据处理相对复杂一点，需要处理左右为负的情况，判断最大时需要都加起来，而返回时需要根+左右两边更大的值，这里稍微不一样。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func diameterOfBinaryTree(root *TreeNode) int {
    if root == nil {
        return 0
    }
    maxDiameter := 0
    
    var maxDepth func(*TreeNode) int
    maxDepth = func(root *TreeNode) int {
        if root == nil {
            return 0
        }

        leftHeight := maxDepth(root.Left)
        rightHeight := maxDepth(root.Right)

        if leftHeight + rightHeight &amp;gt; maxDiameter {
            maxDiameter = leftHeight + rightHeight
        }
    
        return max(leftHeight, rightHeight) + 1
    }
    maxDepth(root)

    return maxDiameter
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-437.路径总和 III</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-437%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C-iii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-437%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C-iii/</guid><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/path-sum-iii/&quot;&gt;&lt;strong&gt;437. 路径总和 III&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ，和一个整数 &lt;code&gt;targetSum&lt;/code&gt; ，求该二叉树里节点值之和等于 &lt;code&gt;targetSum&lt;/code&gt; 的 &lt;strong&gt;路径&lt;/strong&gt; 的数目。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;路径&lt;/strong&gt; 不需要从根节点开始，也不需要在叶子节点结束，但是路径方向必须是向下的（只能从父节点到子节点）。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/04/09/pathsum3-1-tree.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出：3
解释：和等于 8 的路径有 3 条，如图所示。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出：3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：这题其实看过 &lt;a href=&quot;https://leetcode.cn/problems/path-sum-ii/&quot;&gt;&lt;strong&gt;113. 路径总和 II&lt;/strong&gt;&lt;/a&gt; 和 &lt;a href=&quot;https://leetcode.cn/problems/path-sum/&quot;&gt;&lt;strong&gt;112. 路径总和&lt;/strong&gt;&lt;/a&gt; 的题目后，比较一下就可以发现 本题的答案就是&lt;code&gt;子节点的递归 + 根节点的路径数目&lt;/code&gt;，由此写出两个递归即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func pathSum(root *TreeNode, targetSum int) int {
    if root == nil {
        return 0
    }

    res := rootsum(root, targetSum)

    res += pathSum(root.Left, targetSum)
    res += pathSum(root.Right, targetSum)

    return res
}

func rootsum(node *TreeNode, targetSum int) int {
    if node == nil {
        return 0
    }

    count := 0
    if node.Val == targetSum {
        count++
    }

    count += rootsum(node.Left, targetSum-node.Val)
    count += rootsum(node.Right, targetSum-node.Val)

    return count
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-105.从前序与中序遍历序列构造二叉树</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-105%E4%BB%8E%E5%89%8D%E5%BA%8F%E4%B8%8E%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-105%E4%BB%8E%E5%89%8D%E5%BA%8F%E4%B8%8E%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91/</guid><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/&quot;&gt;&lt;strong&gt;105. 从前序与中序遍历序列构造二叉树&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个整数数组 &lt;code&gt;preorder&lt;/code&gt; 和 &lt;code&gt;inorder&lt;/code&gt; ，其中 &lt;code&gt;preorder&lt;/code&gt; 是二叉树的&lt;strong&gt;先序遍历&lt;/strong&gt;， &lt;code&gt;inorder&lt;/code&gt; 是同一棵树的&lt;strong&gt;中序遍历&lt;/strong&gt;，请构造二叉树并返回其根节点。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/19/tree.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: preorder = [-1], inorder = [-1]
输出: [-1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;看思路后的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：从前序遍历序列的第一个元素确定根节点，然后在中序遍历序列中找到该根节点的位置，其左侧为左子树的中序序列，右侧为右子树的中序序列。接着根据左子树的节点个数，在前序序列中划分出左子树和右子树的前序序列，最后递归地构建左右子树即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func buildTree(preorder []int, inorder []int) *TreeNode {
    if len(preorder) == 0 {
        return nil
    }

    rootVal := preorder[0]
    root := &amp;amp;TreeNode{Val: rootVal}

    var rootIndex int
    for i, v := range inorder {
        if v == rootVal {
            rootIndex = i
            break
        }
    }

    leftinorder := inorder[:rootIndex]
    rightinorder := inorder[rootIndex+1:]

    size := len(leftinorder)
    leftpreorder := preorder[1:size+1]
    rightpreorder := preorder[size+1:]

    root.Left = buildTree(leftpreorder, leftinorder)
    root.Right = buildTree(rightpreorder, rightinorder)

    return root
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ai优化版&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func buildTree(preorder []int, inorder []int) *TreeNode {
    if len(preorder) == 0 {
        return nil
    }

    rootVal := preorder[0]
    root := &amp;amp;TreeNode{Val: rootVal}

    var rootIndex int
    for i, v := range inorder {
        if v == rootVal {
            rootIndex = i
            break 
        }
    }

    leftSize := len(inorder[:rootIndex]) 

    root.Left = buildTree(preorder[1 : 1+leftSize], inorder[:rootIndex])

    root.Right = buildTree(preorder[1+leftSize:], inorder[rootIndex+1:])

    return root
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-106.从中序与后序遍历序列构造二叉树</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-106%E4%BB%8E%E4%B8%AD%E5%BA%8F%E4%B8%8E%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-106%E4%BB%8E%E4%B8%AD%E5%BA%8F%E4%B8%8E%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91/</guid><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/&quot;&gt;&lt;strong&gt;106. 从中序与后序遍历序列构造二叉树&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个整数数组 &lt;code&gt;inorder&lt;/code&gt; 和 &lt;code&gt;postorder&lt;/code&gt; ，其中 &lt;code&gt;inorder&lt;/code&gt; 是二叉树的中序遍历， &lt;code&gt;postorder&lt;/code&gt; 是同一棵树的后序遍历，请你构造并返回这颗 &lt;em&gt;二叉树&lt;/em&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/19/tree.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出：[3,9,20,null,null,15,7]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：inorder = [-1], postorder = [-1]
输出：[-1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;看思路后的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：与 &lt;a href=&quot;https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/&quot;&gt;&lt;strong&gt;105. 从前序与中序遍历序列构造二叉树&lt;/strong&gt;&lt;/a&gt; 类似，只是储存root的顺序不一样，一个是中左右，一个是左右中&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func buildTree(inorder []int, postorder []int) *TreeNode {
    if len(inorder) == 0 {
        return nil
    }

    nodeVal := postorder[len(postorder)-1]
    node := &amp;amp;TreeNode{Val: nodeVal}

    var nodeIndex int
    for i, v := range inorder {
        if v == nodeVal {
            nodeIndex = i
            break
        }
    }

    leftinorder := inorder[:nodeIndex]
    rightinorder := inorder[nodeIndex+1:]

    size := len(leftinorder)
    leftpostorder := postorder[:size]
    rightpostorder := postorder[size:len(postorder)-1]

    node.Left = buildTree(leftinorder, leftpostorder)
    node.Right = buildTree(rightinorder, rightpostorder)

    return node
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-112.路径总和</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-112%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-112%E8%B7%AF%E5%BE%84%E6%80%BB%E5%92%8C/</guid><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/path-sum/&quot;&gt;&lt;strong&gt;112. 路径总和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你二叉树的根节点 &lt;code&gt;root&lt;/code&gt; 和一个表示目标和的整数 &lt;code&gt;targetSum&lt;/code&gt; 。判断该树中是否存在 &lt;strong&gt;根节点到叶子节点&lt;/strong&gt; 的路径，这条路径上所有节点值相加等于目标和 &lt;code&gt;targetSum&lt;/code&gt; 。如果存在，返回 &lt;code&gt;true&lt;/code&gt; ；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;叶子节点&lt;/strong&gt; 是指没有子节点的节点。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/18/pathsum1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出：true
解释：等于目标和的根节点到叶节点路径如上图所示。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/18/pathsum2.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,3], targetSum = 5
输出：false
解释：树中存在两条根节点到叶子节点的路径：
(1 --&amp;gt; 2): 和为 3
(1 --&amp;gt; 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [], targetSum = 0
输出：false
解释：由于树是空的，所以不存在根节点到叶子节点的路径。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：毕竟是简单题，这题其实不难，只需要注意一下叶子的边界即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func hasPathSum(root *TreeNode, targetSum int) bool {
    if root == nil {
        return false
    }

    if root.Left == nil &amp;amp;&amp;amp; root.Right == nil {
        return root.Val == targetSum
    }

    targetSum =  targetSum - root.Val
    left := hasPathSum(root.Left, targetSum)
    right := hasPathSum(root.Right, targetSum)

    return left || right
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-235.二叉搜索树的最近公共祖先</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-235%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-235%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/</guid><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/&quot;&gt;&lt;strong&gt;235. 二叉搜索树的最近公共祖先&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://baike.baidu.com/item/%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/8918834?fr=aladdin&quot;&gt;百度百科&lt;/a&gt;中最近公共祖先的定义为：“对于有根树 T 的两个结点 p、q，最近公共祖先表示为一个结点 x，满足 x 是 p、q 的祖先且 x 的深度尽可能大（&lt;strong&gt;一个节点也可以是它自己的祖先&lt;/strong&gt;）。”&lt;/p&gt;
&lt;p&gt;例如，给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/14/binarysearchtree_improved.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：与 &lt;a href=&quot;https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/&quot;&gt;&lt;strong&gt;236. 二叉树的最近公共祖先&lt;/strong&gt;&lt;/a&gt; 不同，这里可以直接判断&lt;code&gt;root&lt;/code&gt;和&lt;code&gt;p&lt;/code&gt;、&lt;code&gt;q&lt;/code&gt;的大小，前序遍历，直接向下俯冲，第一个在&lt;code&gt;p&lt;/code&gt; 和 &lt;code&gt;q&lt;/code&gt; 之间，就是最近公共祖先&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val   int
 *     Left  *TreeNode
 *     Right *TreeNode
 * }
 */

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
	if root == nil {
        return root
    }
    
    if p.Val &amp;lt; root.Val &amp;amp;&amp;amp; q.Val &amp;lt; root.Val {
        return lowestCommonAncestor(root.Left, p, q)
    }else if p.Val &amp;gt; root.Val &amp;amp;&amp;amp; q.Val &amp;gt; root.Val {
        return lowestCommonAncestor(root.Right, p, q)
    }else {
        return root
    } 
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-236.二叉树的最近公共祖先</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-236%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-236%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/</guid><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/&quot;&gt;&lt;strong&gt;236. 二叉树的最近公共祖先&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://baike.baidu.com/item/%E6%9C%80%E8%BF%91%E5%85%AC%E5%85%B1%E7%A5%96%E5%85%88/8918834?fr=aladdin&quot;&gt;百度百科&lt;/a&gt;中最近公共祖先的定义为：“对于有根树 T 的两个节点 p、q，最近公共祖先表示为一个节点 x，满足 x 是 p、q 的祖先且 x 的深度尽可能大（&lt;strong&gt;一个节点也可以是它自己的祖先&lt;/strong&gt;）。”&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2018/12/14/binarytree.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出：3
解释：节点 5 和节点 1 的最近公共祖先是节点 3 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2018/12/14/binarytree.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出：5
解释：节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2], p = 1, q = 2
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    if root == nil || root == p || root == q {
        return root
    }

    left := lowestCommonAncestor(root.Left, p, q)
    right := lowestCommonAncestor(root.Right, p, q)

    if left != nil &amp;amp;&amp;amp; right != nil {
        return root
    }else if left != nil &amp;amp;&amp;amp; right == nil {
        return left
    }else if left == nil &amp;amp;&amp;amp; right != nil {
        return right
    }else {
        return nil
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>第二周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-16-weekly2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-16-weekly2/</guid><pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这周就是在刷力扣，刷了29道题，其中hot100有23道题，从链表到二叉树，二叉树的递归一开始感觉很不适、黑盒思维，现在还是领悟了一点，自己也能主动完成一道中等题了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;刷力扣&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;刷力扣&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>LeetCode-114.二叉树展开为链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-114%E4%BA%8C%E5%8F%89%E6%A0%91%E5%B1%95%E5%BC%80%E4%B8%BA%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-114%E4%BA%8C%E5%8F%89%E6%A0%91%E5%B1%95%E5%BC%80%E4%B8%BA%E9%93%BE%E8%A1%A8/</guid><pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/&quot;&gt;&lt;strong&gt;114. 二叉树展开为链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你二叉树的根结点 &lt;code&gt;root&lt;/code&gt; ，请你将它展开为一个单链表：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;展开后的单链表应该同样使用 &lt;code&gt;TreeNode&lt;/code&gt; ，其中 &lt;code&gt;right&lt;/code&gt; 子指针指向链表中下一个结点，而左子指针始终为 &lt;code&gt;null&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;展开后的单链表应该与二叉树 &lt;a href=&quot;https://baike.baidu.com/item/%E5%85%88%E5%BA%8F%E9%81%8D%E5%8E%86/6442839?fr=aladdin&quot;&gt;&lt;strong&gt;先序遍历&lt;/strong&gt;&lt;/a&gt; 顺序相同。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/14/flaten.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,5,3,4,null,6]
输出：[1,null,2,null,3,null,4,null,5,null,6]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [0]
输出：[0]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：前序遍历+切片存储&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func flatten(root *TreeNode)  {
    res := []*TreeNode{}

    var preorder func(*TreeNode)
    preorder = func(node *TreeNode) {
        if node == nil {
            return
        }
        
        res = append(res,node)
        preorder(node.Left)
        preorder(node.Right)
    }
    preorder(root)

    for i := 0; i &amp;lt; len(res)-1; i++ {
        res[i].Right = res[i+1]
        res[i].Left = nil
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;O(1)的方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：如果我们直接在正常的“前序遍历（中左右）”里去改指针，会遇到一个致命问题： 当你站在根节点（中），把 &lt;code&gt;node.Right&lt;/code&gt; 指向了左孩子之后，&lt;strong&gt;你原本的右孩子就彻底“失联”了&lt;/strong&gt;，后面的递归根本找不到右子树在哪。所以，我们需要反过来处理，使其逻辑相反&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func flatten(root *TreeNode)  {
    var pre *TreeNode

    var traverse func(*TreeNode)
    traverse = func(node *TreeNode) {
        if node == nil {
            return
        }

        traverse(node.Right)

        traverse(node.Left)

        node.Right = pre
        node.Left = nil
        pre = node
    }

    traverse(root)
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-230.二叉搜索树中第 K 小的元素</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-230%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%AC%AC-k-%E5%B0%8F%E7%9A%84%E5%85%83%E7%B4%A0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-230%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%AC%AC-k-%E5%B0%8F%E7%9A%84%E5%85%83%E7%B4%A0/</guid><pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/kth-smallest-element-in-a-bst/&quot;&gt;&lt;strong&gt;230. 二叉搜索树中第 K 小的元素&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个二叉搜索树的根节点 &lt;code&gt;root&lt;/code&gt; ，和一个整数 &lt;code&gt;k&lt;/code&gt; ，请你设计一个算法查找其中第 &lt;code&gt;k&lt;/code&gt; 小的元素（&lt;code&gt;k&lt;/code&gt; 从 1 开始计数）。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/28/kthtree1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [3,1,4,null,2], k = 1
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/01/28/kthtree2.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [5,3,6,2,4,null,null,1], k = 3
输出：3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：只要知道二叉搜索树进行中序遍历，得到的结果一定是一个「严格递增」的有序序列就很简单了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func kthSmallest(root *TreeNode, k int) int {
    res := []int{}

    var inorder func(*TreeNode)
    inorder = func(node *TreeNode){
        if node == nil {
            return 
        }

        inorder(node.Left)

        res = append(res, node.Val)

        inorder(node.Right)
    }

    inorder(root)
    return res[k-1]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-101.对称二叉树</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-101%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-101%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91/</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/symmetric-tree/&quot;&gt;&lt;strong&gt;101. 对称二叉树&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ， 检查它是否轴对称。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.leetcode.cn/1698026966-JDYPDU-image.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,2,3,4,4,3]
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://pic.leetcode.cn/1698027008-nPFLbM-image.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,2,null,3,null,3]
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;这道题我们需要操纵两个节点，所以我们需要另起一个辅助函数，而不是像前几道用原本的函数。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在写这段代码的终止条件时，逻辑顺序非常重要。 我们必须&lt;strong&gt;先处理节点为空的情况&lt;/strong&gt;，&lt;strong&gt;再处理节点不为空但值不相等的情况&lt;/strong&gt;。如果你先把 &lt;code&gt;left.Val != right.Val&lt;/code&gt; 写在前面，一旦传入的是空指针，程序直接就 Panic了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func isSymmetric(root *TreeNode) bool {
    if root == nil {
        return true
    }

    return compare(root.Left, root.Right)
}

func compare(left, right *TreeNode) bool {
    if left == nil &amp;amp;&amp;amp; right == nil {
        return true
    }else if left == nil &amp;amp;&amp;amp; right != nil {
        return false
    }else if left != nil &amp;amp;&amp;amp; right == nil {
        return false
    }else if left.Val != right.Val {
        return false
    }

    outside := compare(left.Left, right.Right)
    inside := compare(left.Right, right.Left)

    return outside &amp;amp;&amp;amp; inside       
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-102.二叉树的层序遍历</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-102%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E5%BA%8F%E9%81%8D%E5%8E%86/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-102%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E5%BA%8F%E9%81%8D%E5%8E%86/</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-level-order-traversal/&quot;&gt;&lt;strong&gt;102. 二叉树的层序遍历&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ，返回其节点值的 &lt;strong&gt;层序遍历&lt;/strong&gt; 。 （即逐层地，从左到右访问所有节点）。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/19/tree1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [3,9,20,null,null,15,7]
输出：[[3],[9,20],[15,7]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1]
输出：[[1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;BFS?的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;初识层序遍历，与之前的一直递归不太一样。感觉是个挺好用的模版&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：用切片来模拟队列&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func levelOrder(root *TreeNode) [][]int {
    res := [][]int{}
    if root == nil {
        return res
    }

    queue := []*TreeNode{root}
    for len(queue) &amp;gt; 0 {
        size := len(queue)
        level := []int{}
        for i := 0; i &amp;lt; size; i++ {
            node := queue[0]
            queue = queue[1:]
            level = append(level, node.Val)

            if node.Left != nil {
                queue = append(queue, node.Left)
            }

            if node.Right != nil {
                queue = append(queue, node.Right)
            }
        }
        res = append(res, level)
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-107.二叉树的层序遍历 II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-107%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E5%BA%8F%E9%81%8D%E5%8E%86-ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-107%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E5%BA%8F%E9%81%8D%E5%8E%86-ii/</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/&quot;&gt;&lt;strong&gt;107. 二叉树的层序遍历 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ，返回其节点值 &lt;strong&gt;自底向上的层序遍历&lt;/strong&gt; 。 （即按从叶子节点所在层到根节点所在的层，逐层从左向右遍历）&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/19/tree1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [3,9,20,null,null,15,7]
输出：[[15,7],[9,20],[3]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1]
输出：[[1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-level-order-traversal/&quot;&gt;&lt;strong&gt;102. 二叉树的层序遍历&lt;/strong&gt;&lt;/a&gt;+反转即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func levelOrderBottom(root *TreeNode) [][]int {
    res := [][]int{}
    if root == nil {
        return res
    }

    queue := []*TreeNode{root}
    for len(queue) &amp;gt; 0 {
        size := len(queue)
        level := []int{}
        for i := 0; i &amp;lt; size; i++ {
            node := queue[0]
            queue = queue[1:]
            level = append(level, node.Val)

            if node.Left != nil {
                queue = append(queue, node.Left)
            }

            if node.Right != nil {
                queue = append(queue, node.Right)
            }
        }
        res = append(res, level)
    }

    for i := 0; i &amp;lt; len(res)/2; i++ {
        res[i], res[len(res)-1-i] = res[len(res)-1-i], res[i]
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-108.将有序数组转换为二叉搜索树</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-108%E5%B0%86%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E8%BD%AC%E6%8D%A2%E4%B8%BA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-108%E5%B0%86%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E8%BD%AC%E6%8D%A2%E4%B8%BA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91/</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/&quot;&gt;&lt;strong&gt;108. 将有序数组转换为二叉搜索树&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，其中元素已经按 &lt;strong&gt;升序&lt;/strong&gt; 排列，请你将其转换为一棵 平衡 二叉搜索树。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/18/btree1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [-10,-3,0,5,9]
输出：[0,-3,9,-10,null,5]
解释：[0,-10,5,null,-3,null,9] 也将被视为正确答案：
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/18/btree.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,3]
输出：[3,1]
解释：[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func sortedArrayToBST(nums []int) *TreeNode {
    if len(nums) == 0 {
        return nil
    }

    mid := len(nums)/2

    root := &amp;amp;TreeNode{Val: nums[mid]}

    root.Left = sortedArrayToBST(nums[:mid])
    root.Right = sortedArrayToBST(nums[mid+1:])

    return root
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-199.二叉树的右视图</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-199%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%8F%B3%E8%A7%86%E5%9B%BE/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-199%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%8F%B3%E8%A7%86%E5%9B%BE/</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-right-side-view/&quot;&gt;&lt;strong&gt;199. 二叉树的右视图&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个二叉树的 &lt;strong&gt;根节点&lt;/strong&gt; &lt;code&gt;root&lt;/code&gt;，想象自己站在它的右侧，按照从顶部到底部的顺序，返回从右侧所能看到的节点值。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**root = [1,2,3,null,5,null,4]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出：&lt;/strong&gt;[1,3,4]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解释：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2024/11/24/tmpd5jn43fs-1.png&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**root = [1,2,3,4,null,null,null,5]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出：&lt;/strong&gt;[1,3,4,5]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解释：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2024/11/24/tmpkpe40xeh-1.png&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**root = [1,null,3]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出：&lt;/strong&gt;[1,3]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 4：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**输入：**root = []&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出：&lt;/strong&gt;[]&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-level-order-traversal/&quot;&gt;&lt;strong&gt;102. 二叉树的层序遍历&lt;/strong&gt;&lt;/a&gt;+修改几个参数 即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func rightSideView(root *TreeNode) []int {
    res := []int{}
    if root == nil {
        return res
    }

    queue := []*TreeNode{root}
    for len(queue) &amp;gt; 0 {
        size := len(queue)
        level := []int{}
        for i := 0; i &amp;lt; size; i++ {
            node := queue[0]
            queue = queue[1:]
            level = append(level, node.Val)

            if node.Right != nil {
                queue = append(queue, node.Right)
            }

            if node.Left != nil {
                queue = append(queue, node.Left)
            }
        }
        res = append(res, level[0])
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-543.二叉树的直径</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-543%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E7%9B%B4%E5%BE%84/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-543%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E7%9B%B4%E5%BE%84/</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/diameter-of-binary-tree/&quot;&gt;&lt;strong&gt;543. 二叉树的直径&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一棵二叉树的根节点，返回该树的 &lt;strong&gt;直径&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;二叉树的 &lt;strong&gt;直径&lt;/strong&gt; 是指树中任意两个节点之间最长路径的 &lt;strong&gt;长度&lt;/strong&gt; 。这条路径可能经过也可能不经过根节点 &lt;code&gt;root&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;两节点之间路径的 &lt;strong&gt;长度&lt;/strong&gt; 由它们之间边数表示。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/06/diamtree.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,3,4,5]
输出：3
解释：3 ，取路径 [4,2,1,3] 或 [5,2,1,3] 的长度。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2]
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：可以认为是 所有节点中左右子树的深度和的最大值 or 不经过根节点的最大值&lt;/p&gt;
&lt;p&gt;所以在求&lt;code&gt;maxDepth&lt;/code&gt;时，维护一个全局的最大值&lt;code&gt;maxDiameter&lt;/code&gt;即可，存储到达跟节点前的最大值&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func diameterOfBinaryTree(root *TreeNode) int {
    if root == nil {
        return 0
    }
    maxDiameter := 0
    
    var maxDepth func(*TreeNode) int
    maxDepth = func(root *TreeNode) int {
        if root == nil {
            return 0
        }

        leftHeight := maxDepth(root.Left)
        rightHeight := maxDepth(root.Right)

        if leftHeight + rightHeight &amp;gt; maxDiameter {
            maxDiameter = leftHeight + rightHeight
        }
    
        return max(leftHeight, rightHeight) + 1
    }
    maxDepth(root)

    return maxDiameter
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-98.验证二叉搜索树</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-98%E9%AA%8C%E8%AF%81%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-98%E9%AA%8C%E8%AF%81%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91/</guid><pubDate>Sun, 15 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/validate-binary-search-tree/&quot;&gt;&lt;strong&gt;98. 验证二叉搜索树&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ，判断其是否是一个有效的二叉搜索树。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;有效&lt;/strong&gt; 二叉搜索树定义如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;节点的左子树只包含 &lt;strong&gt;严格小于&lt;/strong&gt; 当前节点的数。&lt;/li&gt;
&lt;li&gt;节点的右子树只包含 &lt;strong&gt;严格大于&lt;/strong&gt; 当前节点的数。&lt;/li&gt;
&lt;li&gt;所有左子树和右子树自身必须也是二叉搜索树。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/12/01/tree1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [2,1,3]
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/12/01/tree2.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:50%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [5,1,4,null,null,3,6]
输出：false
解释：根节点的值是 5 ，但是右子节点的值是 4 。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：从题目中可以看到二叉搜索树定义，&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;其中&lt;code&gt;isValidBST&lt;/code&gt;的递归，能够保证所有左子树和右子树自身必须也是二叉搜索树。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;所以，我们只需要保证，本身的节点的大小能够比左边最大的大，比右边最小的小即可&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我就是再来个递归获取最大和最小值&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func isValidBST(root *TreeNode) bool {
    if root == nil {
        return true
    }

    left := isValidBST(root.Left)
    leftmax := findmax(root.Left)

    right := isValidBST(root.Right)
    rightmin := findmin(root.Right)

    if leftmax != nil &amp;amp;&amp;amp; rightmin != nil {
        if leftmax.Val &amp;gt;= root.Val || root.Val &amp;gt;= rightmin.Val {
            return false
        }
    }else if leftmax == nil &amp;amp;&amp;amp; rightmin != nil {
        if root.Val &amp;gt;= rightmin.Val {
            return false
        }
    }else if leftmax != nil &amp;amp;&amp;amp; rightmin == nil {
        if root.Val &amp;lt;= leftmax.Val {
            return false
        }
    }

    return left &amp;amp;&amp;amp; right
}

func findmax(root *TreeNode) *TreeNode {
    if root == nil {
        return nil
    } 

    if root.Right == nil {
        return root
    }

    return findmax(root.Right)
}

func findmin(root *TreeNode) *TreeNode {
    if root == nil {
        return nil
    } 

    if root.Left == nil {
        return root
    }

    return findmin(root.Left)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;设定上下边界法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：给我的方法优化了一下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func isValidBST(root *TreeNode) bool {
    return validate(root, math.MinInt, math.MaxInt)
}

func validate(node *TreeNode, min, max int) bool {
    if node == nil {
        return true
    }

    if node.Val &amp;lt;= min || node.Val &amp;gt;= max {
        return false
    }

    leftValid := validate(node.Left, min, node.Val)
    
    rightValid := validate(node.Right, node.Val, max)

    return leftValid &amp;amp;&amp;amp; rightValid
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;中序遍历法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：二叉搜索树进行中序遍历，得到的结果一定是一个「严格递增」的有序序列&lt;/p&gt;
&lt;p&gt;所以只需要进行中序遍历，再比较大小即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func isValidBST(root *TreeNode) bool {
    preVal := math.MinInt 
    
    var inorder func(*TreeNode) bool
    inorder = func(node *TreeNode) bool {
        if node == nil {
            return true
        }

        leftValid := inorder(node.Left)

        if node.Val &amp;lt;= preVal {
            return false
        }
        preVal = node.Val 

        rightValid := inorder(node.Right)

        return leftValid &amp;amp;&amp;amp; rightValid
    }

    return inorder(root)
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-104.二叉树的最大深度</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-104%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%A4%A7%E6%B7%B1%E5%BA%A6/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-104%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%A4%A7%E6%B7%B1%E5%BA%A6/</guid><pubDate>Sat, 14 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/maximum-depth-of-binary-tree/&quot;&gt;&lt;strong&gt;104. 二叉树的最大深度&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个二叉树 &lt;code&gt;root&lt;/code&gt; ，返回其最大深度。&lt;/p&gt;
&lt;p&gt;二叉树的 &lt;strong&gt;最大深度&lt;/strong&gt; 是指从根节点到最远叶子节点的最长路径上的节点数。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/11/26/tmp-tree.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [3,9,20,null,null,15,7]
输出：3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,null,2]
输出：2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;递归的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;递归这种题有时候就是很傻逼和神奇，就像这题和汉谟拉比，不同的是这题从逻辑上可以从下往上推出来，汉谟拉比很麻烦&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func maxDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    leftHeight := maxDepth(root.Left)

    rightHeight := maxDepth(root.Right)
    
    return max(leftHeight, rightHeight) + 1
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-111.二叉树的最小深度</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-111%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E6%B7%B1%E5%BA%A6/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-111%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%9C%80%E5%B0%8F%E6%B7%B1%E5%BA%A6/</guid><pubDate>Sat, 14 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/minimum-depth-of-binary-tree/&quot;&gt;&lt;strong&gt;111. 二叉树的最小深度&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个二叉树，找出其最小深度。&lt;/p&gt;
&lt;p&gt;最小深度是从根节点到最近叶子节点的最短路径上的节点数量。&lt;/p&gt;
&lt;p&gt;**说明：**叶子节点是指没有子节点的节点。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/12/ex_depth.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [3,9,20,null,null,15,7]
输出：2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：这题与 &lt;a href=&quot;https://leetcode.cn/problems/minimum-depth-of-binary-tree/&quot;&gt;二叉树的最小深度&lt;/a&gt; 稍有不同，求最小时会面临一个问题：如果一颗树是“偏瘫”的（比如只有左边的，没有右边的），直接用 &lt;code&gt;min(left, right)&lt;/code&gt;，右边的空指针会返回深度 0，导致整棵树算出来的最小深度是 1。&lt;/p&gt;
&lt;p&gt;所以，我们需要&lt;code&gt;if root.Left == nil &amp;amp;&amp;amp; root.Right != nil { ... }&lt;/code&gt; 和
&lt;code&gt;if root.Right == nil &amp;amp;&amp;amp; root.Left != nil { ... }&lt;/code&gt; 去除这些错误&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func minDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }

    if root.Left == nil &amp;amp;&amp;amp; root.Right != nil {
        return minDepth(root.Right) + 1
    }
   
    if root.Right == nil &amp;amp;&amp;amp; root.Left != nil {
        return minDepth(root.Left) + 1
    }
    
    return min(minDepth(root.Left), minDepth(root.Right)) + 1
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-226.翻转二叉树</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-226%E7%BF%BB%E8%BD%AC%E4%BA%8C%E5%8F%89%E6%A0%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/leetcode-226%E7%BF%BB%E8%BD%AC%E4%BA%8C%E5%8F%89%E6%A0%91/</guid><pubDate>Sat, 14 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/invert-binary-tree/&quot;&gt;&lt;strong&gt;226. 翻转二叉树&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一棵二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ，翻转这棵二叉树，并返回其根节点。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/14/invert1-tree.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [4,2,7,1,3,6,9]
输出：[4,7,2,9,6,3,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/14/invert2-tree.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [2,1,3]
输出：[2,3,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;前序遍历&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;改变一下顺序是后序遍历&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func invertTree(root *TreeNode) *TreeNode {
    if root == nil {
        return nil
    }
    
    root.Left, root.Right = root.Right, root.Left

    invertTree(root.Left)
    invertTree(root.Right)

    return root
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>二叉树的三种遍历</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E4%B8%89%E7%A7%8D%E9%81%8D%E5%8E%86/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%BA%8C%E5%8F%89%E6%A0%91/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E4%B8%89%E7%A7%8D%E9%81%8D%E5%8E%86/</guid><pubDate>Sat, 14 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;二叉树&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-preorder-traversal/&quot;&gt;&lt;strong&gt;144. 二叉树的前序遍历&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-inorder-traversal/&quot;&gt;&lt;strong&gt;94. 二叉树的中序遍历&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-postorder-traversal/&quot;&gt;&lt;strong&gt;145. 二叉树的后序遍历&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你二叉树的根节点 &lt;code&gt;root&lt;/code&gt; ，返回它节点值的 &lt;strong&gt;前/中/后序&lt;/strong&gt; 遍历。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2020/09/15/inorder_1.jpg&quot; alt=&quot;img&quot; style=&quot;zoom:67%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,null,2,3]
输出：
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;img src=&quot;https://assets.leetcode.com/uploads/2024/08/29/tree_2.png&quot; alt=&quot;img&quot; style=&quot;zoom:80%;&quot; /&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1,2,3,4,5,null,8,null,null,6,7,9]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 4：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：root = [1]
输出：[1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;前序遍历&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func preorderTraversal(root *TreeNode) []int {
    res := []int{}
    var dfs func(*TreeNode)
    dfs = func(node *TreeNode){
        if node == nil {
            return
        }

        res = append(res, node.Val)
        dfs(node.Left)
        dfs(node.Right)
    }
    dfs(root)

    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;中序遍历&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func inorderTraversal(root *TreeNode) []int {
    res := []int{}
    var dfs func(*TreeNode)
    dfs = func(node *TreeNode) {
        if node == nil {
            return
        }

        dfs(node.Left)
        res = append(res, node.Val)
        dfs(node.Right)
    }
    dfs(root)

    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;后序遍历&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func postorderTraversal(root *TreeNode) []int {
    res := []int{}
    var dfs func(*TreeNode)
    dfs = func(node *TreeNode){
        if node == nil {
            return
        }

        dfs(node.Left)
        dfs(node.Right)
        res = append(res, node.Val)
    }
    dfs(root)

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-146.LRU缓存</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-146lru%E7%BC%93%E5%AD%98/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-146lru%E7%BC%93%E5%AD%98/</guid><pubDate>Fri, 13 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/lru-cache/&quot;&gt;&lt;strong&gt;146. LRU 缓存&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;请你设计并实现一个满足 &lt;a href=&quot;https://baike.baidu.com/item/LRU&quot;&gt;LRU (最近最少使用) 缓存&lt;/a&gt; 约束的数据结构。&lt;/p&gt;
&lt;p&gt;实现 &lt;code&gt;LRUCache&lt;/code&gt; 类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LRUCache(int capacity)&lt;/code&gt; 以 &lt;strong&gt;正整数&lt;/strong&gt; 作为容量 &lt;code&gt;capacity&lt;/code&gt; 初始化 LRU 缓存&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int get(int key)&lt;/code&gt; 如果关键字 &lt;code&gt;key&lt;/code&gt; 存在于缓存中，则返回关键字的值，否则返回 &lt;code&gt;-1&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void put(int key, int value)&lt;/code&gt; 如果关键字 &lt;code&gt;key&lt;/code&gt; 已经存在，则变更其数据值 &lt;code&gt;value&lt;/code&gt; ；如果不存在，则向缓存中插入该组 &lt;code&gt;key-value&lt;/code&gt; 。如果插入操作导致关键字数量超过 &lt;code&gt;capacity&lt;/code&gt; ，则应该 &lt;strong&gt;逐出&lt;/strong&gt; 最久未使用的关键字。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;函数 &lt;code&gt;get&lt;/code&gt; 和 &lt;code&gt;put&lt;/code&gt; 必须以 &lt;code&gt;O(1)&lt;/code&gt; 的平均时间复杂度运行。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入
[&quot;LRUCache&quot;, &quot;put&quot;, &quot;put&quot;, &quot;get&quot;, &quot;put&quot;, &quot;get&quot;, &quot;put&quot;, &quot;get&quot;, &quot;get&quot;, &quot;get&quot;]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]

解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1);    // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废，缓存是 {1=1, 3=3}
lRUCache.get(2);    // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废，缓存是 {4=4, 3=3}
lRUCache.get(1);    // 返回 -1 (未找到)
lRUCache.get(3);    // 返回 3
lRUCache.get(4);    // 返回 4
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：这里用map来存储数据，双向链实现先后性&lt;/p&gt;
&lt;p&gt;这里的难点是很多的指针的操作，所以我们把它化为多个简单的操作(单纯从逻辑上理解是不难的)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;removeNode(node)&lt;/code&gt;&lt;/strong&gt;: 把某个节点从链表里抠出来。&lt;/p&gt;
&lt;p&gt;让它前一个节点的 &lt;code&gt;next&lt;/code&gt; 绕过它，指向它的后一个节点。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​	让它后一个节点的 &lt;code&gt;prev&lt;/code&gt; 绕过它，指向它的前一个节点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;addToHead(node)&lt;/code&gt;&lt;/strong&gt;: 将节点插入到虚拟头节点之后（代表变成了最新使用的数据）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;moveToHead(node)&lt;/code&gt;&lt;/strong&gt;:  = 先 &lt;code&gt;removeNode&lt;/code&gt; (把它从原位置抠出来) + 再 &lt;code&gt;addToHead&lt;/code&gt; (放到最前面)。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;removeTail()&lt;/code&gt;&lt;/strong&gt;: 找到最没用的那个节点（就是 &lt;code&gt;tail.prev&lt;/code&gt;，虚拟尾节点的前一个），把它 &lt;code&gt;removeNode&lt;/code&gt; 抠出来，并返回这个节点（为了后面能在哈希表里删掉它的 key）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;type DLinkedNode struct {
   key, val int
   pre, next *DLinkedNode
}

type LRUCache struct {
    capacity int
    cache map[int]*DLinkedNode
    head *DLinkedNode
    tail *DLinkedNode
}

func Constructor(capacity int) LRUCache {
    l := LRUCache{
        capacity: capacity,
        cache: map[int]*DLinkedNode{},
        head: &amp;amp;DLinkedNode{},
        tail: &amp;amp;DLinkedNode{},
    }

    l.head.next = l.tail
    l.tail.pre = l.head

    return l
}


func (this *LRUCache) Get(key int) int {
    if node, ok := this.cache[key]; ok {
        this.removeNode(node)
        this.addToHead(node)

        return node.val
    }else {
        return -1
    }
}


func (this *LRUCache) Put(key int, value int) {
    if node, ok := this.cache[key]; ok {
        node.val = value
        this.removeNode(node)
        this.addToHead(node)
    }else {
        node := &amp;amp;DLinkedNode {
            key: key,
            val: value,
        }
        this.cache[key] = node
        this.addToHead(node)

        if len(this.cache) &amp;gt; this.capacity {
            node := this.removeTail()
            delete(this.cache, node.key)
        }
    }
}

func (this *LRUCache) removeNode(node *DLinkedNode) {
    node.pre.next = node.next
    node.next.pre = node.pre
}

func (this *LRUCache) addToHead(node *DLinkedNode) {
    node.pre = this.head
    node.next = this.head.next
    this.head.next.pre = node
    this.head.next = node
}

func (this *LRUCache) removeTail() *DLinkedNode {
    node := this.tail.pre
    node.pre.next = this.tail
    this.tail.pre = node.pre
    return node
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-148.排序链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-148%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-148%E6%8E%92%E5%BA%8F%E9%93%BE%E8%A1%A8/</guid><pubDate>Thu, 12 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/sort-list/&quot;&gt;&lt;strong&gt;148. 排序链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你链表的头结点 &lt;code&gt;head&lt;/code&gt; ，请将其按 &lt;strong&gt;升序&lt;/strong&gt; 排列并返回 &lt;strong&gt;排序后的链表&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/09/14/sort_list_1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [4,2,1,3]
输出：[1,2,3,4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/09/14/sort_list_2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [-1,5,3,4,0]
输出：[-1,0,3,4,5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;归并排序的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;很神奇&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：这个问题就是用归并排序解决的，这里可以分为两部分1.分解 和 2. 合成。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;分解为一个个链表，依靠快慢指针和递归，直到触发&lt;code&gt;if head == nil || head.Next == nil {}&lt;/code&gt;返回一个链表&lt;/li&gt;
&lt;li&gt;就是 &lt;a href=&quot;https://leetcode.cn/problems/merge-two-sorted-lists/&quot;&gt;&lt;strong&gt;21. 合并两个有序链表&lt;/strong&gt;&lt;/a&gt; 的写法&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ps: 这个代码的递归的逻辑很像中间件的洋葱模型，返回一个链表后，再不断地&lt;code&gt;return mergeTwoLists(left, right)&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func sortList(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }

    slow, fast := head, head.Next
    for fast != nil &amp;amp;&amp;amp; fast.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
    }

    mid := slow.Next 
    slow.Next = nil  

    left := sortList(head)
    right := sortList(mid)

    return mergeTwoLists(left, right)
}

func mergeTwoLists(list1, list2 *ListNode) *ListNode {
    dummy := &amp;amp;ListNode{}
    cur := dummy

    for list1 != nil &amp;amp;&amp;amp; list2 != nil {
        if list1.Val &amp;lt; list2.Val {
            cur.Next = list1
            list1 = list1.Next
        } else {
            cur.Next = list2
            list2 = list2.Next
        }
        cur = cur.Next
    }

    if list1 != nil {
        cur.Next = list1
    } else {
        cur.Next = list2
    }

    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-23.合并 K 个升序链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-23%E5%90%88%E5%B9%B6-k-%E4%B8%AA%E5%8D%87%E5%BA%8F%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-23%E5%90%88%E5%B9%B6-k-%E4%B8%AA%E5%8D%87%E5%BA%8F%E9%93%BE%E8%A1%A8/</guid><pubDate>Thu, 12 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/merge-k-sorted-lists/&quot;&gt;&lt;strong&gt;23. 合并 K 个升序链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个链表数组，每个链表都已经按升序排列。&lt;/p&gt;
&lt;p&gt;请你将所有链表合并到一个升序链表中，返回合并后的链表。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：lists = [[1,4,5],[1,3,4],[2,6]]
输出：[1,1,2,3,4,4,5,6]
解释：链表数组如下：
[
  1-&amp;gt;4-&amp;gt;5,
  1-&amp;gt;3-&amp;gt;4,
  2-&amp;gt;6
]
将它们合并到一个有序链表中得到。
1-&amp;gt;1-&amp;gt;2-&amp;gt;3-&amp;gt;4-&amp;gt;4-&amp;gt;5-&amp;gt;6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：lists = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：lists = [[]]
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法(照抄148. 排序链表)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;也算是手撕吧...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func mergeKLists(lists []*ListNode) *ListNode {
    filtered := make([]*ListNode, 0, len(lists))
    for _, l := range lists {
        if l != nil {
            filtered = append(filtered, l)
        }
    }
    if len(filtered) == 0 {
        return nil
    }
    if len(filtered) == 1 {
        return filtered[0]
    }

    for i := 0; i &amp;lt; len(filtered)-1; i++ {
        cur := filtered[i]
        for cur.Next != nil {
            cur = cur.Next
        }
        cur.Next = filtered[i+1]
    }

    return sortList(filtered[0])
}

func sortList(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }

    slow, fast := head, head.Next
    for fast != nil &amp;amp;&amp;amp; fast.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
    }

    mid := slow.Next 
    slow.Next = nil  

    left := sortList(head)
    right := sortList(mid)

    return mergeTwoLists(left, right)
}

func mergeTwoLists(list1, list2 *ListNode) *ListNode {
    dummy := &amp;amp;ListNode{}
    cur := dummy

    for list1 != nil &amp;amp;&amp;amp; list2 != nil {
        if list1.Val &amp;lt; list2.Val {
            cur.Next = list1
            list1 = list1.Next
        } else {
            cur.Next = list2
            list2 = list2.Next
        }
        cur = cur.Next
    }

    if list1 != nil {
        cur.Next = list1
    } else {
        cur.Next = list2
    }

    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;更合适的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：这里的思路与 &lt;a href=&quot;https://leetcode.cn/problems/sort-list/&quot;&gt;&lt;strong&gt;148. 排序链表&lt;/strong&gt;&lt;/a&gt; 稍有不同，上一题是把一个链表化为多个长度为一的链表，这里&lt;code&gt;lists&lt;/code&gt;我们把切片的每一个元素提取，所以需要&lt;code&gt;divideAndMerge&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;其中，&lt;code&gt;divideAndMerge&lt;/code&gt;本质就是对一串数字进行操作，如果只剩一个数字，就进行&lt;code&gt;mergeTwoLists&lt;/code&gt;,后面的逻辑就是和排序链表差不多了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func mergeKLists(lists []*ListNode) *ListNode {
    if len(lists) == 0 {
        return nil
    }
    return divideAndMerge(lists, 0, len(lists)-1)
}

func divideAndMerge(lists []*ListNode, left, right int) *ListNode {
    if left == right {
        return lists[left]
    }
    
    mid := left + (right - left) / 2
    
    l1 := divideAndMerge(lists, left, mid)
    l2 := divideAndMerge(lists, mid+1, right)
    
    return mergeTwoLists(l1, l2)
}

func mergeTwoLists(list1, list2 *ListNode) *ListNode {
    dummy := &amp;amp;ListNode{}
    cur := dummy
    
    for list1 != nil &amp;amp;&amp;amp; list2 != nil {
        if list1.Val &amp;lt; list2.Val {
            cur.Next = list1
            list1 = list1.Next
        } else {
            cur.Next = list2
            list2 = list2.Next
        }
        cur = cur.Next
    }
    if list1 != nil {
        cur.Next = list1
    } else {
        cur.Next = list2
    }
    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-138.随机链表的复制</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-138%E9%9A%8F%E6%9C%BA%E9%93%BE%E8%A1%A8%E7%9A%84%E5%A4%8D%E5%88%B6/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-138%E9%9A%8F%E6%9C%BA%E9%93%BE%E8%A1%A8%E7%9A%84%E5%A4%8D%E5%88%B6/</guid><pubDate>Wed, 11 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;链表&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/copy-list-with-random-pointer/&quot;&gt;&lt;strong&gt;138. 随机链表的复制&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个长度为 &lt;code&gt;n&lt;/code&gt; 的链表，每个节点包含一个额外增加的随机指针 &lt;code&gt;random&lt;/code&gt; ，该指针可以指向链表中的任何节点或空节点。&lt;/p&gt;
&lt;p&gt;构造这个链表的 &lt;strong&gt;&lt;a href=&quot;https://baike.baidu.com/item/%E6%B7%B1%E6%8B%B7%E8%B4%9D/22785317?fr=aladdin&quot;&gt;深拷贝&lt;/a&gt;&lt;/strong&gt;。 深拷贝应该正好由 &lt;code&gt;n&lt;/code&gt; 个 &lt;strong&gt;全新&lt;/strong&gt; 节点组成，其中每个新节点的值都设为其对应的原节点的值。新节点的 &lt;code&gt;next&lt;/code&gt; 指针和 &lt;code&gt;random&lt;/code&gt; 指针也都应指向复制链表中的新节点，并使原链表和复制链表中的这些指针能够表示相同的链表状态。&lt;strong&gt;复制链表中的指针都不应指向原链表中的节点&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;例如，如果原链表中有 &lt;code&gt;X&lt;/code&gt; 和 &lt;code&gt;Y&lt;/code&gt; 两个节点，其中 &lt;code&gt;X.random --&amp;gt; Y&lt;/code&gt; 。那么在复制链表中对应的两个节点 &lt;code&gt;x&lt;/code&gt; 和 &lt;code&gt;y&lt;/code&gt; ，同样有 &lt;code&gt;x.random --&amp;gt; y&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;返回复制链表的头节点。&lt;/p&gt;
&lt;p&gt;用一个由 &lt;code&gt;n&lt;/code&gt; 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 &lt;code&gt;[val, random_index]&lt;/code&gt; 表示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;val&lt;/code&gt;：一个表示 &lt;code&gt;Node.val&lt;/code&gt; 的整数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;random_index&lt;/code&gt;：随机指针指向的节点索引（范围从 &lt;code&gt;0&lt;/code&gt; 到 &lt;code&gt;n-1&lt;/code&gt;）；如果不指向任何节点，则为 &lt;code&gt;null&lt;/code&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你的代码 &lt;strong&gt;只&lt;/strong&gt; 接受原链表的头节点 &lt;code&gt;head&lt;/code&gt; 作为传入参数。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2020/01/09/e1.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出：[[7,null],[13,0],[11,4],[10,2],[1,0]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2020/01/09/e2.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [[1,1],[2,1]]
输出：[[1,1],[2,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2020/01/09/e3.png&quot; alt=&quot;img&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [[3,null],[3,0],[3,null]]
输出：[[3,null],[3,0],[3,null]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法(哈希)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for a Node.
 * type Node struct {
 *     Val int
 *     Next *Node
 *     Random *Node
 * }
 */

func copyRandomList(head *Node) *Node {
    if head == nil {
        return nil
    }

    cur := head
    m := make(map[*Node]*Node)
    for cur != nil {
        newNode := &amp;amp;Node{Val: cur.Val}
        m[cur] = newNode
        cur = cur.Next
    }

    cur = head
    for cur != nil {
        node := m[cur]
        if cur.Next != nil {
            node.Next = m[cur.Next]
        }else {
            node.Next = nil
        }
        
        if cur.Random != nil {
            node.Random = m[cur.Random]
        }else {
            node.Random = nil
        }
        cur = cur.Next
    }

    return m[head]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-2.两数相加</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-2%E4%B8%A4%E6%95%B0%E7%9B%B8%E5%8A%A0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-2%E4%B8%A4%E6%95%B0%E7%9B%B8%E5%8A%A0/</guid><pubDate>Wed, 11 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/add-two-numbers/&quot;&gt;&lt;strong&gt;2. 两数相加&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你两个 &lt;strong&gt;非空&lt;/strong&gt; 的链表，表示两个非负的整数。它们每位数字都是按照 &lt;strong&gt;逆序&lt;/strong&gt; 的方式存储的，并且每个节点只能存储 &lt;strong&gt;一位&lt;/strong&gt; 数字。&lt;/p&gt;
&lt;p&gt;请你将两个数相加，并以相同形式返回一个表示和的链表。&lt;/p&gt;
&lt;p&gt;你可以假设除了数字 0 之外，这两个数都不会以 0 开头。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2021/01/02/addtwonumber1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：l1 = [2,4,3], l2 = [5,6,4]
输出：[7,0,8]
解释：342 + 465 = 807.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：l1 = [0], l2 = [0]
输出：[0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出：[8,9,9,9,0,0,0,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，链表的第一题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
    dummy := &amp;amp;ListNode{}
    cur := dummy
    carry := 0  
    
    for l1 != nil || l2 != nil || carry != 0 {
        n1, n2 := 0, 0
        
        if l1 != nil {
            n1 = l1.Val
            l1 = l1.Next
        }

        if l2 != nil {
            n2 = l2.Val
            l2 = l2.Next
        }

        sum := n1 + n2 + carry
        num := sum % 10
        carry = sum / 10

        cur.Next = &amp;amp;ListNode{Val: num}
        cur = cur.Next
    }
    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-21.合并两个有序链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-21%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%9C%89%E5%BA%8F%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-21%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%9C%89%E5%BA%8F%E9%93%BE%E8%A1%A8/</guid><pubDate>Wed, 11 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/merge-two-sorted-lists/&quot;&gt;&lt;strong&gt;21. 合并两个有序链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个链表的头节点 &lt;code&gt;head&lt;/code&gt; 和一个整数 &lt;code&gt;val&lt;/code&gt; ，请你删除链表中所有满足 &lt;code&gt;Node.val == val&lt;/code&gt; 的节点，并返回 &lt;strong&gt;新的头节点&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;将两个升序链表合并为一个新的 &lt;strong&gt;升序&lt;/strong&gt; 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/03/merge_ex1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：l1 = [1,2,4], l2 = [1,3,4]
输出：[1,1,2,3,4,4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：l1 = [], l2 = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：l1 = [], l2 = [0]
输出：[0]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
    dummy := &amp;amp;ListNode{}
    cur := dummy
    if list1 == nil {
        return list2
    }

    if list2 == nil {
        return list1
    }

    for list1 != nil || list2 != nil {
        if list1 == nil {
            cur.Next = list2
            return dummy.Next
        }
        
        if list2 == nil {
            cur.Next = list1
            return dummy.Next
        }

        if list1.Val &amp;lt; list2.Val {
            cur.Next = list1
            cur = cur.Next
            list1 = list1.Next
        }else {
            cur.Next = list2
            cur = cur.Next
            list2 = list2.Next
        }
    }
    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ai润色后&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
    dummy := &amp;amp;ListNode{}
    cur := dummy

    for list1 != nil &amp;amp;&amp;amp; list2 != nil {
        if list1.Val &amp;lt; list2.Val {
            cur.Next = list1
            list1 = list1.Next
        } else {
            cur.Next = list2
            list2 = list2.Next
        }
        cur = cur.Next 
    }

    if list1 != nil {
        cur.Next = list1
    } else {
        cur.Next = list2
    }

    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;递归&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
    if list1 == nil {
        return list2
    }
    if list2 == nil {
        return list1
    }

    if list1.Val &amp;lt; list2.Val {
        list1.Next = mergeTwoLists(list1.Next, list2)
        return list1
    } else {
        list2.Next = mergeTwoLists(list1, list2.Next)
        return list2
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-25.K个一组翻转链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-25k%E4%B8%AA%E4%B8%80%E7%BB%84%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-25k%E4%B8%AA%E4%B8%80%E7%BB%84%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8/</guid><pubDate>Wed, 11 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/reverse-nodes-in-k-group/&quot;&gt;&lt;strong&gt;25. K 个一组翻转链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你链表的头节点 &lt;code&gt;head&lt;/code&gt; ，每 &lt;code&gt;k&lt;/code&gt; 个节点一组进行翻转，请你返回修改后的链表。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;k&lt;/code&gt; 是一个正整数，它的值小于或等于链表的长度。如果节点总数不是 &lt;code&gt;k&lt;/code&gt; 的整数倍，那么请将最后剩余的节点保持原有顺序。&lt;/p&gt;
&lt;p&gt;你不能只是单纯的改变节点内部的值，而是需要实际进行节点交换。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/03/reverse_ex1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2,3,4,5], k = 2
输出：[2,1,4,3,5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/03/reverse_ex2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2,3,4,5], k = 3
输出：[3,2,1,4,5]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;做出来了，哈哈哈！！！我终于做出来了！！！哈哈哈哈！！！困难题！！！哈哈。我太tm牛了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：&lt;a href=&quot;https://leetcode.cn/problems/reverse-linked-list/&quot;&gt;&lt;strong&gt;206. 反转链表&lt;/strong&gt;&lt;/a&gt; 和 &lt;a href=&quot;https://leetcode.cn/problems/swap-nodes-in-pairs/&quot;&gt;&lt;strong&gt;24. 两两交换链表中的节点&lt;/strong&gt;&lt;/a&gt; 的结合&lt;/p&gt;
&lt;p&gt;​	内部（206. 反转链表）+ 外部（24. 两两交换链表 / 节点缝合）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseKGroup(head *ListNode, k int) *ListNode {
    dummy := &amp;amp;ListNode{Next: head}
    pre := dummy
    cur := head
    count := 0

    for cur != nil {
        cur = cur.Next
        count++
    }

    count = count / k
    cur = dummy.Next
    start := dummy

    for i:= 0; i &amp;lt; count; i++ {
        for j:= 0; j &amp;lt; k; j++ {
            next := cur.Next
            cur.Next = pre
            pre = cur
            cur = next
        }
 
        next := start.Next
        start.Next = pre
        next.Next = cur
        start = next
        pre = next
    }
    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;头插法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：我们不把它们拆下来反转，而是永远盯着第一个节点 &lt;code&gt;1&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一步：把 &lt;code&gt;1&lt;/code&gt; 后面的 &lt;code&gt;2&lt;/code&gt; 拔下来，插到最前面：&lt;code&gt;2 -&amp;gt; 1 -&amp;gt; 3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;第二步：把 &lt;code&gt;1&lt;/code&gt; 后面的 &lt;code&gt;3&lt;/code&gt; 拔下来，插到最前面：&lt;code&gt;3 -&amp;gt; 2 -&amp;gt; 1&lt;/code&gt; 反转完成！在这个过程中，&lt;code&gt;1&lt;/code&gt; 永远是这一组的尾巴，它自然而然地连着下一组，&lt;strong&gt;完全不需要额外的“缝合”操作&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;func reverseKGroup(head *ListNode, k int) *ListNode {
    dummy := &amp;amp;ListNode{Next: head}
    pre := dummy 

    count := 0
    cur := head
    for cur != nil {
        count++
        cur = cur.Next
    }

    for count &amp;gt;= k {
        cur = pre.Next 
        
        for i := 1; i &amp;lt; k; i++ {
            next := cur.Next       
            cur.Next = next.Next   
            next.Next = pre.Next   
            pre.Next = next        
        }
        
        pre = cur 
        count -= k 
    }

    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-141.环形链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-141%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-141%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/linked-list-cycle/&quot;&gt;&lt;strong&gt;141. 环形链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个链表的头节点 &lt;code&gt;head&lt;/code&gt; ，判断链表中是否有环。&lt;/p&gt;
&lt;p&gt;如果链表中有某个节点，可以通过连续跟踪 &lt;code&gt;next&lt;/code&gt; 指针再次到达，则链表中存在环。 为了表示给定链表中的环，评测系统内部使用整数 &lt;code&gt;pos&lt;/code&gt; 来表示链表尾连接到链表中的位置（索引从 0 开始）。&lt;strong&gt;注意：&lt;code&gt;pos&lt;/code&gt; 不作为参数进行传递&lt;/strong&gt; 。仅仅是为了标识链表的实际情况。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;如果链表中存在环&lt;/em&gt; ，则返回 &lt;code&gt;true&lt;/code&gt; 。 否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [3,2,0,-4], pos = 1
输出：true
解释：链表中有一个环，其尾部连接到第二个节点。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist_test2.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2], pos = 0
输出：true
解释：链表中有一个环，其尾部连接到第一个节点。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist_test3.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1], pos = -1
输出：false
解释：链表中没有环。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;双指针的解法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func hasCycle(head *ListNode) bool {
    if head == nil {
        return false
    }

    slow, fast := head, head

    for fast != nil &amp;amp;&amp;amp; fast.Next != nil {
        fast = fast.Next.Next
        slow = slow.Next
        if fast == slow {
            return true
        }
    }

    return false
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-142.环形链表II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-142%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-142%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8ii/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/remove-linked-list-elements/&quot;&gt;&lt;strong&gt;203. 移除链表元素&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个链表的头节点  &lt;code&gt;head&lt;/code&gt; ，返回链表开始入环的第一个节点。 &lt;em&gt;如果链表无环，则返回 &lt;code&gt;null&lt;/code&gt;。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;如果链表中有某个节点，可以通过连续跟踪 &lt;code&gt;next&lt;/code&gt; 指针再次到达，则链表中存在环。 为了表示给定链表中的环，评测系统内部使用整数 &lt;code&gt;pos&lt;/code&gt; 来表示链表尾连接到链表中的位置（&lt;strong&gt;索引从 0 开始&lt;/strong&gt;）。如果 &lt;code&gt;pos&lt;/code&gt; 是 &lt;code&gt;-1&lt;/code&gt;，则在该链表中没有环。&lt;strong&gt;注意：&lt;code&gt;pos&lt;/code&gt; 不作为参数进行传递&lt;/strong&gt;，仅仅是为了标识链表的实际情况。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不允许修改&lt;/strong&gt; 链表。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2018/12/07/circularlinkedlist.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [3,2,0,-4], pos = 1
输出：返回索引为 1 的链表节点
解释：链表中有一个环，其尾部连接到第二个节点。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist_test2.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2], pos = 0
输出：返回索引为 0 的链表节点
解释：链表中有一个环，其尾部连接到第一个节点。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/07/circularlinkedlist_test3.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1], pos = -1
输出：返回 null
解释：链表中没有环。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法(哈希)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，暴力法哈哈&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func detectCycle(head *ListNode) *ListNode {
    cur := head
    res := make(map[*ListNode]int)

    for cur != nil {
        if res[cur] == 1 {
            return cur
        }
        res[cur]++ 
        cur = cur.Next
    }

    return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;快慢指针&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;第一个想出来快慢指针的人，简直就是天才，太神奇了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：快慢指针必然在环内的某一点相遇。我们把整段路程切成三段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;x：从&lt;strong&gt;链表头&lt;/strong&gt;到&lt;strong&gt;环入口&lt;/strong&gt;的距离。&lt;/li&gt;
&lt;li&gt;y：从&lt;strong&gt;环入口&lt;/strong&gt;到&lt;strong&gt;相遇点&lt;/strong&gt;的距离。&lt;/li&gt;
&lt;li&gt;z：从&lt;strong&gt;相遇点&lt;/strong&gt;继续走，回到&lt;strong&gt;环入口&lt;/strong&gt;的距离&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先，我们要先知道慢指针在进入环之后，绝对不可能走完一整圈，它必定会在第一圈内就被快指针追上。fast和slow的相对速度是1，最大距离是L-1，所以相遇时慢指针移动L-1，L-1 &amp;lt; L，慢指针走过的距离也严格小于环的总长度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;我们可以得出 慢指针距离：x + y，快指针距离：x + y + n(y + z) 或 2(x + y)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2(x + y) = x + y + n(y + z) 得到 x = n(y + z) - y&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;化简一下 &lt;strong&gt;x = (n - 1)(y + z) + z&lt;/strong&gt;，即他们相遇的点就是我们所求的答案&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func detectCycle(head *ListNode) *ListNode {
    slow, fast := head, head

    for fast != nil &amp;amp;&amp;amp; fast.Next != nil {
        fast = fast.Next.Next
        slow = slow.Next

        if slow == fast {
            left := head
            right := slow

            for left != right {
                left = left.Next
                right = right.Next
            }

            return left
        }
    }
    return nil
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-160.相交链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-160%E7%9B%B8%E4%BA%A4%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-160%E7%9B%B8%E4%BA%A4%E9%93%BE%E8%A1%A8/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/intersection-of-two-linked-lists/&quot;&gt;&lt;strong&gt;160. 相交链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你两个单链表的头节点 &lt;code&gt;headA&lt;/code&gt; 和 &lt;code&gt;headB&lt;/code&gt; ，请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点，返回 &lt;code&gt;null&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;图示两个链表在节点 &lt;code&gt;c1&lt;/code&gt; 开始相交**：**&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/14/160_statement.png&quot;&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/14/160_statement.png&quot; alt=&quot;img&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;题目数据 &lt;strong&gt;保证&lt;/strong&gt; 整个链式结构中不存在环。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;，函数返回结果后，链表必须 &lt;strong&gt;保持其原始结构&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自定义评测：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;评测系统&lt;/strong&gt; 的输入如下（你设计的程序 &lt;strong&gt;不适用&lt;/strong&gt; 此输入）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;intersectVal&lt;/code&gt; - 相交的起始节点的值。如果不存在相交节点，这一值为 &lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;listA&lt;/code&gt; - 第一个链表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;listB&lt;/code&gt; - 第二个链表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;skipA&lt;/code&gt; - 在 &lt;code&gt;listA&lt;/code&gt; 中（从头节点开始）跳到交叉节点的节点数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;skipB&lt;/code&gt; - 在 &lt;code&gt;listB&lt;/code&gt; 中（从头节点开始）跳到交叉节点的节点数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;评测系统将根据这些输入创建链式数据结构，并将两个头节点 &lt;code&gt;headA&lt;/code&gt; 和 &lt;code&gt;headB&lt;/code&gt; 传递给你的程序。如果程序能够正确返回相交节点，那么你的解决方案将被 &lt;strong&gt;视作正确答案&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://assets.leetcode.com/uploads/2018/12/13/160_example_1.png&quot;&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/05/160_example_1_1.png&quot; alt=&quot;img&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出：Intersected at &apos;8&apos;
解释：相交节点的值为 8 （注意，如果两个链表相交则不能为 0）。
从各自的表头开始算起，链表 A 为 [4,1,8,4,5]，链表 B 为 [5,6,1,8,4,5]。
在 A 中，相交节点前有 2 个节点；在 B 中，相交节点前有 3 个节点。
— 请注意相交节点的值不为 1，因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说，它们在内存中指向两个不同的位置，而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点，B 中第四个节点) 在内存中指向相同的位置。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://assets.leetcode.com/uploads/2018/12/13/160_example_2.png&quot;&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/05/160_example_2.png&quot; alt=&quot;img&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出：Intersected at &apos;2&apos;
解释：相交节点的值为 2 （注意，如果两个链表相交则不能为 0）。
从各自的表头开始算起，链表 A 为 [1,9,1,2,4]，链表 B 为 [3,2,4]。
在 A 中，相交节点前有 3 个节点；在 B 中，相交节点前有 1 个节点。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://assets.leetcode.com/uploads/2018/12/13/160_example_3.png&quot;&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/12/14/160_example_3.png&quot; alt=&quot;img&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出：No intersection
解释：从各自的表头开始算起，链表 A 为 [2,6,4]，链表 B 为 [1,5]。
由于这两个链表不相交，所以 intersectVal 必须为 0，而 skipA 和 skipB 可以是任意值。
这两个链表不相交，因此返回 null 。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;双指针的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这道题太纯爱了&lt;/p&gt;
&lt;p&gt;走过你的来时路，只为与你相遇&lt;/p&gt;
&lt;p&gt;若有缘，我们在交点相逢；若无缘，我便走完你走过的路，陪你一起停在时间的尽头&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;**思路：**两个指针分别从两个链表的头节点开始遍历，链表 A 在交点前的长度为 &lt;code&gt;a&lt;/code&gt;，链表 B 在交点前的长度为 &lt;code&gt;b&lt;/code&gt;，交点后的公共部分长度为 &lt;code&gt;c&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指针 A 走过的总路程是：&lt;code&gt;a + c + b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;指针 B 走过的总路程是：&lt;code&gt;b + c + a&lt;/code&gt; 因为 &lt;code&gt;a + c + b == b + c + a&lt;/code&gt;，所以两个指针一定会同时到达交点。如果两个链表没有交点（即 &lt;code&gt;c = 0&lt;/code&gt;），那么它们最后会同时指向 &lt;code&gt;nil&lt;/code&gt; 并跳出循环。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func getIntersectionNode(headA, headB *ListNode) *ListNode {
    if headA == nil || headB == nil {
        return nil
    }

    ptrA, ptrB := headA, headB
    for ptrA != ptrB {
        if ptrA != nil {
            ptrA = ptrA.Next
        }else {
            ptrA = headB
        }

        if ptrB != nil {
            ptrB = ptrB.Next
        }else {
            ptrB = headA
        }
    }

    return ptrA
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-19.删除链表的倒数第 N 个结点</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-19%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%AC-n-%E4%B8%AA%E7%BB%93%E7%82%B9/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-19%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%AC-n-%E4%B8%AA%E7%BB%93%E7%82%B9/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/remove-nth-node-from-end-of-list/&quot;&gt;&lt;strong&gt;19. 删除链表的倒数第 N 个结点&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个链表，删除链表的倒数第 &lt;code&gt;n&lt;/code&gt; 个结点，并且返回链表的头结点&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/03/remove_ex1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2,3,4,5], n = 2
输出：[1,2,3,5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1], n = 1
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2], n = 1
输出：[1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，一遍过，哈哈哈！不妄我失败了这么多次链表，虽然比较简单就是了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeNthFromEnd(head *ListNode, n int) *ListNode {
    dummy := &amp;amp;ListNode{Next: head}

    cur := dummy.Next
    count := 1
    for cur != nil {
        cur = cur.Next
        count++
    }

    need := count - n - 1
    cur = dummy
    for i := 0; i &amp;lt; need; i++ {
        cur = cur.Next
    }

    if cur.Next != nil {
        cur.Next = cur.Next.Next
    }

    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;双指针&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func removeNthFromEnd(head *ListNode, n int) *ListNode {
	dummyNode := &amp;amp;ListNode{0, head}
	fast, slow := dummyNode, dummyNode
  
	for i := 0; i &amp;lt;= n; i++ { 
		fast = fast.Next
	}
  
	for fast != nil {
		fast = fast.Next
		slow = slow.Next
	}
	slow.Next = slow.Next.Next
  
	return dummyNode.Next
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-206.反转链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-206%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-206%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/reverse-linked-list/&quot;&gt;&lt;strong&gt;206. 反转链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你单链表的头节点 &lt;code&gt;head&lt;/code&gt; ，请你反转链表，并返回反转后的链表。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/19/rev1ex1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2,3,4,5]
输出：[5,4,3,2,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/02/19/rev1ex2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2]
输出：[2,1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;双指针的解法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseList(head *ListNode) *ListNode {
    var pre *ListNode
    cur := head
    for cur != nil {
        next := cur.Next
        cur.Next = pre
        pre = cur
        cur = next
    }
    
    return pre
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;递归的方法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func reverseList(head *ListNode) *ListNode {
    return help(nil, head)
}

func help(pre, head *ListNode)*ListNode{
    if head == nil {
        return pre
    }
    next := head.Next
    head.Next = pre
    return help(head, next)
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-234.回文链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-234%E5%9B%9E%E6%96%87%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-234%E5%9B%9E%E6%96%87%E9%93%BE%E8%A1%A8/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/palindrome-linked-list/&quot;&gt;&lt;strong&gt;234. 回文链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个单链表的头节点 &lt;code&gt;head&lt;/code&gt; ，请你判断该链表是否为回文链表。如果是，返回 &lt;code&gt;true&lt;/code&gt; ；否则，返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/03/pal1linked-list.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2,2,1]
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/03/pal2linked-list.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2]
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法(哈希+左右指针)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，单纯做出来还是很简单的，不过13ms确实有点慢&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func isPalindrome(head *ListNode) bool {
    if head == nil {
        return true
    }

    cur := head
    res := []int{}
    for cur != nil {
        res = append(res, cur.Val)
        cur = cur.Next
    }

    left, right := 0, len(res)-1
    for left &amp;lt; right {
        if res[left] != res[right] {
            return false
        }
        left++
        right--
    }

    return true
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;很有趣的解法(快慢指针+反转链表+左右指针)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func isPalindrome(head *ListNode) bool {
    if head == nil || head.Next == nil {
        return true
    }

    slow, fast := head, head
    for fast != nil &amp;amp;&amp;amp; fast.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
    }

    var pre *ListNode
    cur := slow
    for cur != nil {
        next := cur.Next
        cur.Next = pre
        pre = cur
        cur = next
    }

    left := head
    right := pre
    for right != nil {
        if right.Val != left.Val {
            return false
        }
        
        left = left.Next
        right = right.Next
    }

    return true
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-24.两两交换链表中的节点</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-24%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-24%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/swap-nodes-in-pairs/&quot;&gt;&lt;strong&gt;24. 两两交换链表中的节点&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个链表，两两交换其中相邻的节点，并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题（即，只能进行节点交换）。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/10/03/swap_ex1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2,3,4]
输出：[2,1,4,3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = []
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1]
输出：[1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;正确的解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：与&lt;a href=&quot;https://leetcode.cn/problems/reverse-linked-list/&quot;&gt;&lt;strong&gt;206. 反转链表&lt;/strong&gt;&lt;/a&gt;稍有不同，这里需要注意两点&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;这里需要变动头节点，所以最好引入虚拟头节点&lt;/li&gt;
&lt;li&gt;边界空指针的问题：这里操作涉及三个元素，但只需要检查两个，第三个元素可以是 &lt;code&gt;nil&lt;/code&gt;。如果只检查一个1.是没有意义2.是会造成询问&lt;code&gt;nil&lt;/code&gt;的下一个元素是什么，导致程序崩溃&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func swapPairs(head *ListNode) *ListNode {
    dummy := &amp;amp;ListNode{Next: head}
    pre := dummy

    for pre.Next != nil &amp;amp;&amp;amp; pre.Next.Next != nil {
        node1 := pre.Next
        node2 := node1.Next
        node3 := node2.Next

        pre.Next = node2
        node2.Next = node1
        node1.Next = node3

        pre = node1
    } 

    return dummy.Next
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-707.设计链表</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-707%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-707%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8/</guid><pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/design-linked-list/&quot;&gt;&lt;strong&gt;707. 设计链表&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你可以选择使用单链表或者双链表，设计并实现自己的链表。&lt;/p&gt;
&lt;p&gt;单链表中的节点应该具备两个属性：&lt;code&gt;val&lt;/code&gt; 和 &lt;code&gt;next&lt;/code&gt; 。&lt;code&gt;val&lt;/code&gt; 是当前节点的值，&lt;code&gt;next&lt;/code&gt; 是指向下一个节点的指针/引用。&lt;/p&gt;
&lt;p&gt;如果是双向链表，则还需要属性 &lt;code&gt;prev&lt;/code&gt; 以指示链表中的上一个节点。假设链表中的所有节点下标从 &lt;strong&gt;0&lt;/strong&gt; 开始。&lt;/p&gt;
&lt;p&gt;实现 &lt;code&gt;MyLinkedList&lt;/code&gt; 类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MyLinkedList()&lt;/code&gt; 初始化 &lt;code&gt;MyLinkedList&lt;/code&gt; 对象。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;int get(int index)&lt;/code&gt; 获取链表中下标为 &lt;code&gt;index&lt;/code&gt; 的节点的值。如果下标无效，则返回 &lt;code&gt;-1&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void addAtHead(int val)&lt;/code&gt; 将一个值为 &lt;code&gt;val&lt;/code&gt; 的节点插入到链表中第一个元素之前。在插入完成后，新节点会成为链表的第一个节点。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void addAtTail(int val)&lt;/code&gt; 将一个值为 &lt;code&gt;val&lt;/code&gt; 的节点追加到链表中作为链表的最后一个元素。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void addAtIndex(int index, int val)&lt;/code&gt; 将一个值为 &lt;code&gt;val&lt;/code&gt; 的节点插入到链表中下标为 &lt;code&gt;index&lt;/code&gt; 的节点之前。如果 &lt;code&gt;index&lt;/code&gt; 等于链表的长度，那么该节点会被追加到链表的末尾。如果 &lt;code&gt;index&lt;/code&gt; 比长度更大，该节点将 &lt;strong&gt;不会插入&lt;/strong&gt; 到链表中。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void deleteAtIndex(int index)&lt;/code&gt; 如果下标有效，则删除链表中下标为 &lt;code&gt;index&lt;/code&gt; 的节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入
[&quot;MyLinkedList&quot;, &quot;addAtHead&quot;, &quot;addAtTail&quot;, &quot;addAtIndex&quot;, &quot;get&quot;, &quot;deleteAtIndex&quot;, &quot;get&quot;]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]

解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2);    // 链表变为 1-&amp;gt;2-&amp;gt;3
myLinkedList.get(1);              // 返回 2
myLinkedList.deleteAtIndex(1);    // 现在，链表变为 1-&amp;gt;3
myLinkedList.get(1);              // 返回 3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;单链表解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;是一道新手学习和了解链表的很好的题目&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;type Node struct {
	Val  int         
	Next *Node 
}

type MyLinkedList struct {
   dummyHead *Node
   Size int
}


func Constructor() MyLinkedList {
    newNode := &amp;amp;Node{ 
		-999,
		nil,
	}
	return MyLinkedList{ 
		dummyHead: newNode,
		Size:      0,
	}
}


func (this *MyLinkedList) Get(index int) int {
    if this == nil || index &amp;lt; 0 || index &amp;gt;= this.Size { 
		return -1
	}

    current := this.dummyHead.Next
    for i := 0; i &amp;lt; index; i++ {
        current = current.Next
    }

    return current.Val
}


func (this *MyLinkedList) AddAtHead(val int)  {
    newNode := &amp;amp;Node{
        Val: val,
        Next: this.dummyHead.Next,
    }

    this.dummyHead.Next = newNode
    this.Size++
}


func (this *MyLinkedList) AddAtTail(val int)  {
    newNode := &amp;amp;Node{Val: val}

    current := this.dummyHead
    for current.Next != nil {
        current = current.Next
    }

    current.Next = newNode
    this.Size++
}


func (this *MyLinkedList) AddAtIndex(index int, val int)  {
    if index &amp;lt; 0 || index &amp;gt; this.Size {
        return
    }

    newNode := &amp;amp;Node{Val: val}
    current := this.dummyHead
    for i := 0; i &amp;lt; index; i++ {
        current = current.Next
    }

    newNode.Next = current.Next
    current.Next = newNode
    this.Size++
}


func (this *MyLinkedList) DeleteAtIndex(index int)  {
    if index &amp;lt; 0 || index &amp;gt;= this.Size { 
		return
	}
	current := this.dummyHead       
	for i := 0; i &amp;lt; index; i++ { 
		current = current.Next
	}
	if current.Next != nil {
		current.Next = current.Next.Next 
	}
	this.Size-- 
}


/**
 * Your MyLinkedList object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Get(index);
 * obj.AddAtHead(val);
 * obj.AddAtTail(val);
 * obj.AddAtIndex(index,val);
 * obj.DeleteAtIndex(index);
 */
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>第一周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-9-weekly1/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/26%E6%98%A5/2026-3-9-weekly1/</guid><pubDate>Mon, 09 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这周就是在刷力扣，刷了26道题，其中hot100有21道题，从哈希到矩阵，虽然大部分还是看完思路在写的，但还是有点收获的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;刷力扣&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;刷力扣&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>LeetCode-203.移除链表元素</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-203%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E9%93%BE%E8%A1%A8/leetcode-203%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0/</guid><pubDate>Mon, 09 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;链表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/remove-linked-list-elements/&quot;&gt;&lt;strong&gt;203. 移除链表元素&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个链表的头节点 &lt;code&gt;head&lt;/code&gt; 和一个整数 &lt;code&gt;val&lt;/code&gt; ，请你删除链表中所有满足 &lt;code&gt;Node.val == val&lt;/code&gt; 的节点，并返回 &lt;strong&gt;新的头节点&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2021/03/06/removelinked-list.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [1,2,6,3,4,5,6], val = 6
输出：[1,2,3,4,5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [], val = 1
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：head = [7,7,7,7], val = 7
输出：[]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，链表的第一题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeElements(head *ListNode, val int) *ListNode {
    if head == nil {
        return head
    }

    for head != nil &amp;amp;&amp;amp; head.Val == val {
        head = head.Next
    }

    current := head
    for current != nil &amp;amp;&amp;amp; current.Next != nil {
        if current.Next.Val != val {
            current = current.Next
        }else {
            current.Next = current.Next.Next
        }
    }
    
    return head
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-240.搜索二维矩阵II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-240%E6%90%9C%E7%B4%A2%E4%BA%8C%E7%BB%B4%E7%9F%A9%E9%98%B5ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-240%E6%90%9C%E7%B4%A2%E4%BA%8C%E7%BB%B4%E7%9F%A9%E9%98%B5ii/</guid><pubDate>Sun, 08 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;矩阵&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/search-a-2d-matrix-ii/&quot;&gt;&lt;strong&gt;240. 搜索二维矩阵 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;编写一个高效的算法来搜索 &lt;code&gt;*m* x *n*&lt;/code&gt; 矩阵 &lt;code&gt;matrix&lt;/code&gt; 中的一个目标值 &lt;code&gt;target&lt;/code&gt; 。该矩阵具有以下特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每行的元素从左到右升序排列。&lt;/li&gt;
&lt;li&gt;每列的元素从上到下升序排列。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2020/11/25/searchgrid2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2020/11/25/searchgrid.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;暴力法最快乐的一集&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;二叉树似乎是最正确的答案，等之后学到再看看吧&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func searchMatrix(matrix [][]int, target int) bool {
    m := len(matrix)
    n := len(matrix[0])

    for i := 0; i &amp;lt; m; i++ {
        for j := 0; j &amp;lt; n; j++ {
            if matrix[i][j] &amp;gt; target {
                break
            }

            if(matrix[i][j]==target) {
                return true
            }
        }
    }

    return false;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-48.旋转图像</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-48%E6%97%8B%E8%BD%AC%E5%9B%BE%E5%83%8F/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-48%E6%97%8B%E8%BD%AC%E5%9B%BE%E5%83%8F/</guid><pubDate>Sun, 08 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;矩阵&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/rotate-image/&quot;&gt;&lt;strong&gt;48. 旋转图像&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个 &lt;em&gt;n&lt;/em&gt; × &lt;em&gt;n&lt;/em&gt; 的二维矩阵 &lt;code&gt;matrix&lt;/code&gt; 表示一个图像。请你将图像顺时针旋转 90 度。&lt;/p&gt;
&lt;p&gt;你必须在**&lt;a href=&quot;https://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95&quot;&gt; 原地&lt;/a&gt;** 旋转图像，这意味着你需要直接修改输入的二维矩阵。&lt;strong&gt;请不要&lt;/strong&gt; 使用另一个矩阵来旋转图像。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/08/28/mat1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出：[[7,4,1],[8,5,2],[9,6,3]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/08/28/mat2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出：[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;正确的方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：只要知道 向右翻转 = 左对角线对称 + 左右对称 即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func rotate(matrix [][]int)  {
    n := len(matrix)
    
     for i := 0; i &amp;lt; n; i++ {
        for j := i+1; j &amp;lt; n; j++{
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        }
    }

    for i := 0; i &amp;lt; n; i++ {
        for j := 0; j &amp;lt; n/2; j++{
            matrix[i][j], matrix[i][n-j-1] = matrix[i][n-j-1], matrix[i][j]
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-54.螺旋矩阵</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-54%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-54%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5/</guid><pubDate>Sun, 08 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;矩阵&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/spiral-matrix/&quot;&gt;&lt;strong&gt;54. 螺旋矩阵&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个 &lt;code&gt;m&lt;/code&gt; 行 &lt;code&gt;n&lt;/code&gt; 列的矩阵 &lt;code&gt;matrix&lt;/code&gt; ，请按照 &lt;strong&gt;顺时针螺旋顺序&lt;/strong&gt; ，返回矩阵中的所有元素。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/11/13/spiral1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出：[1,2,3,6,9,8,7,4,5]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/11/13/spiral.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出：[1,2,3,4,8,12,11,10,9,5,6,7]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;打了补丁的自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我靠，这个矩形我看半天没看出来哪里写错了，后来看了ai才发现矩形会有一条行/列，没有消耗完，会继续执行的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;: 参照&lt;a href=&quot;https://leetcode.cn/problems/spiral-matrix-ii/&quot;&gt;&lt;strong&gt;59. 螺旋矩阵 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;难点&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;正方形&lt;/strong&gt;特殊之处是&lt;strong&gt;行和列是一样多&lt;/strong&gt;的，向右走完后，剩下的一定是空集。向左的循环自然进不去。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长方形&lt;/strong&gt;向右走完后&lt;strong&gt;行和列是不一样多&lt;/strong&gt;的，行虽然死了，但列还活着。代码就会依靠还活着的“列条件”，继续执行&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;func spiralOrder(matrix [][]int) []int {
    m := len(matrix) 
    n := len(matrix[0])
    res := []int{}
    top, bottom := 0, m-1
    left, right := 0, n-1

    for len(res) &amp;lt; m * n {
        for i := left; i &amp;lt;= right; i++ {
            res = append(res, matrix[top][i])
        }
        top++
        
        if top &amp;gt; bottom {
            break
        }

        for i := top; i &amp;lt;= bottom; i++ {
            res = append(res, matrix[i][right])
        }
        right--
        
        if left &amp;gt; right {
            break
        }
        

        for i := right; i &amp;gt;= left; i-- {
            res = append(res, matrix[bottom][i])
        }
        bottom--

        for i := bottom; i &amp;gt;= top; i-- {
            res = append(res, matrix[i][left])
        }
        left++
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-59.螺旋矩阵II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-59%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-59%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5ii/</guid><pubDate>Sun, 08 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;矩阵&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/spiral-matrix-ii/&quot;&gt;&lt;strong&gt;59. 螺旋矩阵 II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个正整数 &lt;code&gt;n&lt;/code&gt; ，生成一个包含 &lt;code&gt;1&lt;/code&gt; 到 &lt;code&gt;n2&lt;/code&gt; 所有元素，且元素按顺时针顺序螺旋排列的 &lt;code&gt;n x n&lt;/code&gt; 正方形矩阵 &lt;code&gt;matrix&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/11/13/spiraln.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 3
输出：[[1,2,3],[8,9,4],[7,6,5]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 1
输出：[[1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，不过写的比较丑陋，我自己都看出来了混合使用了&lt;strong&gt;相对长度 (&lt;code&gt;n&lt;/code&gt;)&lt;/strong&gt; 和 &lt;strong&gt;绝对长度 (&lt;code&gt;len&lt;/code&gt;)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路简单，但写起来不那么简单，靠着测试用例不断校对&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func generateMatrix(n int) [][]int {
    matrix := make([][]int, n)
    count := 0
    circle := 0
    len := n
    square := n*n

    for i := 0; i &amp;lt; n; i++{
        matrix[i] = make([]int, n)
    }

    for count &amp;lt; square {
        for i := 0; i &amp;lt; n; i++ {
            count++ 
            matrix[circle][i+circle] = count
        }

        for i := 1; i &amp;lt; n; i++ {
            count++
            matrix[i+circle][len-circle-1] = count
        }

        for i := len-circle-2; i &amp;gt;= circle; i-- {
            count++
            matrix[len-circle-1][i] = count
        }

        for i := len-circle-2; i &amp;gt;= circle+1; i-- {
            count++
            matrix[i][circle] = count
        }

        n -= 2
        circle++
    }

    return matrix
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;更优美的方法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func generateMatrix(n int) [][]int {
    matrix := make([][]int, n)
    for i := 0; i &amp;lt; n; i++ {
        matrix[i] = make([]int, n)
    }

    top, bottom := 0, n-1
    left, right := 0, n-1
    
    count := 1
    target := n * n

    for count &amp;lt;= target {
        // 1. 从左到右（贴着 top 走），走完后 top 边界下移
        for i := left; i &amp;lt;= right; i++ {
            matrix[top][i] = count
            count++
        }
        top++

        // 2. 从上到下（贴着 right 走），走完后 right 边界左移
        for i := top; i &amp;lt;= bottom; i++ {
            matrix[i][right] = count
            count++
        }
        right--

        // 3. 从右到左（贴着 bottom 走），走完后 bottom 边界上移
        for i := right; i &amp;gt;= left; i-- {
            matrix[bottom][i] = count
            count++
        }
        bottom--

        // 4. 从下到上（贴着 left 走），走完后 left 边界右移
        for i := bottom; i &amp;gt;= top; i-- {
            matrix[i][left] = count
            count++
        }
        left++
    }

    return matrix
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-73.矩阵置零</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-73%E7%9F%A9%E9%98%B5%E7%BD%AE%E9%9B%B6/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E7%9F%A9%E9%98%B5/leetcode-73%E7%9F%A9%E9%98%B5%E7%BD%AE%E9%9B%B6/</guid><pubDate>Sun, 08 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;矩阵&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/set-matrix-zeroes/&quot;&gt;&lt;strong&gt;73. 矩阵置零&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个 &lt;code&gt;*m* x *n*&lt;/code&gt; 的矩阵，如果一个元素为 &lt;strong&gt;0&lt;/strong&gt; ，则将其所在行和列的所有元素都设为 &lt;strong&gt;0&lt;/strong&gt; 。请使用 &lt;strong&gt;&lt;a href=&quot;http://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95&quot;&gt;原地&lt;/a&gt;&lt;/strong&gt; 算法**。**&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/08/17/mat1.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出：[[1,0,1],[0,0,0],[1,0,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.com/uploads/2020/08/17/mat2.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出：[[0,0,0,0],[0,4,5,0],[0,3,1,0]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;空间复杂度O(m+n)的方法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func setZeroes(matrix [][]int)  {
    m := len(matrix)
    n := len(matrix[0])
    row := make([]bool, m)
    col := make([]bool, n)

    for i := 0; i &amp;lt; m; i++ {
        for j := 0; j &amp;lt; n; j++{
            if matrix[i][j] == 0 {
                row[i] = true
                col[j] = true
            }
        }
    }

    for i := 0; i &amp;lt; m; i++ {
        for j := 0; j &amp;lt; n; j++{
            if row[i] == true || col[j] == true {
                matrix[i][j] = 0
            }
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;空间复杂度O(1)的方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;思路&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;相较于上个方法，这里把矩阵的第一行和第一列，直接当成上面的 &lt;code&gt;row&lt;/code&gt; 和 &lt;code&gt;col&lt;/code&gt; 数组来用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;两个疑惑点&lt;/strong&gt;: 1.为什么可以这样用？ 2.不会影响第一行和列吗？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;这里因为如果这个数字下面有0，那么这行/列最后会都会变为0。如果没有就不变。所以拿这个作为&lt;code&gt;row&lt;/code&gt; 和 &lt;code&gt;col&lt;/code&gt; 数组来用，不会影响这几个数字的结局。&lt;/li&gt;
&lt;li&gt;用两个布尔变量 &lt;code&gt;row0Flag&lt;/code&gt; 和 &lt;code&gt;col0Flag&lt;/code&gt;，去扫一遍第一行和第一列，记下来它们原本到底有没有 0。这样就可以判断原本有没有0。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;func setZeroes(matrix [][]int)  {
    m := len(matrix)
    n := len(matrix[0])
    row0Flag := false
    col0Flag := false

    for i := 0; i &amp;lt; n; i++ {
        if matrix[0][i] == 0 {
            row0Flag = true
        }
    }

    for i := 0; i &amp;lt; m; i++ {
        if matrix[i][0] == 0 {
            col0Flag = true
        }
    }

    for i := 1; i &amp;lt; m; i++ {
        for j := 1; j &amp;lt; n; j++{
            if matrix[i][j] == 0 {
                matrix[i][0] = 0
                matrix[0][j] = 0
            }
        }
    }

    for i := 1; i &amp;lt; m; i++ {
        for j := 1; j &amp;lt; n; j++{
            if matrix[i][0] == 0 || matrix[0][j] == 0 {
                matrix[i][j] = 0
            }
        }
    }
    
    if row0Flag == true {
        for i := 0; i &amp;lt; n; i++ {
            matrix[0][i] = 0
        }
    }

    if col0Flag == true {
        for i := 0; i &amp;lt; m; i++ {
            matrix[i][0] = 0
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>一些零碎知识的补充</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%B8%80%E4%BA%9B%E9%9B%B6%E7%A2%8E%E7%9F%A5%E8%AF%86%E7%9A%84%E8%A1%A5%E5%85%85/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E4%B8%80%E4%BA%9B%E9%9B%B6%E7%A2%8E%E7%9F%A5%E8%AF%86%E7%9A%84%E8%A1%A5%E5%85%85/</guid><pubDate>Sat, 07 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h4&gt;时间复杂度&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;题目给定的数据规模 n&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;你应该瞄准的时间复杂度&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;对应的常见算法或数据结构&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;n &amp;lt;= 20&lt;/td&gt;
&lt;td&gt;O(2^n) 或 O(n!)&lt;/td&gt;
&lt;td&gt;回溯法 (Backtracking)、状态压缩 DP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n &amp;lt;= 10^2&lt;/td&gt;
&lt;td&gt;O(n^3)&lt;/td&gt;
&lt;td&gt;动态规划 (3D DP)、Floyd 算法&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n &amp;lt;= 10^3&lt;/td&gt;
&lt;td&gt;O(n^2)&lt;/td&gt;
&lt;td&gt;双层 for 循环、动态规划 (2D DP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n &amp;lt;= 10^4 ~ 10^5&lt;/td&gt;
&lt;td&gt;O(n log n) 或 O(n)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;最常见！&lt;/strong&gt; 排序、双指针、二分查找、哈希表、栈/队列&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n &amp;lt;= 10^6&lt;/td&gt;
&lt;td&gt;O(n) 或 O(log n) 或 O(1)&lt;/td&gt;
&lt;td&gt;二分查找、数学解法、位运算&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;额外空间复杂度&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;O(n) ：&lt;/strong&gt; 哈希表、辅助数组和栈和队列&lt;/p&gt;
&lt;p&gt;**O(1)：**不能去 new 一个同样大小的新数组或哈希表，只能用几个变量作为指针来回倒腾数据&lt;/p&gt;
&lt;p&gt;在 Go 中，&lt;strong&gt;字符串是一个只读的字节切片&lt;/strong&gt;（&lt;code&gt;[]byte&lt;/code&gt;），它不关心这些字节具体是什么编码。&lt;/p&gt;
&lt;h4&gt;(1) 通过索引访问&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;s := &quot;hello&quot;
for i := 0; i &amp;lt; len(s); i++ {
    b := s[i]          // b 的类型是 byte（uint8）
    fmt.Printf(&quot;%c &quot;, b)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种方式每次取一个&lt;strong&gt;字节&lt;/strong&gt;，对于 ASCII 字符没问题，但如果字符串包含中文等 Unicode 字符，就会乱码。&lt;/p&gt;
&lt;h4&gt;(2) 使用 &lt;code&gt;range&lt;/code&gt; 遍历&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;s := &quot;hello&quot;
for i, r := range s {  // r 的类型是 rune（int32）
    fmt.Printf(&quot;%c &quot;, r)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;range&lt;/code&gt; 会自动将字节序列按 UTF-8 解码，每次迭代返回一个 &lt;strong&gt;rune&lt;/strong&gt;（即 Unicode 码点，类型为 int32）&lt;/p&gt;
&lt;p&gt;&apos;a&apos;是rune类型&lt;/p&gt;
&lt;p&gt;&quot;a&quot;是字符串类型&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;sort.Slice&lt;/code&gt; – 对任意切片自定义排序&lt;/h2&gt;
&lt;p&gt;当你需要按某种规则排序（比如按绝对值、按结构体字段）时，&lt;code&gt;sort.Slice&lt;/code&gt; 最常用。它通过你提供的 less 函数决定顺序。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 按绝对值降序
nums := []int{-5, 2, -8, 3}
sort.Slice(nums, func(i, j int) bool {
    return abs(nums[i]) &amp;gt; abs(nums[j]) // 降序
})
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-238.除了自身以外数组的乘积</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-238%E9%99%A4%E4%BA%86%E8%87%AA%E8%BA%AB%E4%BB%A5%E5%A4%96%E6%95%B0%E7%BB%84%E7%9A%84%E4%B9%98%E7%A7%AF/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-238%E9%99%A4%E4%BA%86%E8%87%AA%E8%BA%AB%E4%BB%A5%E5%A4%96%E6%95%B0%E7%BB%84%E7%9A%84%E4%B9%98%E7%A7%AF/</guid><pubDate>Fri, 06 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;数组&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/product-of-array-except-self/&quot;&gt;&lt;strong&gt;238. 除了自身以外数组的乘积&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt;，返回 数组 &lt;code&gt;answer&lt;/code&gt; ，其中 &lt;code&gt;answer[i]&lt;/code&gt; 等于 &lt;code&gt;nums&lt;/code&gt; 中除了 &lt;code&gt;nums[i]&lt;/code&gt; 之外其余各元素的乘积 。&lt;/p&gt;
&lt;p&gt;题目数据 &lt;strong&gt;保证&lt;/strong&gt; 数组 &lt;code&gt;nums&lt;/code&gt;之中任意元素的全部前缀元素和后缀的乘积都在 &lt;strong&gt;32 位&lt;/strong&gt; 整数范围内。&lt;/p&gt;
&lt;p&gt;请 **不要使用除法，**且在 &lt;code&gt;O(n)&lt;/code&gt; 时间复杂度内完成此题。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [1,2,3,4]
输出: [24,12,8,6]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [-1,1,0,-3,3]
输出: [0,0,9,0,0]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;看了思路后写的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：就像题目说的一样，用前缀和和后缀和，不过这里是积&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func productExceptSelf(nums []int) []int {
    n := len(nums)
    res := make([]int,n)
    left := make([]int,n)
    right := make([]int,n)

    left[0] = 1
    for i := 1; i &amp;lt; n; i++ {
        left[i] = left[i-1] * nums[i-1] 
    }

    right[n-1] = 1
    for i := n-2; i &amp;gt;= 0; i-- {
        right[i] = right[i+1] * nums[i+1]
    }

    for i := 0; i &amp;lt; n; i++ {
        res[i] = left[i]*right[i]
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;更优化的方法&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func productExceptSelf(nums []int) []int {
    n := len(nums)
    ans := make([]int, n)
    
    ans[0] = 1
    for i := 1; i &amp;lt; n; i++ {
        ans[i] = ans[i-1] * nums[i-1]
    }
    
    rightProduct := 1
    for i := n - 1; i &amp;gt;= 0; i-- {
        ans[i] = ans[i] * rightProduct
        rightProduct *= nums[i]
    }
    
    return ans
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-41.缺失的第一个正数</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-41%E7%BC%BA%E5%A4%B1%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%AD%A3%E6%95%B0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-41%E7%BC%BA%E5%A4%B1%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%AD%A3%E6%95%B0/</guid><pubDate>Fri, 06 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;数组&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/first-missing-positive/&quot;&gt;&lt;strong&gt;41. 缺失的第一个正数&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个未排序的整数数组 &lt;code&gt;nums&lt;/code&gt; ，请你找出其中没有出现的最小的正整数。&lt;/p&gt;
&lt;p&gt;请你实现时间复杂度为 &lt;code&gt;O(n)&lt;/code&gt; 并且只使用常数级别额外空间的解决方案。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,0]
输出：3
解释：范围 [1,2] 中的数字都在数组中。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [3,4,-1,1]
输出：2
解释：1 在数组中，但 2 没有。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [7,8,9,11,12]
输出：1
解释：最小的正数 1 没有出现。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;正确的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🤔，感觉很神奇&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func firstMissingPositive(nums []int) int {
    n := len(nums)
    for i := range n {
        for nums[i] &amp;gt; 0 &amp;amp;&amp;amp; nums[i] &amp;lt; n &amp;amp;&amp;amp; nums[nums[i]-1] != nums[i] {
            nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1]
        }
    }
  
    for i := range n {
        if nums[i] != i+1 {
            return i+1
        }
    }
    return n+1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;自己的解法(哈希)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;写了我一节课提交了6次终于过了，感觉不是很难，但就是写不出来...&lt;/p&gt;
&lt;p&gt;虽然耗时也挺高10ms，但终究还是写出来，毕竟也算是困难题&lt;/p&gt;
&lt;p&gt;好吧，其实不完全满足，时间复杂度为 O(nlogn)，空间复杂度为 O(n)，算做出来一道中等题吧&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func firstMissingPositive(nums []int) int {
    sort.Ints(nums)
    count := 0
    skip := 0
    m := []int{}
     
    for _, j := range nums {
        if j &amp;gt; 0 {
            m = append(m, j)
            count++
        }
    } 

    for i := 0; i &amp;lt; count; i++ {
        if i &amp;gt; 0 &amp;amp;&amp;amp; m[i] == m[i-1] {
            skip++
            if i == count-1 {
                return m[i]+1
            }
            continue
        }

        if m[i] != i - skip + 1 {
            return i - skip + 1
        } 

        if i == count-1 {
            return m[i]+1
        }
    }
    
    return 1
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-56.合并区间</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-56%E5%90%88%E5%B9%B6%E5%8C%BA%E9%97%B4/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-56%E5%90%88%E5%B9%B6%E5%8C%BA%E9%97%B4/</guid><pubDate>Fri, 06 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;数组&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/merge-intervals/&quot;&gt;&lt;strong&gt;56. 合并区间&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以数组 &lt;code&gt;intervals&lt;/code&gt; 表示若干个区间的集合，其中单个区间为 &lt;code&gt;intervals[i] = [starti, endi]&lt;/code&gt; 。请你合并所有重叠的区间，并返回 &lt;em&gt;一个不重叠的区间数组，该数组需恰好覆盖输入中的所有区间&lt;/em&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：intervals = [[1,3],[2,6],[8,10],[15,18]]
输出：[[1,6],[8,10],[15,18]]
解释：区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：intervals = [[1,4],[4,5]]
输出：[[1,5]]
解释：区间 [1,4] 和 [4,5] 可被视为重叠区间。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：intervals = [[4,7],[1,4]]
输出：[[1,7]]
解释：区间 [1,4] 和 [4,7] 可被视为重叠区间。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;第二次手撕&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func merge(intervals [][]int) [][]int {
    if len(intervals) &amp;lt;= 1 {
        return intervals
    }

    sort.Slice(intervals, func(i, j int) bool {
        return intervals[i][0] &amp;lt; intervals[j][0]
    })

    res := [][]int{intervals[0]}
    for i := 1; i &amp;lt; len(intervals); i++ {
        if intervals[i][0] &amp;lt;= res[len(res)-1][1] {
            if intervals[i][1] &amp;gt; res[len(res)-1][1] {
                res[len(res)-1][1] = intervals[i][1]
            }
        }else {
            res = append(res, intervals[i])
        }
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;看了思路后写的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：1.排序&lt;/p&gt;
&lt;p&gt;​	2.遍历排序后的区间。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果当前区间的&lt;strong&gt;左端点&lt;/strong&gt; ≤ 结果集中最后一个区间的&lt;strong&gt;右端点&lt;/strong&gt;，说明有重叠，&lt;strong&gt;合并&lt;/strong&gt;（更新结果集最后一个区间的右端点为两者的最大值）。&lt;/li&gt;
&lt;li&gt;如果当前区间的&lt;strong&gt;左端点&lt;/strong&gt; &amp;gt; 结果集中最后一个区间的&lt;strong&gt;右端点&lt;/strong&gt;，说明不重叠，直接作为新区间&lt;strong&gt;加入&lt;/strong&gt;结果集&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;func merge(intervals [][]int) [][]int {
    if len(intervals) &amp;lt;= 1 {
        return intervals
    }

    sort.Slice(intervals,func(i, j int) bool {
        return intervals[i][0] &amp;lt; intervals[j][0]
    })

    res := [][]int{intervals[0]}
    for i := 1; i &amp;lt; len(intervals); i++ {
        current := intervals[i]
        last := &amp;amp;res[len(res)-1]

        if current[0] &amp;lt;= (*last)[1] {
            if current[1] &amp;gt; (*last)[1] {
                (*last)[1] = current[1]
            }
        }else{
                res = append(res, current)
            }

    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-560.和为 K 的子数组</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-560%E5%92%8C%E4%B8%BA-k-%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-560%E5%92%8C%E4%B8%BA-k-%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84/</guid><pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/subarray-sum-equals-k/&quot;&gt;&lt;strong&gt;560. 和为 K 的子数组&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; 和一个整数 &lt;code&gt;k&lt;/code&gt; ，请你统计并返回 &lt;em&gt;该数组中和为 &lt;code&gt;k&lt;/code&gt; 的子数组的个数&lt;/em&gt; 。&lt;/p&gt;
&lt;p&gt;子数组是数组中元素的连续非空序列&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,1,1], k = 2
输出：2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,2,3], k = 3
输出：2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.解法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：1.负数破坏了单调性，所以不能用滑动窗口&lt;/p&gt;
&lt;p&gt;​	2.前缀和 + 哈希表 | k = 两个前缀和的差&lt;/p&gt;
&lt;p&gt;​	3.参考&lt;a href=&quot;https://leetcode.cn/problems/two-sum/&quot;&gt;&lt;strong&gt;1. 两数之和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func subarraySum(nums []int, k int) int {
    sum := 0
    m := make(map[int]int)
    m[0] = 1
    res := 0

    for i := 0; i &amp;lt; len(nums); i++ {
        sum += nums[i]
        need := sum - k
        if j, ok := m[need]; ok {
            res += j
        }
        m[sum]++
    } 
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-189.轮转数组</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-189%E8%BD%AE%E8%BD%AC%E6%95%B0%E7%BB%84/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-189%E8%BD%AE%E8%BD%AC%E6%95%B0%E7%BB%84/</guid><pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;数组&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/rotate-array/&quot;&gt;&lt;strong&gt;189. 轮转数组&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个整数数组 &lt;code&gt;nums&lt;/code&gt;，将数组中的元素向右轮转 &lt;code&gt;k&lt;/code&gt; 个位置，其中 &lt;code&gt;k&lt;/code&gt; 是非负数。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [-1,-100,3,99], k = 2
输出：[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;暴力法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;老是忘记append要+...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func rotate(nums []int, k int)  {
    n := len(nums)
    l := n - k % n
    
    temp := append(nums[l:], nums[:l]...)
    copy(nums, temp)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;一个神奇的翻转三次的方法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;评论区卧虎藏龙啊🤔&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func rotate(nums []int, k int) {
    n := len(nums)
    k %= n

    reverse(nums)
    reverse(nums[:k])
    reverse(nums[k:])
}

func reverse(a []int) {
    left, right := 0, len(a)-1
    for left &amp;lt; right {
        a[left], a[right] = a[right], a[left]
        left++
        right--
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-53.最大子数组和</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-53%E6%9C%80%E5%A4%A7%E5%AD%90%E6%95%B0%E7%BB%84%E5%92%8C/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-53%E6%9C%80%E5%A4%A7%E5%AD%90%E6%95%B0%E7%BB%84%E5%92%8C/</guid><pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;数组&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/maximum-subarray/&quot;&gt;&lt;strong&gt;53. 最大子数组和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，请你找出一个具有最大和的连续子数组（子数组最少包含一个元素），返回其最大和。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;子数组&lt;/strong&gt;是数组中的一个连续部分。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [-2,1,-3,4,-1,2,1,-5,4]
输出：6
解释：连续子数组 [4,-1,2,1] 的和最大，为 6 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1]
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [5,4,-1,7,8]
输出：23
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI优化后的答案&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;优雅&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：前缀和+数组&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxSubArray(nums []int) int {
    sum := 0
    maxsum := -10001
    minsum := 0

    for _, num := range nums {
        sum += num
        
        maxsum = max(maxsum, sum-minsum)

        minsum = min(minsum, sum)
    }

    return maxsum
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;自己的答案&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有点丑陋了这个答案，虽然是手撕&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func maxSubArray(nums []int) int {
    sum := 0
    maxsum := -10001
    minnum := 10001
    m := []int{0}
    

    if len(nums) == 1 {
        return nums[0]
    }

    for i := 1; i &amp;lt;= len(nums); i++ {
        minnum = min(minnum, m[i-1])
        sum += nums[i-1]
        m = append(m, sum)
        
        maxsum = max(maxsum, m[i]-minnum)
    }

    return maxsum
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;一个204/210正确的答案&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;超时了，可惜...纪念一下逝去的暴力法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func maxSubArray(nums []int) int {
    sum := 0
    maxsum := -10001
    m := []int{0}
    

    if len(nums) == 1 {
        return nums[0]
    }

    for i := 1; i &amp;lt;= len(nums); i++ {
        sum += nums[i-1]
        m = append(m, sum)

        for j := 0; j &amp;lt; i; j++ {
            maxsum = max(maxsum, m[i]-m[j])
        }
        
    }

    return maxsum
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-977.有序数组的平方</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-977%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%95%B0%E7%BB%84/leetcode-977%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9/</guid><pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;数组&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/squares-of-a-sorted-array/&quot;&gt;&lt;strong&gt;977. 有序数组的平方&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个按 &lt;strong&gt;非递减顺序&lt;/strong&gt; 排序的整数数组 &lt;code&gt;nums&lt;/code&gt;，返回 &lt;strong&gt;每个数字的平方&lt;/strong&gt; 组成的新数组，要求也按 &lt;strong&gt;非递减顺序&lt;/strong&gt; 排序。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [-4,-1,0,3,10]
输出：[0,1,9,16,100]
解释：平方后，数组变为 [16,1,0,9,100]
排序后，数组变为 [0,1,9,16,100]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [-7,-3,2,3,11]
输出：[4,9,9,49,121]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;我的答案&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;被简单题卡住了一会儿&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：1.平方就是看绝对值，来个abs把负的变为正的即可&lt;/p&gt;
&lt;p&gt;​	2.普通的左右双指针&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func sortedSquares(nums []int) []int {
    n := len(nums)
    res := make([]int, n)
    left, right := 0, n-1
    
    for i := n - 1; i &amp;gt;= 0; i-- {
        if abs(nums[left]) &amp;gt; abs(nums[right]) {
            res[i] = nums[left] * nums[left]
            left++
        } else {
            res[i] = nums[right] * nums[right]
            right--
        }
    }
    return res
}

func abs(x int) int {
    if x &amp;lt; 0 {
        return -x
    }
    return x
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-209.长度最小的子数组</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-209%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-209%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84/</guid><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;滑动窗口&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/minimum-size-subarray-sum/&quot;&gt;&lt;strong&gt;209. 长度最小的子数组&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个含有 &lt;code&gt;n&lt;/code&gt; 个正整数的数组和一个正整数 &lt;code&gt;target&lt;/code&gt; &lt;strong&gt;。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;找出该数组中满足其总和大于等于 &lt;code&gt;target&lt;/code&gt; 的长度最小的 &lt;strong&gt;子数组&lt;/strong&gt; &lt;code&gt;[numsl, numsl+1, ..., numsr-1, numsr]&lt;/code&gt; ，并返回其长度**。**如果不存在符合条件的子数组，返回 &lt;code&gt;0&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：target = 7, nums = [2,3,1,2,4,3]
输出：2
解释：子数组 [4,3] 是该条件下的长度最小的子数组。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：target = 4, nums = [1,4,4]
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：target = 11, nums = [1,1,1,1,1,1,1,1]
输出：0
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法(滑动的窗口)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，不过自己写的太丑陋了，让ai润色一下&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func minSubArrayLen(target int, nums []int) int {
    left, right := 0, 0
    sum := 0
    minlen := len(nums) + 1 

    for right &amp;lt; len(nums) {
        sum += nums[right]
        
        for sum &amp;gt;= target {
            minlen = min(minlen,right-left+1)
            sum -= nums[left]
            left++
        }

        right++
    }

    if minlen == len(nums) + 1 {
        return 0
    }

    return minlen
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-239.滑动窗口最大值</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-239%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-239%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC/</guid><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;滑动窗口&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/sliding-window-maximum/&quot;&gt;&lt;strong&gt;239. 滑动窗口最大值&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt;，有一个大小为 &lt;code&gt;k&lt;/code&gt; 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 &lt;code&gt;k&lt;/code&gt; 个数字。滑动窗口每次只向右移动一位。&lt;/p&gt;
&lt;p&gt;返回 &lt;em&gt;滑动窗口中的最大值&lt;/em&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,3,-1,-3,5,3,6,7], k = 3
输出：[3,3,5,5,6,7]
解释：
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1], k = 1
输出：[1]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的失败的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;只有42/52通过了测试用例，超出时间限制了🥲&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func maxSlidingWindow(nums []int, k int) []int {
    right := 0
    window := []int{}
    res := []int{}

    if len(nums) &amp;lt; k {
        return nums
    }

    for right &amp;lt; len(nums) {
        window = append(window, nums[right])
        maxVal := window[0]
        
        if len(window) == k {
            for _, val := range window {
                if val &amp;gt; maxVal {
                    maxVal = val
                }   
            }

            res = append(res, maxVal)
            window = window[1:] 
        }
        right++
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.滑动窗口 + 单调对列&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;评论区找到的地狱故事挺好地解释了这个算法&lt;/p&gt;
&lt;p&gt;这是一个降本增笑的故事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果新员工比老员工强（或者一样强），把老员工裁掉。（元素进入窗口）&lt;/li&gt;
&lt;li&gt;如果老员工 35 岁了，也裁掉。（元素离开窗口）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;裁员后，资历最老（最左边）的人就是最强的员工了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：我们需要降低时间复杂度，之前的时间复杂度是 &lt;strong&gt;O(N×k)&lt;/strong&gt;，为了把时间复杂度降到 &lt;strong&gt;O(N)&lt;/strong&gt;，我们需要一种特殊的数据结构，它需要满足：队头永远是当前窗口的最大值&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxSlidingWindow(nums []int, k int) []int {
    if len(nums) == 0 || k == 0 {
        return []int{}
    }
    
    var deque []int 
    var res []int
    
    for right := 0; right &amp;lt; len(nums); right++ {
        
        for len(deque) &amp;gt; 0 &amp;amp;&amp;amp; nums[deque[len(deque)-1]] &amp;lt; nums[right] {
            deque = deque[:len(deque)-1] 
        }
        
        deque = append(deque, right)
        
        if deque[0] &amp;lt; right - k + 1 {
            deque = deque[1:] 
        }
        
        if right &amp;gt;= k - 1 {
            res = append(res, nums[deque[0]])
        }
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-3.无重复字符的最长子串</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-3%E6%97%A0%E9%87%8D%E5%A4%8D%E5%AD%97%E7%AC%A6%E7%9A%84%E6%9C%80%E9%95%BF%E5%AD%90%E4%B8%B2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-3%E6%97%A0%E9%87%8D%E5%A4%8D%E5%AD%97%E7%AC%A6%E7%9A%84%E6%9C%80%E9%95%BF%E5%AD%90%E4%B8%B2/</guid><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;滑动窗口&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/longest-substring-without-repeating-characters/&quot;&gt;&lt;strong&gt;3. 无重复字符的最长子串&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个字符串 &lt;code&gt;s&lt;/code&gt; ，请你找出其中不含有重复字符的 &lt;strong&gt;最长 子串&lt;/strong&gt; 的长度。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;abcabcbb&quot;
输出: 3 
解释: 因为无重复字符的最长子串是 &quot;abc&quot;，所以其长度为 3。注意 &quot;bca&quot; 和 &quot;cab&quot; 也是正确答案。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;bbbbb&quot;
输出: 1
解释: 因为无重复字符的最长子串是 &quot;b&quot;，所以其长度为 1。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;pwwkew&quot;
输出: 3
解释: 因为无重复字符的最长子串是 &quot;wke&quot;，所以其长度为 3。
     请注意，你的答案必须是 子串 的长度，&quot;pwke&quot; 是一个子序列，不是子串。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.滑动的窗口&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;第一次做滑动窗口的题目，所以是看完答案后，自己再一遍，不知道是不是双指针的拓展的原因，我感觉其实不太难&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func lengthOfLongestSubstring(s string) int {
    left, right := 0, 0
    maxlen := 0
    window := make(map[byte]int)

    for right &amp;lt; len(s) {
        window[s[right]]++

        for window[s[right]] &amp;gt; 1 {
            window[s[left]]--
            left++
        }

        if maxlen &amp;lt; right - left + 1 {
            maxlen = right - left + 1
        }

        right++
    }

    return maxlen
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-438.找到字符串中所有字母异位词</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-438%E6%89%BE%E5%88%B0%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E6%89%80%E6%9C%89%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-438%E6%89%BE%E5%88%B0%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E6%89%80%E6%9C%89%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D/</guid><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;滑动窗口&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/find-all-anagrams-in-a-string/&quot;&gt;&lt;strong&gt;438. 找到字符串中所有字母异位词&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个字符串 &lt;code&gt;s&lt;/code&gt; 和 &lt;code&gt;p&lt;/code&gt;，找到 &lt;code&gt;s&lt;/code&gt; 中所有 &lt;code&gt;p&lt;/code&gt; 的 &lt;strong&gt;异位词&lt;/strong&gt; 的子串，返回这些子串的起始索引。不考虑答案输出的顺序&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;cbaebabacd&quot;, p = &quot;abc&quot;
输出: [0,6]
解释:
起始索引等于 0 的子串是 &quot;cba&quot;, 它是 &quot;abc&quot; 的异位词。
起始索引等于 6 的子串是 &quot;bac&quot;, 它是 &quot;abc&quot; 的异位词。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;abab&quot;, p = &quot;ab&quot;
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 &quot;ab&quot;, 它是 &quot;ab&quot; 的异位词。
起始索引等于 1 的子串是 &quot;ba&quot;, 它是 &quot;ab&quot; 的异位词。
起始索引等于 2 的子串是 &quot;ab&quot;, 它是 &quot;ab&quot; 的异位词。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法(滑动的窗口)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，嘿嘿...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路:滑动窗口+哈希&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func findAnagrams(s string, p string) []int {
    left, right := 0, 0
    m, window := [26]int{}, [26]int{}
    res := []int{}
    
    for _, i := range p {
        m[i-&apos;a&apos;]++
    }

    for right &amp;lt; len(s) {
        window[s[right]-&apos;a&apos;]++

        if right - left + 1 == len(p) {
            if window == m {
                res = append(res, left)
            }

            window[s[left]-&apos;a&apos;]--
            left++
        }

        right++
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-76.最小覆盖子串</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-76%E6%9C%80%E5%B0%8F%E8%A6%86%E7%9B%96%E5%AD%90%E4%B8%B2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-76%E6%9C%80%E5%B0%8F%E8%A6%86%E7%9B%96%E5%AD%90%E4%B8%B2/</guid><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;滑动窗口&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/minimum-window-substring/&quot;&gt;&lt;strong&gt;76. 最小覆盖子串&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个字符串 &lt;code&gt;s&lt;/code&gt; 和 &lt;code&gt;t&lt;/code&gt;，长度分别是 &lt;code&gt;m&lt;/code&gt; 和 &lt;code&gt;n&lt;/code&gt;，返回 s 中的 &lt;strong&gt;最短窗口 子串&lt;/strong&gt;，使得该子串包含 &lt;code&gt;t&lt;/code&gt; 中的每一个字符（&lt;strong&gt;包括重复字符&lt;/strong&gt;）。如果没有这样的子串，返回空字符串 &lt;code&gt;&quot;&quot;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;测试用例保证答案唯一。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;ADOBECODEBANC&quot;, t = &quot;ABC&quot;
输出：&quot;BANC&quot;
解释：最小覆盖子串 &quot;BANC&quot; 包含来自字符串 t 的 &apos;A&apos;、&apos;B&apos; 和 &apos;C&apos;。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;a&quot;, t = &quot;a&quot;
输出：&quot;a&quot;
解释：整个字符串 s 是最小覆盖子串。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;a&quot;, t = &quot;aa&quot;
输出: &quot;&quot;
解释: t 中两个字符 &apos;a&apos; 均应包含在 s 的子串中，
因此没有符合条件的子字符串，返回空字符串。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.一个正确的答案&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;刚开始做被爆了捏，做不出来&lt;/p&gt;
&lt;p&gt;不过事后看其实也还好，没想象的可怕&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路：1.判断出s包含了t 2.使用滑动窗口，让它左右互搏，推断出最小值&lt;/p&gt;
&lt;p&gt;这里的难点是是如何高效地判断s包含了t？&lt;/p&gt;
&lt;p&gt;答：多引入几个变量，need、valid、needcount和window，表示不同的状态量，都匹配了就是包含。&lt;/p&gt;
&lt;p&gt;关于这里的滑动窗口，我认为可以参考&lt;a href=&quot;https://leetcode.cn/problems/fruit-into-baskets/&quot;&gt;&lt;strong&gt;904. 水果成篮&lt;/strong&gt;&lt;/a&gt;是差不多的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func minWindow(s string, t string) string {
    left, right := 0, 0
    var need, window [128]int
    needcount, valid := 0, 0
    minlen := 100001
    start := 0

    for _, i := range t {
        need[i]++
        if need[i] == 1 {
            needcount++
        }
    }

    for right &amp;lt; len(s) {
        c := s[right]
        if need[c] &amp;gt; 0 {
            window[c]++
            if window[c] == need[c] {
                valid++
            }
        }

        for valid == needcount {
            if right - left + 1 &amp;lt; minlen {
                start = left
                minlen = right - left + 1
            }
            
            d := s[left]
            if need[d] &amp;gt; 0 {
                window[d]--
                if window[d] &amp;lt; need[d]{
                    valid--
                }
            }
            left++
        }

        right++
    }

    if minlen == 100001 {
        return &quot;&quot;
    }

    return s[start : start+minlen]
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-904.水果成篮</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-904%E6%B0%B4%E6%9E%9C%E6%88%90%E7%AF%AE/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3/leetcode-904%E6%B0%B4%E6%9E%9C%E6%88%90%E7%AF%AE/</guid><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;滑动窗口&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/fruit-into-baskets/&quot;&gt;&lt;strong&gt;904. 水果成篮&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;中译中：求只包含两种元素的最长连续子数组&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你正在探访一家农场，农场从左到右种植了一排果树。这些树用一个整数数组 &lt;code&gt;fruits&lt;/code&gt; 表示，其中 &lt;code&gt;fruits[i]&lt;/code&gt; 是第 &lt;code&gt;i&lt;/code&gt; 棵树上的水果 &lt;strong&gt;种类&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;你想要尽可能多地收集水果。然而，农场的主人设定了一些严格的规矩，你必须按照要求采摘水果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你只有 &lt;strong&gt;两个&lt;/strong&gt; 篮子，并且每个篮子只能装 &lt;strong&gt;单一类型&lt;/strong&gt; 的水果。每个篮子能够装的水果总量没有限制。&lt;/li&gt;
&lt;li&gt;你可以选择任意一棵树开始采摘，你必须从 &lt;strong&gt;每棵&lt;/strong&gt; 树（包括开始采摘的树）上 &lt;strong&gt;恰好摘一个水果&lt;/strong&gt; 。采摘的水果应当符合篮子中的水果类型。每采摘一次，你将会向右移动到下一棵树，并继续采摘。&lt;/li&gt;
&lt;li&gt;一旦你走到某棵树前，但水果不符合篮子的水果类型，那么就必须停止采摘。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;fruits&lt;/code&gt; ，返回你可以收集的水果的 &lt;strong&gt;最大&lt;/strong&gt; 数目。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：fruits = [1,2,1]
输出：3
解释：可以采摘全部 3 棵树。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：fruits = [0,1,2,2]
输出：3
解释：可以采摘 [1,2,2] 这三棵树。
如果从第一棵树开始采摘，则只能采摘 [0,1] 这两棵树。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：fruits = [1,2,3,2,2]
输出：4
解释：可以采摘 [2,3,2,2] 这四棵树。
如果从第一棵树开始采摘，则只能采摘 [1,2] 这两棵树。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法(滑动的窗口)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;手撕，不过摸爬滚打了好久&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func totalFruit(fruits []int) int {
    left, right := 0, 0
  window := make(map[int]int)
    count := 0
    res := 0

    if len(fruits) &amp;lt; 3 {
        return len(fruits)
    }

    for right &amp;lt; len(fruits) {
        window[fruits[right]]++
        if window[fruits[right]] == 1 {
            count++
        }

        if count &amp;lt; 3 {
            res = max(res,right-left+1)
        }else{
            window[fruits[left]] -= 1
            if window[fruits[left]] == 0 {
                count--
            }
            left++
        }

        right++
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-11. 盛最多水的容器</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-11-%E7%9B%9B%E6%9C%80%E5%A4%9A%E6%B0%B4%E7%9A%84%E5%AE%B9%E5%99%A8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-11-%E7%9B%9B%E6%9C%80%E5%A4%9A%E6%B0%B4%E7%9A%84%E5%AE%B9%E5%99%A8/</guid><pubDate>Tue, 03 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/container-with-most-water/&quot;&gt;&lt;strong&gt;11. 盛最多水的容器&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个长度为 &lt;code&gt;n&lt;/code&gt; 的整数数组 &lt;code&gt;height&lt;/code&gt; 。有 &lt;code&gt;n&lt;/code&gt; 条垂线，第 &lt;code&gt;i&lt;/code&gt; 条线的两个端点是 &lt;code&gt;(i, 0)&lt;/code&gt; 和 &lt;code&gt;(i, height[i])&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;找出其中的两条线，使得它们与 &lt;code&gt;x&lt;/code&gt; 轴共同构成的容器可以容纳最多的水。&lt;/p&gt;
&lt;p&gt;返回容器可以储存的最大水量。&lt;/p&gt;
&lt;p&gt;**说明：**你不能倾斜容器。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://aliyun-lc-upload.oss-cn-hangzhou.aliyuncs.com/aliyun-lc-upload/uploads/2018/07/25/question_11.jpg&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：[1,8,6,2,5,4,8,3,7]
输出：49 
解释：图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下，容器能够容纳水（表示为蓝色部分）的最大值为 49。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：height = [1,1]
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的方法(双指针)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;比较简单的中等题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路:在减小宽度时时，永远只移动较短的那块木板&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func maxArea(height []int) int {
    left := 0
    right := len(height) - 1
    h := 0
    max := 0
    for left &amp;lt; right {
        if height[left] &amp;lt;  height[right] {
            h = height[left]
        }else {
            h = height[right]
        }

        if max &amp;lt; h * (right - left) {
            max = h * (right - left)
        }
        
        if height[left] &amp;lt; height[right] {
            left++
        }else{
            right--
        }
    }
    return max
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-18.四数之和</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-18%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-18%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C/</guid><pubDate>Tue, 03 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/4sum/&quot;&gt;&lt;strong&gt;18. 四数之和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个由 &lt;code&gt;n&lt;/code&gt; 个整数组成的数组 &lt;code&gt;nums&lt;/code&gt; ，和一个目标值 &lt;code&gt;target&lt;/code&gt; 。请你找出并返回满足下述全部条件且&lt;strong&gt;不重复&lt;/strong&gt;的四元组 &lt;code&gt;[nums[a], nums[b], nums[c], nums[d]]&lt;/code&gt; （若两个四元组元素一一对应，则认为两个四元组重复）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0 &amp;lt;= a, b, c, d &amp;lt; n&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a&lt;/code&gt;、&lt;code&gt;b&lt;/code&gt;、&lt;code&gt;c&lt;/code&gt; 和 &lt;code&gt;d&lt;/code&gt; &lt;strong&gt;互不相同&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nums[a] + nums[b] + nums[c] + nums[d] == target&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你可以按 &lt;strong&gt;任意顺序&lt;/strong&gt; 返回答案 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,0,-1,0,-2,2], target = 0
输出：[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [2,2,2,2,2], target = 8
输出：[[2,2,2,2]]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法(双指针)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在三数之和的基础上加层循环即可，并处理下循环开始一些错误的剪枝，target可以为负，还是蛮需要三数之和的基础的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func fourSum(nums []int, target int) [][]int {
    var res [][]int
    n := len(nums)
    if n &amp;lt; 4 {
        return res
    }

    sort.Ints(nums)

    for i := 0; i &amp;lt; n-3; i++ {
        if i &amp;gt; 0 &amp;amp;&amp;amp; nums[i] == nums[i-1] {
            continue
        }

        for j := i + 1; j &amp;lt; n-2; j++ {
          
            if j &amp;gt; i+1 &amp;amp;&amp;amp; nums[j] == nums[j-1] {
                continue
            }

            left, right := j+1, n-1
            for left &amp;lt; right {
                sum := nums[i] + nums[j] + nums[left] + nums[right]
                if sum == target {
                    res = append(res, []int{nums[i], nums[j], nums[left], nums[right]})
                    
                    for left &amp;lt; right &amp;amp;&amp;amp; nums[left] == nums[left+1] {
                        left++
                    }
                   
                    for left &amp;lt; right &amp;amp;&amp;amp; nums[right] == nums[right-1] {
                        right--
                    }
                  
                    left++
                    right--
                } else if sum &amp;lt; target {
                    left++
                } else {
                    right--
                }
            }
        }
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-42.接雨水</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-42%E6%8E%A5%E9%9B%A8%E6%B0%B4/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-42%E6%8E%A5%E9%9B%A8%E6%B0%B4/</guid><pubDate>Tue, 03 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/trapping-rain-water/&quot;&gt;&lt;strong&gt;42. 接雨水&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定 &lt;code&gt;n&lt;/code&gt; 个非负整数表示每个宽度为 &lt;code&gt;1&lt;/code&gt; 的柱子的高度图，计算按此排列的柱子，下雨之后能接多少雨水。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.leetcode.cn/aliyun-lc-upload/uploads/2018/10/22/rainwatertrap.png&quot; alt=&quot;img&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出：6
解释：上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图，在这种情况下，可以接 6 个单位的雨水（蓝色部分表示雨水）。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：height = [4,2,0,3,2,5]
输出：9
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.Gemini的方法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;第一道困难题，果然还是做不出来...不过知道了思路后，难度会减少很多&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路: 每个柱子能积多少水取决于左右两侧第二高的柱子，柱子自身被包括在其中一个边界中，这是正确的，但从理解上有时感觉很奇怪&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func trap(height []int) int {
    left, right := 0, len(height) - 1
    leftmax, rightmax := 0, 0
    res := 0

    for left &amp;lt; right {
        leftmax = max(leftmax, height[left])
        rightmax = max(rightmax, height[right])

        if leftmax &amp;lt; rightmax {
            res += leftmax - height[left]
            left++
        }else{
            res += rightmax - height[right]
            right--
        }
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.评论区翻到的思路&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于初学者，其实这个思路挺简单的，很容易理解，我就按照评论区中顺着思路用Go写下来了。&lt;/p&gt;
&lt;p&gt;不过理解后其实还是第一种更好的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;思路:将实例图中的蓝色也看成实心的，算出每一层的面积，加起来，然后减去height的总和，剩下的就是水量。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func trap(height []int) int {
    left, right := 0, len(height) - 1
    area := 0
    sum := 0
    maxH := 0

    for _, h := range height {
        sum += h
        if h &amp;gt; maxH {
            maxH = h
        }
    }

    for h := 1; h &amp;lt;= maxH; h++ {
        for left &amp;lt; len(height) &amp;amp;&amp;amp; height[left] &amp;lt; h {
            left++
        }
        
        for right &amp;gt;= 0 &amp;amp;&amp;amp; height[right] &amp;lt; h {
            right--
        }

        if left &amp;gt; right {
            break
        }
        area += right - left + 1
    }

    return area - sum
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-151.反转字符串中的单词</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-151%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E5%8D%95%E8%AF%8D/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-151%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E5%8D%95%E8%AF%8D/</guid><pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/reverse-words-in-a-string/&quot;&gt;&lt;strong&gt;151. 反转字符串中的单词&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个字符串 &lt;code&gt;s&lt;/code&gt; ，请你反转字符串中 &lt;strong&gt;单词&lt;/strong&gt; 的顺序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;单词&lt;/strong&gt; 是由非空格字符组成的字符串。&lt;code&gt;s&lt;/code&gt; 中使用至少一个空格将字符串中的 &lt;strong&gt;单词&lt;/strong&gt; 分隔开。&lt;/p&gt;
&lt;p&gt;返回 &lt;strong&gt;单词&lt;/strong&gt; 顺序颠倒且 &lt;strong&gt;单词&lt;/strong&gt; 之间用单个空格连接的结果字符串。&lt;/p&gt;
&lt;p&gt;**注意：**输入字符串 &lt;code&gt;s&lt;/code&gt;中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中，单词间应当仅用单个空格分隔，且不包含任何额外的空格。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt; 包含英文大小写字母、数字和空格 &lt;code&gt;&apos; &apos;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt; 中 &lt;strong&gt;至少存在一个&lt;/strong&gt; 单词&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;the sky is blue&quot;
输出：&quot;blue is sky the&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;  hello world  &quot;
输出：&quot;world hello&quot;
解释：反转后的字符串中不能存在前导空格和尾随空格。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = &quot;a good   example&quot;
输出：&quot;example good a&quot;
解释：如果两个单词间有多余的空格，反转后的字符串需要将单词间的空格减少到仅有一个。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的方法(调用API)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;原来这种题不让调用啊🤔，我还在想这就是中等题吗...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func reverseWords(s string) string {
    words := strings.Fields(s)
    
    left, right := 0, len(words)-1
    for left &amp;lt; right {
        words[left], words[right] = words[right], words[left]
        left++
        right--
    }
    
    return strings.Join(words, &quot; &quot;)
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.正确的方法(双指针)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;思路:1. 移除多余空格 -&amp;gt; 2. 翻转整个字节切片 -&amp;gt; 3. 翻转每个单词&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;疑惑点:翻转每个单词，依赖后面的空格，因此最后一个单词需要额外的边界处理&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func reverseWords(s string) string {
    b := []byte(s)

    fast, slow := 0, 0
    for ; fast&amp;lt;len(b); fast++ {
        if b[fast] != &apos; &apos; {
            if slow != 0 {
                b[slow] = &apos; &apos;
                slow++
            }
            for fast&amp;lt;len(b) &amp;amp;&amp;amp; b[fast] != &apos; &apos; {
                b[slow] = b[fast]
                fast++
                slow++
            }
        }
    }

    b = b[:slow]
    reverse(b)

    start := 0
    for i := 0; i &amp;lt;= len(b); i++ {
        if i == len(b) || b[i] == &apos; &apos;{
            reverse(b[start:i])
            start = i + 1
        }
    }
    return string(b)
}

func reverse(s []byte)  {
    left := 0
    right := len(s)-1
    for left &amp;lt; right{
        s[left], s[right]= s[right], s[left]
        left++
        right--
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-27.移除元素</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-27%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-27%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0/</guid><pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/remove-element/&quot;&gt;&lt;strong&gt;27. 移除元素&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个数组 &lt;code&gt;nums&lt;/code&gt; 和一个值 &lt;code&gt;val&lt;/code&gt;，你需要 &lt;strong&gt;&lt;a href=&quot;https://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95&quot;&gt;原地&lt;/a&gt;&lt;/strong&gt; 移除所有数值等于 &lt;code&gt;val&lt;/code&gt; 的元素。元素的顺序可能发生改变。然后返回 &lt;code&gt;nums&lt;/code&gt; 中与 &lt;code&gt;val&lt;/code&gt; 不同的元素的数量。&lt;/p&gt;
&lt;p&gt;假设 &lt;code&gt;nums&lt;/code&gt; 中不等于 &lt;code&gt;val&lt;/code&gt; 的元素数量为 &lt;code&gt;k&lt;/code&gt;，要通过此题，您需要执行以下操作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更改 &lt;code&gt;nums&lt;/code&gt; 数组，使 &lt;code&gt;nums&lt;/code&gt; 的前 &lt;code&gt;k&lt;/code&gt; 个元素包含不等于 &lt;code&gt;val&lt;/code&gt; 的元素。&lt;code&gt;nums&lt;/code&gt; 的其余元素和 &lt;code&gt;nums&lt;/code&gt; 的大小并不重要。&lt;/li&gt;
&lt;li&gt;返回 &lt;code&gt;k&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [3,2,2,3], val = 3
输出：2, nums = [2,2,_,_]
解释：你的函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要（因此它们并不计入评测）。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0,1,2,2,3,0,4,2], val = 2
输出：5, nums = [0,1,4,0,3,_,_,_]
解释：你的函数应该返回 k = 5，并且 nums 中的前五个元素为 0,0,1,3,4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要（因此它们并不计入评测）。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的方法(暴力法)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这道题可以看出go还不赖，通过append能够实现切片的删除功能，不赖，不过一开始append后面没有...导致错了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func removeElement(nums []int, val int) int {
    for i :=0 ; i &amp;lt; len(nums); {
        if nums[i] == val{
            nums = append(nums[:i], nums[i+1:]...)
        }else{
            i++
        }
    }
    return len(nums)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.快慢指针&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;初识双指针&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func removeElement(nums []int, val int) int {
    slow := 0
    for fast :=0; fast&amp;lt;len(nums);fast++{
        if nums[fast] == val{
            continue
        }
        nums[slow] = nums[fast]
        slow++
    }
    return slow
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-283.移动零</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-283%E7%A7%BB%E5%8A%A8%E9%9B%B6/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-283%E7%A7%BB%E5%8A%A8%E9%9B%B6/</guid><pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/move-zeroes/&quot;&gt;&lt;strong&gt;283. 移动零&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个数组 &lt;code&gt;nums&lt;/code&gt;，编写一个函数将所有 &lt;code&gt;0&lt;/code&gt; 移动到数组的末尾，同时保持非零元素的相对顺序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;请注意&lt;/strong&gt; ，必须在不复制数组的情况下原地对数组进行操作。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: nums = [0]
输出: [0]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的方法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;可以看出不难，简单的快慢针的应用，最后被如何填充0卡住了一会儿，老想着用append，最后陷入append后，len(nums)又更长的愚蠢状况下&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func moveZeroes(nums []int)  {
    fast, slow := 0, 0
    for ; fast &amp;lt; len(nums); fast++ {
        if nums[fast] != 0 {
            nums[slow] = nums[fast]
            slow++
        }
    }   
    
    for i := slow; i &amp;lt; len(nums); i++ {
            nums[i] = 0
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-344. 反转字符串</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-344-%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-344-%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2/</guid><pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/reverse-string/&quot;&gt;&lt;strong&gt;344. 反转字符串&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;编写一个函数，其作用是将输入的字符串反转过来。输入字符串以字符数组 &lt;code&gt;s&lt;/code&gt; 的形式给出。&lt;/p&gt;
&lt;p&gt;不要给另外的数组分配额外的空间，你必须**&lt;a href=&quot;https://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95&quot;&gt;原地&lt;/a&gt;修改输入数组**、使用 O(1) 的额外空间解决这一问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = [&quot;h&quot;,&quot;e&quot;,&quot;l&quot;,&quot;l&quot;,&quot;o&quot;]
输出：[&quot;o&quot;,&quot;l&quot;,&quot;l&quot;,&quot;e&quot;,&quot;h&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：s = [&quot;H&quot;,&quot;a&quot;,&quot;n&quot;,&quot;n&quot;,&quot;a&quot;,&quot;h&quot;]
输出：[&quot;h&quot;,&quot;a&quot;,&quot;n&quot;,&quot;n&quot;,&quot;a&quot;,&quot;H&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的方法(双指针)&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于这种送分题就该重拳出击👊&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func reverseString(s []byte)  {
    left := 0
    right := len(s)-1
    for left &amp;lt; right{
        s[left], s[right]= s[right], s[left]
        left++
        right--
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-128.最长连续序列</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-128%E6%9C%80%E9%95%BF%E8%BF%9E%E7%BB%AD%E5%BA%8F%E5%88%97/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-128%E6%9C%80%E9%95%BF%E8%BF%9E%E7%BB%AD%E5%BA%8F%E5%88%97/</guid><pubDate>Sat, 21 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/longest-consecutive-sequence/&quot;&gt;&lt;strong&gt;128. 最长连续序列&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个未排序的整数数组 &lt;code&gt;nums&lt;/code&gt; ，找出数字连续的最长序列（不要求序列元素在原数组中连续）的长度。&lt;/p&gt;
&lt;p&gt;请你设计并实现时间复杂度为 &lt;code&gt;O(n)&lt;/code&gt; 的算法解决此问题。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [100,4,200,1,3,2]
输出：4
解释：最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0,3,7,2,5,8,4,6,0,1]
输出：9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [1,0,1,2]
输出：3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;其实我没太看出来，和哈希有什么关系，可能是我用了Go的sort.Ints(nums)，我的速度还挺快的，8ms，击败96.45%，😁&lt;/p&gt;
&lt;p&gt;好吧，它要求了时间复杂度是 O(n)，排序的时间复杂度是O(n log n)，其实算偏题了，但速度比哈希快也是挺奇怪的...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func longestConsecutive(nums []int) int {
    if len(nums) == 0 {
        return 0
    }
    sort.Ints(nums)
    count := 1
    max := 1
  
    for i, num := range nums {
        if i &amp;gt; 0 &amp;amp;&amp;amp; num == nums[i-1] {
            continue
        }
        if i &amp;gt; 0 &amp;amp;&amp;amp; num == nums[i-1]+1{
            count += 1
            if count &amp;gt; max{
                max = count
            }
        }else{
            count = 1
        }
    }
    return max
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.哈希表&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func longestConsecutive(nums []int) int {
    set := make(map[int]bool)
    for _, num := range nums {
        set[num] = true
    }
    maxLen := 0
    for num := range set {
        if !set[num-1] {
            curNum := num
            curLen := 1
            for set[curNum+1] {
                curNum++
                curLen++
            }
            if curLen &amp;gt; maxLen {
                maxLen = curLen
            }
        }
    }
    return maxLen
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-49. 字母异位词分组</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-49-%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D%E5%88%86%E7%BB%84/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-49-%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D%E5%88%86%E7%BB%84/</guid><pubDate>Sat, 21 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/group-anagrams/&quot;&gt;&lt;strong&gt;49. 字母异位词分组&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个字符串数组，请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输入:&lt;/strong&gt; strs = [&quot;eat&quot;, &quot;tea&quot;, &quot;tan&quot;, &quot;ate&quot;, &quot;nat&quot;, &quot;bat&quot;]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出:&lt;/strong&gt; [[&quot;bat&quot;],[&quot;nat&quot;,&quot;tan&quot;],[&quot;ate&quot;,&quot;eat&quot;,&quot;tea&quot;]]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解释：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 strs 中没有字符串可以通过重新排列来形成 &lt;code&gt;&quot;bat&quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;字符串 &lt;code&gt;&quot;nat&quot;&lt;/code&gt; 和 &lt;code&gt;&quot;tan&quot;&lt;/code&gt; 是字母异位词，因为它们可以重新排列以形成彼此。&lt;/li&gt;
&lt;li&gt;字符串 &lt;code&gt;&quot;ate&quot;&lt;/code&gt; ，&lt;code&gt;&quot;eat&quot;&lt;/code&gt; 和 &lt;code&gt;&quot;tea&quot;&lt;/code&gt; 是字母异位词，因为它们可以重新排列以形成彼此。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输入:&lt;/strong&gt; strs = [&quot;&quot;]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出:&lt;/strong&gt; [[&quot;&quot;]]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 3:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输入:&lt;/strong&gt; strs = [&quot;a&quot;]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;输出:&lt;/strong&gt; [[&quot;a&quot;]]&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;算真正意义上自己完成的hot100的第一题，虽然做了半个多小时，但还是做出来了，吼吼～&lt;/p&gt;
&lt;p&gt;感觉学哈希只学会了count[v - &apos;a&apos;]++，做出来后感觉还是挺简单的，开始困住我的是构建怎样的map，有点左右脑互搏了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func groupAnagrams(strs []string) [][]string {
   m := make(map[[26]int][]string)
   for _, str := range strs {
        count := [26]int{}
        for _, v := range str {
            count[v - &apos;a&apos;]++
        }
        m[count] = append(m[count],str)
   }   

    res := [][]string{}
    for _, v := range m {
        res =append(res, v)
    }
   return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-15.三数之和</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-15%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%8F%8C%E6%8C%87%E9%92%88/leetcode-15%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C/</guid><pubDate>Sat, 21 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;双指针&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/3sum/&quot;&gt;&lt;strong&gt;15. 三数之和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你一个整数数组 &lt;code&gt;nums&lt;/code&gt; ，判断是否存在三元组 &lt;code&gt;[nums[i], nums[j], nums[k]]&lt;/code&gt; 满足 &lt;code&gt;i != j&lt;/code&gt;、&lt;code&gt;i != k&lt;/code&gt; 且 &lt;code&gt;j != k&lt;/code&gt; ，同时还满足 &lt;code&gt;nums[i] + nums[j] + nums[k] == 0&lt;/code&gt; 。请你返回所有和为 &lt;code&gt;0&lt;/code&gt; 且不重复的三元组。&lt;/p&gt;
&lt;p&gt;**注意：**答案中不可以包含重复的三元组。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [-1,0,1,2,-1,-4]
输出：[[-1,-1,2],[-1,0,1]]
解释：
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意，输出的顺序和三元组的顺序并不重要。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0,1,1]
输出：[]
解释：唯一可能的三元组和不为 0 。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums = [0,0,0]
输出：[[0,0,0]]
解释：唯一可能的三元组和为 0 。
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.代码随想录的哈希&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;没做出来捏☹️，这个题目用哈希真的是很麻烦和恶心，对于新手来说去重真的不简单，不只是先固定a再加上二数之和这么简单。速度也很慢479ms... 之后学到双指针再看看&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func threeSum(nums []int) [][]int {
    res := make([][]int, 0)
    sort.Ints(nums)
    for i := 0; i &amp;lt; len(nums); i++ {
        if nums[i] &amp;gt; 0 {
            break
        }
        if i &amp;gt; 0 &amp;amp;&amp;amp; nums[i] == nums[i-1] {
            continue
        }
        set := make(map[int]struct{})
        for j := i + 1; j &amp;lt; len(nums); j++ {
            if j &amp;gt; i + 2 &amp;amp;&amp;amp; nums[j] == nums[j-1] &amp;amp;&amp;amp; nums[j-1] == nums[j-2] {
                continue
            }
            c := -nums[i] - nums[j]
            if _, ok := set[c]; ok {
                res = append(res, []int{nums[i], nums[j], c})
                delete(set, c)
            } else {
                set[nums[j]] = struct{}{}
            }
        }
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.双指针&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;思路：排序 + 固定基准数 &lt;code&gt;i&lt;/code&gt; + 双指针寻找另外两个数&lt;/p&gt;
&lt;p&gt;因为最大的难点就是避免重复，所以我们需要处理的是数据重复的问题。&lt;/p&gt;
&lt;p&gt;关于处理重复这个双指针和前边的值比较，还是和后边的值比较，在我自己实践中感觉本质上一样的，但是需要注意的是：&lt;/p&gt;
&lt;p&gt;和后边的值比较，需要注意边界问题，避免第一个和最后一个元素的越界&lt;/p&gt;
&lt;p&gt;和前边的值比较，会停在这一堆重复数字的最后一个上面，必须强制执行一次 &lt;code&gt;left++&lt;/code&gt; 和 &lt;code&gt;right--&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func threeSum(nums []int) [][]int {
    var res [][]int
    n := len(nums)
    if n &amp;lt; 3 {
        return res
    }

    sort.Ints(nums)

    for i := 0; i &amp;lt; n-2; i++ {
        if nums[i] &amp;gt; 0 {
            break
        }

        if i &amp;gt; 0 &amp;amp;&amp;amp; nums[i] == nums[i-1] {
            continue
        }

        left := i + 1
        right := n - 1

        for left &amp;lt; right {
            sum := nums[i] + nums[left] + nums[right]

            if sum == 0 {
                res = append(res, []int{nums[i], nums[left], nums[right]})
                
                for left &amp;lt; right &amp;amp;&amp;amp; nums[left] == nums[left+1] {
                    left++
                }
               
                for left &amp;lt; right &amp;amp;&amp;amp; nums[right] == nums[right-1] {
                    right--
                }
                
                left++
                right--
            } else if sum &amp;lt; 0 {
                left++ 
            } else {
                right-- 
            }
        }
    }

    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-202.快乐数</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-202%E5%BF%AB%E4%B9%90%E6%95%B0/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-202%E5%BF%AB%E4%B9%90%E6%95%B0/</guid><pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/happy-number/&quot;&gt;&lt;strong&gt;202.快乐数&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;编写一个算法来判断一个数 &lt;code&gt;n&lt;/code&gt; 是不是快乐数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;「快乐数」&lt;/strong&gt; 定义为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于一个正整数，每一次将该数替换为它每个位置上的数字的平方和。&lt;/li&gt;
&lt;li&gt;然后重复这个过程直到这个数变为 1，也可能是 &lt;strong&gt;无限循环&lt;/strong&gt; 但始终变不到 1。&lt;/li&gt;
&lt;li&gt;如果这个过程 &lt;strong&gt;结果为&lt;/strong&gt; 1，那么这个数就是快乐数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果 &lt;code&gt;n&lt;/code&gt; 是 &lt;em&gt;快乐数&lt;/em&gt; 就返回 &lt;code&gt;true&lt;/code&gt; ；不是，则返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 19
输出：true
解释：
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：n = 2
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;提示：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;`1 &amp;lt;= n &amp;lt;= 231 - 1&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;思路:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其实就是两步: 1.求和 2.&lt;strong&gt;判断是否循环&lt;/strong&gt;(也是被无限循环吓住了)&lt;/p&gt;
&lt;p&gt;**难点:**就是理解快乐数为什么不像 π 一样无限循环?&lt;/p&gt;
&lt;p&gt;一个 10 位数最大约 99 亿，但它的各位平方和最大只有 92×10=81092×10=810。所以不管起点多大，经过一次计算，数字就会迅速掉到一个较小的范围内,越来越小&lt;/p&gt;
&lt;p&gt;快乐数序列要么最终停在 1（1 本身也是循环），要么进入一个不含 1 的循环，&lt;strong&gt;绝不会无限不循环地走下去&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func isHappy(n int) bool {
    m := make(map[int]bool)
    for n != 1 &amp;amp;&amp;amp; !m[n] {
        n, m[n] = getSum(n), true
    }
    return n == 1
}

func getSum(n int) int {
    sum := 0
    for n &amp;gt; 0 {
        sum += (n % 10) * (n % 10)
        n = n / 10
    }
    return sum
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-242.有效的字母异位词</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-242%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-242%E6%9C%89%E6%95%88%E7%9A%84%E5%AD%97%E6%AF%8D%E5%BC%82%E4%BD%8D%E8%AF%8D/</guid><pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/valid-anagram/&quot;&gt;&lt;strong&gt;242.有效的字母异位词&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个字符串 &lt;code&gt;s&lt;/code&gt; 和 &lt;code&gt;t&lt;/code&gt; ，编写一个函数来判断 &lt;code&gt;t&lt;/code&gt; 是否是 &lt;code&gt;s&lt;/code&gt; 的 字母异位词。&lt;/p&gt;
&lt;p&gt;字母异位词是通过重新排列不同单词或短语的字母而形成的单词或短语，并使用所有原字母一次。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;anagram&quot;, t = &quot;nagaram&quot;
输出: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入: s = &quot;rat&quot;, t = &quot;car&quot;
输出: false
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func isAnagram(s string, t string) bool {
    record := [26]int{}
    for _, i := range s {
        record[i - rune(&apos;a&apos;)]++
    }

    for _, i := range t {
        record[i - rune(&apos;a&apos;)]--
    }

    return record == [26]int{}
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-349.两个数组的交集</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-349%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-349%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%BA%A4%E9%9B%86/</guid><pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/intersection-of-two-arrays/&quot;&gt;&lt;strong&gt;349.两个数组的交集&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定两个数组 &lt;code&gt;nums1&lt;/code&gt; 和 &lt;code&gt;nums2&lt;/code&gt; ，返回 &lt;em&gt;它们的 交集&lt;/em&gt; 。输出结果中的每个元素一定是 &lt;strong&gt;唯一&lt;/strong&gt; 的。我们可以 &lt;strong&gt;不考虑输出结果的顺序&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums1 = [1,2,2,1], nums2 = [2,2]
输出：[2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出：[9,4]
解释：[4,9] 也是可通过的
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法&lt;/strong&gt;（在&lt;a href=&quot;https://leetcode.cn/problems/valid-anagram/&quot;&gt;&lt;strong&gt;242.有效的字母异位词&lt;/strong&gt;&lt;/a&gt;的基础上修改）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func intersection(nums1 []int, nums2 []int) []int {
    record1 := make(map[int]int)
    for _, i := range nums1{
        record1[i]++
    }

    record2 := make(map[int]int)
    for _, i := range nums2{
        record2[i]++
    }

    output := []int{}
    for i := range record1{
        if record2[i] &amp;gt; 0{
            output = append(output, i)
        }
    }

    return output
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.使用字典和集合(代码随想录)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func intersection(nums1 []int, nums2 []int) []int {
    set:=make(map[int]struct{},0)  // 用map模拟set
    res:=make([]int,0)
    for _,v:=range nums1{
        if _,ok:=set[v];!ok{
            set[v]=struct{}{}
        }
    }
    for _,v:=range nums2{
        //如果存在于上一个数组中，则加入结果集，并清空该set值
        if _,ok:=set[v];ok{
            res=append(res,v)
            delete(set, v)
        }
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3.使用数组&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;和我的方法差不多，但感觉更精准，符合取交集这个要求&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func intersection(nums1 []int, nums2 []int) []int {
    count1 := make([]int, 1001, 1001)
    count2 := make([]int, 1001, 1001)
    res := make([]int, 0)
    for _, v := range nums1 {
        count1[v] = 1
    }
    for _, v := range nums2 {
        count2[v] = 1
    }
    for i := 0; i &amp;lt;= 1000; i++ {
        if count1[i] + count2[i] == 2 {
            res = append(res, i)
        }
    }
    return res
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-383. 赎金信</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-383-%E8%B5%8E%E9%87%91%E4%BF%A1/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-383-%E8%B5%8E%E9%87%91%E4%BF%A1/</guid><pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/ransom-note/&quot;&gt;&lt;strong&gt;383. 赎金信&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你两个字符串：&lt;code&gt;ransomNote&lt;/code&gt; 和 &lt;code&gt;magazine&lt;/code&gt; ，判断 &lt;code&gt;ransomNote&lt;/code&gt; 能不能由 &lt;code&gt;magazine&lt;/code&gt; 里面的字符构成。&lt;/p&gt;
&lt;p&gt;如果可以，返回 &lt;code&gt;true&lt;/code&gt; ；否则返回 &lt;code&gt;false&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;magazine&lt;/code&gt; 中的每个字符只能在 &lt;code&gt;ransomNote&lt;/code&gt; 中使用一次。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：ransomNote = &quot;a&quot;, magazine = &quot;b&quot;
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：ransomNote = &quot;aa&quot;, magazine = &quot;ab&quot;
输出：false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：ransomNote = &quot;aa&quot;, magazine = &quot;aab&quot;
输出：true
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.自己的解法&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我做到了，自己完成，秒杀，哈哈哈！！！&lt;/p&gt;
&lt;p&gt;(没想到我三个循环比代码随想录的两个循环一个判断要快5ms，amazing)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func canConstruct(ransomNote string, magazine string) bool {
    m := make(map[rune]int)
    for _, i := range magazine {
        m[i-&apos;a&apos;]++
    }

    for _, i := range ransomNote {
        m[i-&apos;a&apos;]-- 
    }

    for _, i := range m {
        if i &amp;lt; 0 {
            return false
        }
    }

    return true
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>LeetCode-454.四数相加II</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-454%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0ii/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-454%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0ii/</guid><pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/4sum-ii/&quot;&gt;&lt;strong&gt;454.四数相加II&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给你四个整数数组 &lt;code&gt;nums1&lt;/code&gt;、&lt;code&gt;nums2&lt;/code&gt;、&lt;code&gt;nums3&lt;/code&gt; 和 &lt;code&gt;nums4&lt;/code&gt; ，数组长度都是 &lt;code&gt;n&lt;/code&gt; ，请你计算有多少个元组 &lt;code&gt;(i, j, k, l)&lt;/code&gt; 能满足：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0 &amp;lt;= i, j, k, l &amp;lt; n&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出：2
解释：
两个元组如下：
1. (0, 0, 0, 1) -&amp;gt; nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -&amp;gt; nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入：nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出：1
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;代码随想路&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;感觉是对直接四个循环的优化，通过一个哈希储存数据减少循环,拿空间换时间&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
    m :=make(map[int]int)
    count := 0
    for _, i := range nums1 {
        for _, j := range nums2{
            m[i + j]++
        }
    }

    for _, i := range nums3 {
        for _, j := range nums4{
            if v , ok := m[-i - j]; ok{
                count += v
            }
        }
    }

    return count
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>第十九周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2026-01-21-25%E7%A7%8Bweekly19/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2026-01-21-25%E7%A7%8Bweekly19/</guid><pubDate>Wed, 21 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;考试考完了！！！&lt;/p&gt;
&lt;p&gt;考试考完了！！&lt;/p&gt;
&lt;p&gt;考试考完了！&lt;/p&gt;
&lt;p&gt;复活了！&lt;/p&gt;
&lt;p&gt;复活了！！&lt;/p&gt;
&lt;p&gt;复活了！！！&lt;/p&gt;
</content:encoded></item><item><title>第十四周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-12-15-weekly14/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-12-15-weekly14/</guid><pubDate>Mon, 15 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这周由于生病+六级考试的原因，其实没什么时间学习，不过倒也做了一点和学了点东西。不过马上就要期末考了，之后估计主要去看大物和概率论了(备考压力还是有点大的)，可能偶尔会继续学习吧...&lt;/p&gt;
&lt;p&gt;还有好多要学习啊🥲，docker、消息队列、微服务、八股、算法......感觉学前都很难、学后就觉得是简单的掉包罢了(虽然事实如此)，人果然不能共情自己&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;这周主要是对我的小项目完成了暂时的功能(业务?)设计的实现，包括用分页展示note的社区(之后可能会用游标)、所有展示笔记类似的功能(像返回最近记录、展示star的内容、获取关注的人的笔记推送等)、实现关注和取关的功能。&lt;/li&gt;
&lt;li&gt;优化并修复了些代码，像把redis的实现从全局变量这种简单粗暴的方式改为了依赖注入，更加严谨一点&lt;/li&gt;
&lt;li&gt;了解了一些消息队列的还是，在小项目中成功连接了rabbitMQ，初步学习了相关文档，准备进一步的学习后进行部署和应用&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;学习和应用rabbitMQ&lt;/li&gt;
&lt;li&gt;学习和使用docker&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>第十三周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-12-08-weekly13/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-12-08-weekly13/</guid><pubDate>Mon, 08 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;由于上周还是上上周，我提过这版的goland内置API过低连接不上docker，因为懒得回退版本，所以没有选择去看docker，这周我主要是一直在为小项目添砖加瓦吧，完成了user的全部功能，给note也添加了部分功能，其实现在看虽然不是完成品，但我感觉也很不赖了。其实完成一个小项目确实不是什么难事，只需要回最基础的gin+gorm和强大的AI即可&lt;/p&gt;
&lt;p&gt;现在看什么笔记，备忘录，文档确实是差不多东西的玩意儿&lt;/p&gt;
&lt;p&gt;GO～（摩托声）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;完成了所有user需要的功能(自认为，仅限后端部分)，包括这周完成的修改密码、个人主页部分，和之前已经完成的注册、登入和登出&lt;/li&gt;
&lt;li&gt;完成了一些note的功能，包括添加了简单的搜索功能、置顶功能、点赞(收藏/star)功能、添加isprivate和favoritecount字段，为未来我伟大的explore/community功能打下伏笔（不过这样看怎么有点像小红书了？），还有一两个还没完成的功能。(不过AI建议我还要加上事务等工具完善，现在太简陋了😭)&lt;/li&gt;
&lt;li&gt;查询了一下，发现note的一些功能是需要与前端合作的，像自动保存和富文本，只能暂且放下(怪不得cyjj没完成这些)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Goland更新了！修复好了连接docker的bug，或许学学docker&lt;/li&gt;
&lt;li&gt;或许继续完善功能(感觉单靠gin+gorm+redis快要到极限了)&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>第十二周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-12-01-weekly12/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-12-01-weekly12/</guid><pubDate>Mon, 01 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这周，我实践的不是很多，只是在上周完成了redis的应用部署情况下继续部署。在回顾整个项目时也是发现了新的感悟和不足，redis虽然也叫数据库，但更多是进行性能优化的功能，如果是一个小项目只用gin和gorm就够了。我现在发现虽然我知道了中间件的洋葱模型，但我不太理解他在整个过程中的逻辑思路，并且发现了一些其他的不足&lt;/p&gt;
&lt;p&gt;我好菜啊...🥲&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;用redis进行了更多的部署，包括用户会话管理(加上了黑名单)，实现了登出功能。&lt;/li&gt;
&lt;li&gt;设置了随机过期时间防止雪崩，了解了防击穿(我现在似乎用不上所以只知道是用redis的锁)，实行了降级策略（避免redis挂了，程序无法运行）&lt;/li&gt;
&lt;li&gt;实现了最近访问记录功能&lt;/li&gt;
&lt;li&gt;回顾了整个代码（之前有点囫囵吞枣，像jwt的一些方法我都不太了解）。记住了一些常用的方法：json包里的&lt;code&gt;marshal&lt;/code&gt;和&lt;code&gt;Unmarshal&lt;/code&gt;([]byte和数据结构的转换),，jwt包的&lt;code&gt;parse&lt;/code&gt;(需要的密匙，非要用函数作为参数来传递)和&lt;code&gt;ParseUnverified&lt;/code&gt;(有三个返回值了还能填充claims，太高级了)&lt;/li&gt;
&lt;li&gt;在实现相关功能时了解了一些&lt;code&gt;go-redis的api&lt;/code&gt;(其实感觉和redis操作差不多，方法名字都一样，不过老是要使用context参数和结尾加个result()有点麻烦，所以去封装了一下，不过封装多了感觉其实差不多)&lt;/li&gt;
&lt;li&gt;做了一道力扣😄&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;没想好，哈哈哈&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>LeetCode 1.两数之和</title><link>https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-1%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E7%AE%97%E6%B3%95/%E5%93%88%E5%B8%8C/leetcode-1%E4%B8%A4%E6%95%B0%E4%B9%8B%E5%92%8C/</guid><pubDate>Tue, 25 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;哈希表&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/two-sum/&quot;&gt;&lt;strong&gt;1. 两数之和&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个整数数组 &lt;code&gt;nums&lt;/code&gt; 和一个整数目标值 &lt;code&gt;target&lt;/code&gt;，请你在该数组中找出 &lt;strong&gt;和为目标值&lt;/strong&gt; &lt;em&gt;&lt;code&gt;target&lt;/code&gt;&lt;/em&gt; 的那 &lt;strong&gt;两个&lt;/strong&gt; 整数，并返回它们的数组下标。&lt;/p&gt;
&lt;p&gt;你可以假设每种输入只会对应一个答案，并且你不能使用两次相同的元素。&lt;/p&gt;
&lt;p&gt;你可以按任意顺序返回答案。&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例 1：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;输入：nums = [2,7,11,15], target = 9 输出：[0,1] 解释：因为 nums[0] + nums[1] == 9 ，返回 [0, 1] 。&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 2：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;输入：nums = [3,2,4], target = 6 输出：[1,2]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;示例 3：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;输入：nums = [3,3], target = 6
输出：[0,1]&lt;/p&gt;
&lt;hr /&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1.最简单暴力的(自己很久前的解法)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func twoSum(nums []int, target int) []int {
    for i := 0; i &amp;lt; len(nums); i++ {
        for j := i + 1; j &amp;lt; len(nums); j++ {
            if nums[i] + nums[j] == target {
                return []int{i, j}  
            }
        }
    }
    return nil
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.现在的&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AI告诉我说要先检查后储存，我把m[num] = i放前面 竟然是错了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;func twoSum(nums []int, target int) []int {
    m := make(map[int]int)
    for i , num := range nums {
        need := target - num
        if j , ok := m[need] ; ok{
            return []int{j, i}
        }
        m[num] = i
    }
    return nil
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>第十一周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-24-weekly11/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-24-weekly11/</guid><pubDate>Mon, 24 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这周我认为过的不赖，无论是学习还是游戏，我能够记得我周一至周日每天的所作所为，不是一种浑浑噩噩的生活。这周可以说是恢复了一些学习的感觉，回顾了并发、学习了redis，添加了缓存，安装了docker，也和朋友一起玩了好久的瓦，这周过的真不赖☺️&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;对并发进行了回顾和拓展，更加地理解了生产者-消费者模型，更加了解一些同步原语(Sync包)内除了waitgroup和mutex的一些内容，sync.Once，sync.Map和sync.Cond。同时了解一些并发模型，理发师问题，哲学家吃饭问题和读者写者问题。&lt;/li&gt;
&lt;li&gt;对redis的5种类型string，list，hash，set和zset的各种操作进行了了解和实践&lt;/li&gt;
&lt;li&gt;完成了对小项目的redis的连接，并在应用层对Get和用户登入添加了缓存化处理，对create，update和delete添加了缓存失效处理。&lt;/li&gt;
&lt;li&gt;安装了docker，原本打算完成最基础的Goland对docker连接等基础的操作部署，不过由于Goland的内置docker版本太低，被新版的docker拒绝，先暂且搁置&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;对小项目增加更多的redis部署，Redis连接失败时的降级策略等东西&lt;/li&gt;
&lt;li&gt;不知道&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>一些并发的模型</title><link>https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-11-18-%E5%B9%B6%E5%8F%91%E6%A8%A1%E5%9E%8B/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-11-18-%E5%B9%B6%E5%8F%91%E6%A8%A1%E5%9E%8B/</guid><pubDate>Tue, 18 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 生产者-消费者模型&lt;/h2&gt;
&lt;p&gt;这是最基础、最常用、也是最实用的模型。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有两个或多个&lt;strong&gt;生产者&lt;/strong&gt;线程，它们生产数据（或任务）并放入一个共享的&lt;strong&gt;缓冲区&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;有一个或多个&lt;strong&gt;消费者&lt;/strong&gt;线程，它们从缓冲区中取出数据（或任务）并进行处理。&lt;/li&gt;
&lt;li&gt;生产者和消费者之间通过这个缓冲区进行&lt;strong&gt;解耦&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;核心挑战&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;缓冲区为空&lt;/strong&gt;：消费者不能从空缓冲区取数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缓冲区已满&lt;/strong&gt;：生产者不能向已满的缓冲区放数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;竞态条件&lt;/strong&gt;：对缓冲区的访问必须是互斥的，防止多个线程同时修改导致数据不一致。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

type Task struct {
    Runnable func(workerId int)
}

func main() {
    // 一个负责任务分发的管道
    ch := make(chan Task, 10)

    // 启动几个 worker 负责处理任务
    for id := range 10 {
        go func(workerId int) {
            for t := range ch {
                t.Runnable(workerId)
            }
        }(id)
    }

    // 任务分发
    for i := range 20 {
	    j := i
        t1 := Task{
            Runnable: func(workerId int) {
                fmt.Printf(&quot;workerId%v：task%v做一件事情\n&quot;, workerId, j)
            },
        }
        ch &amp;lt;- t1
    }
    time.Sleep(1 * time.Second)
    close(ch)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现实应用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;消息队列（如Kafka, RabbitMQ）。&lt;/li&gt;
&lt;li&gt;线程池任务调度。&lt;/li&gt;
&lt;li&gt;Golang中的Channel，Java中的 &lt;code&gt;BlockingQueue&lt;/code&gt; 其底层思想就是生产者-消费者模型。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 读者-写者问题&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：在读多写少的问题中，对读写锁的使用，写锁类似于互斥锁，读锁类似于共享锁（能开多个）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;读者&lt;/strong&gt;只读取共享数据，不修改，&lt;strong&gt;写者&lt;/strong&gt;会修改共享数据。&lt;strong&gt;允许多个读者同时读&lt;/strong&gt;，但&lt;strong&gt;写者必须独占访问&lt;/strong&gt;（即写时不能有读者或其他写者）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心挑战&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在保证数据一致性的前提下，最大限度地提高并发性（特别是对读者）。&lt;/li&gt;
&lt;li&gt;可能导致&lt;strong&gt;写者饥饿&lt;/strong&gt;：如果读者源源不断，写者可能永远无法获得访问权。&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	var (
		data    int
		rwMutex sync.RWMutex // 读写锁
		wg      sync.WaitGroup
	)

	// 写者
	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i &amp;lt; 5; i++ {
			rwMutex.Lock() // 写锁
			data = i
			fmt.Printf(&quot;写入: %d\n&quot;, i)
			time.Sleep(time.Millisecond * 200)
			rwMutex.Unlock()
			time.Sleep(time.Millisecond * 100)
		}
	}()

	// 读者（多个）
	for i := 0; i &amp;lt; 3; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			for j := 0; j &amp;lt; 5; j++ {
				rwMutex.RLock() // 读锁
				fmt.Printf(&quot;读者%d 读取: %d\n&quot;, id, data)
				time.Sleep(time.Millisecond * 50)
				rwMutex.RUnlock()
				time.Sleep(time.Millisecond * 100)
			}
		}(i)
	}

	wg.Wait()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现实应用&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据库的并发控制。&lt;/li&gt;
&lt;li&gt;文件系统、缓存的访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 哲学家就餐问题&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：避免&lt;strong&gt;多个进程（或线程）竞争有限资源时&lt;/strong&gt;的死锁问题，通过特定的策略(破坏循环)或限制并发度（筷子数量）等方法，解决死锁问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;五个哲学家围坐在一张圆桌旁，他们的一生只在做两件事：&lt;strong&gt;思考&lt;/strong&gt;和&lt;strong&gt;吃饭&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;桌上有五根筷子（不是五双），每两个哲学家之间有一根。&lt;/li&gt;
&lt;li&gt;哲学家吃饭时需要同时拿起他&lt;strong&gt;左边和右边&lt;/strong&gt;的筷子。&lt;/li&gt;
&lt;li&gt;如果筷子在别人手里，他就必须等待。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;核心挑战&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;死锁&lt;/strong&gt;：如果所有哲学家同时感到饥饿，并同时拿起自己左边的筷子，那么所有人都会永远等待右边的筷子被释放，导致系统僵住。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	// 5根筷子（互斥锁）
	chopsticks := make([]sync.Mutex, 5)
	var wg sync.WaitGroup

	// 哲学家函数
	philosopher := func(id int) {
		defer wg.Done()
		
		left := id
		right := (id + 1) % 5

		// 避免死锁：编号为偶数的哲学家先拿左边，奇数先拿右边
		for i := 0; i &amp;lt; 3; i++ { // 吃3次
			if id%2 == 0 {
				chopsticks[left].Lock()
				chopsticks[right].Lock()
			} else {
				chopsticks[right].Lock()
				chopsticks[left].Lock()
			}

			// 拿到两根筷子，开始吃饭
			fmt.Printf(&quot;哲学家%d 正在吃饭...\n&quot;, id)
			time.Sleep(time.Millisecond * 100)

			// 放下筷子
			chopsticks[left].Unlock()
			chopsticks[right].Unlock()

			// 思考
			fmt.Printf(&quot;哲学家%d 正在思考...\n&quot;, id)
			time.Sleep(time.Millisecond * 100)
		}
	}

	// 启动5个哲学家
	for i := 0; i &amp;lt; 5; i++ {
		wg.Add(1)
		go philosopher(i)
	}

	wg.Wait()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现实应用&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;任何需要获取多个互斥资源才能工作的场景，比如进程需要同时锁定多个数据库记录进行更新。&lt;/p&gt;
&lt;h2&gt;4. 理发师问题&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：模拟有容量限制的服务系统，通过&lt;strong&gt;空结构体&lt;/strong&gt;(似乎叫信号量)来实现请求者与服务者的同步，并实现超容量时的拒绝和服务者的空闲/工作状态转换。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个理发店有一个理发师（服务线程）、一把理发椅（临界资源）和N把供顾客等待的椅子（等待队列）。&lt;/li&gt;
&lt;li&gt;如果没有顾客，理发师就在理发椅上睡觉。&lt;/li&gt;
&lt;li&gt;顾客到来时，如果理发师在睡觉，就叫醒他理发。&lt;/li&gt;
&lt;li&gt;如果理发师在忙，顾客就坐在等待椅上等待。&lt;/li&gt;
&lt;li&gt;如果等待椅也坐满了，顾客就会离开。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;核心挑战&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;协调理发师（服务者）和顾客（请求者）的睡眠与唤醒。&lt;/li&gt;
&lt;li&gt;管理有限的等待队列。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	// 理发店参数
	const (
		waitingChairs = 3 // 等待椅数量
		totalCustomers = 10 // 总顾客数
	)

	var (
		waitingRoom = make(chan struct{}, waitingChairs) // 等待室（缓冲channel）
		wg          sync.WaitGroup
		barberReady = make(chan struct{}, 1) // 理发师就绪信号
	)

	// 理发师
	wg.Add(1)
	go func() {
		defer wg.Done()
		for {
			select {
			case &amp;lt;-waitingRoom:
				// 有顾客，开始理发
				barberReady &amp;lt;- struct{}{} // 理发师准备就绪
				fmt.Println(&quot;理发师正在理发...&quot;)
				time.Sleep(time.Millisecond * 200) // 理发时间
				fmt.Println(&quot;理发完成！&quot;)
			default:
				// 没有顾客，睡觉
				fmt.Println(&quot;理发师在睡觉...&quot;)
				time.Sleep(time.Millisecond * 500)
			}
		}
	}()

	// 顾客
	for i := 0; i &amp;lt; totalCustomers; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			time.Sleep(time.Millisecond * time.Duration(rand.Intn(300)))

			select {
			case waitingRoom &amp;lt;- struct{}{}:
				// 成功进入等待室
				fmt.Printf(&quot;顾客%d 在等待理发\n&quot;, id)
				&amp;lt;-barberReady // 等待理发师就绪
				fmt.Printf(&quot;顾客%d 正在理发\n&quot;, id)
			default:
				// 等待室满了，离开
				fmt.Printf(&quot;顾客%d 看到等待室满了，离开了\n&quot;, id)
			}
		}(i)
	}

	// 等待所有顾客完成
	time.Sleep(time.Second * 3)
	fmt.Println(&quot;营业结束&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;现实应用&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;线程池或服务器模型。例如，一个Web服务器有固定数量的工作线程（理发师）和一个最大连接队列（等待椅）。当新请求到达时，如果有空闲线程则立即处理，否则进入队列等待，如果队列也满了，则返回“服务器繁忙”错误。&lt;/p&gt;
</content:encoded></item><item><title>并发</title><link>https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-11-18-%E5%B9%B6%E5%8F%91/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-11-18-%E5%B9%B6%E5%8F%91/</guid><pubDate>Tue, 18 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;并发&lt;/h2&gt;
&lt;p&gt;什么是并发？我的理解是&lt;strong&gt;并发是关于如何让一个系统在面对多个任务时，既能高效地利用资源，又能正确地协调它们之间的交互&lt;/strong&gt;。在《戴森球计划》等游戏运行时，CPU满载运行时渲染的蓝色洪流，我认为是对并发/并行最完美的具象化呈现。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先说进程。&lt;/strong&gt; 进程是一个正在运行的程序实例，Chrome浏览器和Word文档，它们就是两个不同的进程。操作系统会为每个进程分配彼此隔离的用户空间，并把它们交给 CPU 调度执行。一个应用可以只开一个进程，也可以开很多个，这取决于应用自身；对操作系统来说，进程之间没有啥区别，它只负责把要跑的活儿交给 CPU。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;那一颗 CPU 怎么“同时”跑这么多东西？&lt;/strong&gt; 关键在于“时间片”。单个 CPU 核心同一时刻只能执行一个任务，但操作系统会把时间切成很细的片段，轮流把这些时间片分给不同的可运行实体。每个时间片到了就切换到下一个，如此快速轮转，让我们主观上感觉“所有程序都在同时跑”。&lt;strong&gt;这就是并发&lt;/strong&gt;，宏观上的并行，微观上的交替。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;再说线程。线程是操作系统调度的最小单位&lt;/strong&gt;，线程通常对应一个功能。一个进程至少包含一个线程；所谓“调度进程”本质上是在&lt;strong&gt;调度进程里的线程&lt;/strong&gt;。同一进程中的线程共享进程的资源，但各自拥有独立的栈（栈主要是负责存局部变量和函数调用栈等数据的）。&lt;/p&gt;
&lt;p&gt;线程大致分两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内核级线程&lt;/strong&gt;：创建、销毁、调度与上下文切换由内核完成，需要系统调用，开销相对更高。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户级线程(协程)&lt;/strong&gt;：在线程库/运行时于用户态完成调度与切换，通常只在必要时与少量内核线程关联，因而切换开销更小。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;goroutine 就是一种用户级线程&lt;/strong&gt; 它由 Go 运行时在用户态调度，创建成本低、切换轻量，还配有按需增长的栈。运行时采用 M:N 调度（后面可以了解一下 &lt;strong&gt;GMP 模型&lt;/strong&gt;），把大量 goroutine 映射到少量内核线程上，从而在保持高并发的同时控制系统调用与上下文切换的成本。&lt;/p&gt;
&lt;h2&gt;Goroutine&lt;/h2&gt;
&lt;p&gt;Go语言中使用goroutine非常简单，只需要在调用函数的时候在前面加上go关键字，就可以为一个函数创建一个goroutine。一个goroutine必定对应一个函数，可以创建多个goroutine去执行相同的函数。&lt;/p&gt;
&lt;p&gt;我们想要实现一下用 10 个协程去累加一个数字，每个协程将这个变量自增 10w 次，我们期望得到 100w 的结果&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

func main() {
    sum := 0
    for range 10 {
        go func() {
            for range 100000 {
                sum += 1
            }
        }()
    }
    time.Sleep(1 * time.Second)
    fmt.Println(sum)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果呢？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;root@RINAI-SWORD:/project/lanshan/count# go run ./
569738
root@RINAI-SWORD:/project/lanshan/count# go run ./
503786
root@RINAI-SWORD:/project/lanshan/count# go run ./
595125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;得到是不确定的数字，可能有人觉得奇怪，但是在现实中，这才是符合预期的，你如果把数值调小，让多个线程累加到 100 或者 1000，你的结果可能正是你期望的，但是仅仅是因为样本数量太少而没有引发多线程出现的问题。&lt;/p&gt;
&lt;p&gt;那么为什么会出现这种结果？&lt;/p&gt;
&lt;p&gt;这涉及到我们 cpu 的工作原理，我们的一条自增 ++ 代码，在 cpu 层面并不是原子执行的，实际上，一个简单的自增在计算机层面会是这样的顺序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1. cpu 从指定内存读取 sum 的值
2. cpu 将 sum + 1。
3. cpu 将 sum 写回指定内存。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;大概是这三个步骤，那么在多线程场景下思考，只要在 1 -&amp;gt; 2 的间隙发生线程切换，这里线程切换会将当前线程中的某些上下文数据保存下来到内存中，等到切换回线程1的时候就会从内存中恢复这些数据到 cpu 中，在另一个线程中执行了 sum + 1，就会导致我们当前 cpu 读取的数值是旧的，比如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;线程1：cpu 读取到 sum = 10。
线程2：cpu 读取到 sum = 10。
线程2：cpu 将 sum + 1。
线程2：cpu 回写 sum，此时 sum = 11。
线程1：cpu 根据读取到的 sum + 1。
线程1：cpu 回写 sum，此时 sum = 11.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;由此可见，多线程虽然利用多核的优势，但是也给我们带来了一些麻烦。因此，我们需要同步原语，以消除这种不确定性，在并发环境中强制实现“顺序”和“互斥”&lt;/p&gt;
&lt;h2&gt;原子性和原子操作&lt;/h2&gt;
&lt;p&gt;原子性的核心目标是&lt;strong&gt;保证数据在并发访问下的一致性&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在多线程/多核环境中，操作系统会随时在不同的线程之间进行切换，如果一个非原子操作执行到一半被中断，而另一个线程又来读取或修改相同的数据，结果将是不可预测的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;通常是原子的（在主流32/64位CPU上）：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读取或写入一个&lt;strong&gt;对齐的、原生数据类型&lt;/strong&gt;（如在Go中，&lt;code&gt;int32&lt;/code&gt;、&lt;code&gt;int64&lt;/code&gt;、&lt;code&gt;bool&lt;/code&gt;等变量的单次读或写）通常是原子的。这意味着你不会读到半个写操作的结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;通常不是原子的（需要额外保护）：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;任何需要多个步骤的操作：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;​	对结构体、切片、映射等复杂数据结构的修改。&lt;/p&gt;
&lt;p&gt;​	在32位系统上对64位变量的读写（如 &lt;code&gt;int64&lt;/code&gt;），可能需要两条指令来完成。&lt;/p&gt;
&lt;p&gt;**原子操作：**Go中 &lt;code&gt;sync/atomic&lt;/code&gt; 包，封装了底层的硬件原子指令，提供了如 &lt;code&gt;atomic.AddInt32&lt;/code&gt;、&lt;code&gt;atomic.LoadPointer&lt;/code&gt;、&lt;code&gt;atomic.CompareAndSwapUint64&lt;/code&gt; 等函数。&lt;/p&gt;
&lt;h2&gt;Channel&lt;/h2&gt;
&lt;p&gt;&quot;&lt;strong&gt;不要通过共享内存来通信，而要通过通信来共享内存&lt;/strong&gt;&quot;，这句话便是 Go 语言的并发哲学，什么意思？就是说，如果两个 goroutine 希望共享一个变量，不应该通过一个外部的全局变量来进行加锁读写，而是应该通过 channel 将 goroutine A 中的变量传递给 goroutine B。&lt;/p&gt;
&lt;p&gt;下面是一个任务调度器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;time&quot;
)

type Task struct {
    // 函数也可以是结构体的成员
    Runnable func(workerId int)
}

func main() {
    // 一个负责任务分发的管道
    ch := make(chan Task, 10)

    // 启动几个 worker 负责处理任务
    for id := range 10 {
        go func(workerId int) {
            for t := range ch {
                t.Runnable(workerId)
            }
        }(id)
    }

    // 任务分发
    for i := range 20 {
	    j := i
        t1 := Task{
            Runnable: func(workerId int) {
                fmt.Printf(&quot;workerId%v：task%v做一件事情\n&quot;, workerId, j)
            },
        }
        ch &amp;lt;- t1
    }
    time.Sleep(1 * time.Second)
    close(ch)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;select 关键字&lt;/h2&gt;
&lt;p&gt;用于处理多个通道的读写操作，类似于&lt;code&gt;switch&lt;/code&gt;，每个case都是通道操作，但是最终只会执行一个(如果多个通道同时接收到数值，会随机选择一个进行接收)。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	tick := time.Tick(100 * time.Millisecond)
	boom := time.After(500 * time.Millisecond)
	for {
		select {
		case &amp;lt;-tick:
			fmt.Println(&quot;tick.&quot;)
		case &amp;lt;-boom:
			fmt.Println(&quot;BOOM!&quot;)
			return
		default:
			fmt.Println(&quot;    .&quot;)
			time.Sleep(50 * time.Millisecond)
		}
	}
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;同步原语(Sync包)&lt;/h2&gt;
&lt;h3&gt;1 .WaitGroup&lt;/h3&gt;
&lt;p&gt;它提供了一种简单、同步的方式，让一个 Goroutine（通常是主 Goroutine）能够阻塞，直到其他多个 Goroutine 都完成它们的工作。它只有三个方法&lt;code&gt;Add(delta int)&lt;/code&gt;、&lt;code&gt;Done()&lt;/code&gt;和&lt;code&gt;Wait()&lt;/code&gt;，功能正如字面意思一样。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
)

func main() {
    wg := sync.WaitGroup{}
    for range 10 {
        // wg.Add 计数器+1，代表添加一个执行任务
        wg.Add(1)
        go func() {
            fmt.Println(1)
            // wg.Done() 计数器-1，代表执行完成
            wg.Done()
        }()
    }
    // 等待 Add 的任务全部 Done
    wg.Wait()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;2 .Mutex互斥锁&lt;/h2&gt;
&lt;p&gt;对于&lt;strong&gt;同一把&lt;/strong&gt;互斥锁：同一时间&lt;strong&gt;只能有一个&lt;/strong&gt;协程获得锁，当锁被持有时，其他协程尝试加锁会&lt;strong&gt;被阻塞&lt;/strong&gt;，直到锁被释放。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var mu sync.Mutex
var counter int

func increment() {
    mu.Lock()         // 加锁
    defer mu.Unlock() // 函数返回时解锁
    counter++
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;除了 &lt;code&gt;sync.Mutex&lt;/code&gt; 还有一种另一种锁 &lt;code&gt;sync.RWmutex&lt;/code&gt; 也就是读写锁，因为在只有并发读，没有并发写的时候，再加锁并没有什么用，因为并发读始终是安全的，因此读写锁就是针对于互斥锁的一个优化，在读多写少的场景下我们可以选择读写锁来替代互斥锁。&lt;/p&gt;
&lt;h3&gt;3.sync.Once&lt;/h3&gt;
&lt;p&gt;程序运行时，懒加载初始化常用（其实平时也不咋用这个），保证了整个生命周期，一个 sync.Once 对象仅会执行一次 Do 方法，多余的都会跳过。&lt;/p&gt;
&lt;p&gt;比如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
)

func main() {
    init := sync.Once{}
    num := 0
    for range 10 {
        init.Do(func() {
            num ++
        })
    }
    fmt.Println(num)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果为 1，无需多言。&lt;/p&gt;
&lt;h3&gt;4.sync.Map&lt;/h3&gt;
&lt;p&gt;众所不周知，我们 go 中原生的 &lt;code&gt;map&lt;/code&gt; 并不是并发安全的，在并发读写的情况下会 panic，导致程序崩溃，于是 sync 标准库推出了 &lt;code&gt;sync.Map&lt;/code&gt; ，这是一个并发安全的 &lt;code&gt;map&lt;/code&gt;，严格意义来说，我们直接在原生 &lt;code&gt;map&lt;/code&gt; 的基础上加互斥锁或者读写锁也能够解决问题，但是 &lt;code&gt;sync.Map&lt;/code&gt; 是做了一定基础的优化的，go 1.24 之前的版本和之后的版本有不同的实现方式，感兴趣可以去了解一下。总之，有了它，我们就不需要为 &lt;code&gt;map&lt;/code&gt; 维护一个互斥锁了。&lt;/p&gt;
&lt;h3&gt;5. sync.Cond&lt;/h3&gt;
&lt;p&gt;它可以实现一种信号通知的功能&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;sync&quot;
	&quot;time&quot;
)

func main() {
	l := sync.Mutex{}
	c := sync.NewCond(&amp;amp;l)

	go func() {
		// 调用 wait 前需要先加锁
		c.L.Lock()
		c.Wait()
		println(&quot;Hello, world!&quot;)
		// 调用 wait 后需要解锁
		c.L.Unlock()
	}()

	time.Sleep(time.Second)
	println(&quot;唤醒&quot;)
	// Signal 方法唤醒等待的 goroutine
	c.Signal()

	time.Sleep(time.Second)
	println(&quot;end&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;剩下的不常用。&lt;/p&gt;
&lt;p&gt;参考链接：https://draven.co/golang/docs/part3-runtime/ch06-concurrency/golang-sync-primitives/&lt;/p&gt;
&lt;h2&gt;Context 上下文&lt;/h2&gt;
&lt;p&gt;context 可以在函数传播链中用于存储一些 kv 键值对信息用于下游获取，也可以在并发控制中发挥作用，比如我们可以为这个函数调用设计一个超时时间，我们的 context 就可以通过这个超时时间来取消这个函数调用链，除了超时控制，我们还可以手动地去 cancel 这个上下文，取消这次调用，但是需要注意的是，你即便取消了这个 context,已经执行的代码并不能撤回，谨慎设置超时时间。 例子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import (
	&quot;context&quot;
	&quot;fmt&quot;
	&quot;time&quot;
)

func doSomething(ctx context.Context) {
	for {
		select {
		case &amp;lt;-ctx.Done():
			fmt.Println(&quot;doSomething stopped:&quot;, ctx.Err())
			return // 退出 goroutine
		default:
			fmt.Println(&quot;hello&quot;)
			time.Sleep(time.Second)
		}
	}
}

func main() {
	ctx := context.Background()

	ctx, cancel := context.WithTimeout(ctx, 2*time.Second)

	defer cancel()

	doSomething(ctx)

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;详细讲解 https://draven.co/golang/docs/part3-runtime/ch06-concurrency/golang-context/&lt;/p&gt;
</content:encoded></item><item><title>第十周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-17-weekly10/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-17-weekly10/</guid><pubDate>Mon, 17 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这周就是准备和完成了这次概率论的期中考，其次主要是进行第一次的pr，虽然只是简单地修改了格式错误，但是看到自己的头像出现在contributors这一栏中还是很有成就感的😍。现在已经是第十一周了，距离期末考就一个半月的时间了，在这期间继续努力吧。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;完成概率论期中考&lt;/li&gt;
&lt;li&gt;进行了一次开源尝试，提交了一次pr&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;学习并部署redis&lt;/li&gt;
&lt;li&gt;不知道&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>第九周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-10-weekly9/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-10-weekly9/</guid><pubDate>Mon, 10 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这一周，我在爽玩鸭科夫的基础上，算是顺利的完成了上周的学习了bcrypt包的密码加密，并完成了用户的登陆和注册(不过用户登陆使用的jwt内容有点忘记，下周考完试在回顾一下)。虽然有考试的原因，但感觉最近几周有点懈怠了，周报都没什么好写（想当初我左学gin，右学gorm，还有时间学习大物，真是物是人非啊🫠）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;学习bcrypt包的密码加密&lt;/li&gt;
&lt;li&gt;用bcrypt和jwt完成了用户的登陆和注册&lt;/li&gt;
&lt;li&gt;稍微看了一些redis&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;复习概率论✅&lt;/li&gt;
&lt;li&gt;还有时间的话，学习redis并部署&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Bcrypt和盐</title><link>https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-11-05-bcrypt/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-11-05-bcrypt/</guid><pubDate>Wed, 05 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;bcrypt&lt;/strong&gt; 是一种结合了盐值机制的自适应哈希函数。与普通哈希算法的根本区别在于，bcrypt 在设计上内置了盐值的使用，从而显著提升了密码存储的安全性。&lt;/p&gt;
&lt;p&gt;普通哈希算法存在一个关键缺陷：对于相同的输入，始终产生相同的输出。这意味着如果多个用户使用相同密码（例如“123456”），其哈希值也会完全相同，系统因此容易受到彩虹表攻击。&lt;/p&gt;
&lt;p&gt;彩虹表攻击：彩虹表就是一张升级版的储存常见明文密码和哈希值的表。它通过链式结构和规约函数解决了存储空间的问题，平衡了空间和时间。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;盐（Salt）&lt;/strong&gt; 就是为了解决这个问题而生的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：盐是一段随机生成的、足够长的字符串。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工作方式&lt;/strong&gt;：在哈希密码之前，系统会先为每个用户生成一个独一无二的盐，然后把这个盐拼接在用户的密码后面，再对**“密码+盐”** 这个组合进行哈希。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储&lt;/strong&gt;：最终，系统将&lt;strong&gt;哈希结果&lt;/strong&gt;和&lt;strong&gt;盐值本身&lt;/strong&gt;一起存储到数据库中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于每个用户拥有独特的盐值，即使密码相同，最终得到的哈希结果也会完全不同。这意味着攻击者无法使用同一张彩虹表破解所有用户密码，而必须为每个盐值单独建立破解表，这使得攻击成本急剧上升，在实际中几乎不可行。&lt;/p&gt;
&lt;p&gt;此外，bcrypt 被刻意设计为计算缓慢且内存密集，这种“故意低效”的设计大幅增加了暴力破解和彩虹表构建所需的时间和资源开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总结来说，bcrypt = 故意缓慢的哈希算法 + 自动强盐机制 + 可配置的计算成本&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;bcrypt的使用在Golang中则是比较简单，具体可以见&lt;a href=&quot;https://pkg.go.dev/golang.org/x/crypto/bcrypt&quot;&gt;bcrypt文档&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;下面简单说一下：&lt;/p&gt;
&lt;p&gt;1.生成密码哈希&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func GenerateFromPassword(password []byte, cost int) ([]byte, error)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.验证密码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func CompareHashAndPassword(hashedPassword, password []byte) error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.获取哈希成本&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func Cost(hashedPassword []byte) (int, error)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;tips：bcrypt 最多处理 72 字节的密码&lt;/p&gt;
</content:encoded></item><item><title>第八周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-03-weekly8/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-11-03-weekly8/</guid><pubDate>Mon, 03 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这一周就是哼哧哼哧地复习大学物理和离散，考完期中考，并度过了一个很爽的周末，在鸭科夫里大搜特搜，大赚特赚。在瓦里又上了一段。喔吼～不过也确实没什么好说的，这周就是这么简单。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;考完离散&lt;/li&gt;
&lt;li&gt;考完大物&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;看一下之前的代码（有点不记得了）✅&lt;/li&gt;
&lt;li&gt;完成用户的登陆和注册，学习使用bcrypt加密（上周的计划）✅&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>第七周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-27-weekly7/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-27-weekly7/</guid><pubDate>Mon, 27 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这一周我感觉过得挺失败的☹️，虽然顺利完成了数据结构的考试，也在项目上更进一步（虽然依靠了AI的帮助），但是感觉效率不是很高，有点焦虑和倦怠。正如我在之前吐槽到别人真的太强了，我还在吭哧吭哧学习。不过这里就不多焦虑了。下周有大学物理和离散结构的考试，主要是复习，有机会的话理解回顾一下代码（有些ai生成的没理解）和学习一下bcrypt加密。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;成功完成数据结构考试&lt;/li&gt;
&lt;li&gt;Viper来进行配置管理&lt;/li&gt;
&lt;li&gt;实现jwt的鉴权&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;复习大学物理✅&lt;/li&gt;
&lt;li&gt;复习离散结构✅&lt;/li&gt;
&lt;li&gt;完成用户的登陆和注册，学习使用bcrypt加密&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>第六周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-20-weekly6/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-20-weekly6/</guid><pubDate>Mon, 20 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;​	这一周原本是大复特习的节奏，不过由于学校期中考的离谱安排，大学物理与概率论隔了两周时间，所以我就继续边学习边完成项目了。不过，有一说一，我觉得之前缺乏学习热情导致的原因还是陌生导致的，觉得很难，其实tag和原本的没什么不同，加个many2many，修改一下原本对tag的支持就基本完成了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;完成了物理知识的复习（刷题之后再说吧）&lt;/li&gt;
&lt;li&gt;完成了tag系统，并学习了Gorm的相关知识：many2many，关联模式的association()、replace()等&lt;/li&gt;
&lt;li&gt;了解了cookie、session和token的知识概念，并在post记录了下来&lt;/li&gt;
&lt;li&gt;了解了jwt的知识概念，跟着csdn上的一篇博客&lt;a href=&quot;https://blog.csdn.net/hsuhwsb/article/details/149157912&quot;&gt;Gin 框架中如何实现 JWT 鉴权中间件&lt;/a&gt;初步学习了利用 jwt 包实现 web 鉴权&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;数据结构刷点题（要考试了）🫠✅&lt;/li&gt;
&lt;li&gt;学习Viper来进行配置管理✅&lt;/li&gt;
&lt;li&gt;仿着csdn的那篇博客， 来实现 JWT 工具、编写登录/注册接口和编写鉴权中间件&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Cookie Session Token理解笔记</title><link>https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-10-19-cookie/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-10-19-cookie/</guid><pubDate>Sun, 19 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;作为初学者，之前对于cookie、session和token的概念老是搞不清楚，现在搞懂了一些，就赶紧记下这一刻的知识，方便以后的查询。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;历史的演进是：&lt;code&gt;Cookie -&amp;gt; Session (基于Cookie) -&amp;gt; Token (尤其是JWT)&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;1. Cookie&lt;/h2&gt;
&lt;p&gt;Cookie 本身不进行验证，它只是一个存储和传输机制，一个携带信息的工具。在session出现之前，Cookie直接存储用户信息，十分不安全。&lt;/p&gt;
&lt;h2&gt;2. Session&lt;/h2&gt;
&lt;p&gt;session一般结合cookie使用，是存储在服务器，它会在服务器储存相关信息，设置session并返回sessionid，sessionid存储在客户端，每次登陆用cookie带上sessionid，去寻找session验证。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Session 验证&lt;/strong&gt;：类似于“&lt;strong&gt;查账本&lt;/strong&gt;”的方式。服务器收到Session ID后，需要去数据库或内存中&lt;strong&gt;查找&lt;/strong&gt;这个ID对应的Session数据。&lt;/p&gt;
&lt;p&gt;因为需要为每个活跃用户存储一份数据，所以&lt;strong&gt;存储量 = 用户数量 × 每个用户的数据大小&lt;/strong&gt;，所以导致了技术上的限制：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Session数据存储在&lt;strong&gt;单个服务器&lt;/strong&gt;的内存中&lt;/li&gt;
&lt;li&gt;在集群环境中，请求可能被负载均衡到不同服务器&lt;/li&gt;
&lt;li&gt;除非所有服务器共享Session存储（如Redis），否则无法识别用户&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. Token&lt;/h2&gt;
&lt;p&gt;token是存储在客户端的，相关信息存储在token的payload上，服务器只储存一个统一的密匙，用密匙进行验证。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;token验证&lt;/strong&gt;：类似于“&lt;strong&gt;验证人民币&lt;/strong&gt;”的方式。服务器中的密匙，根据token的header和payload验证签名。（header上的算法类似于开锁方法和说明书，密匙相当于那把钥匙，&lt;strong&gt;算法不等于密匙&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;因为只&lt;strong&gt;存储一份统一的密匙&lt;/strong&gt;，所以存储量是个常量，天生符合分布式系统。&lt;/p&gt;
&lt;h2&gt;4. 安全性&lt;/h2&gt;
&lt;p&gt;关于安全方面，不太清楚，就直接贴一下，AI的回答吧。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Session 的安全核心&lt;/strong&gt;是：Session ID 的&lt;strong&gt;保密性&lt;/strong&gt;。一旦泄露，攻击者可以完全冒充用户，直到服务器端主动使其失效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Token 的安全核心&lt;/strong&gt;是：&lt;strong&gt;签名验证&lt;/strong&gt;和&lt;strong&gt;短生命周期&lt;/strong&gt;。它的设计一定程度上接受了“令牌可能会被偷”的现实，但通过技术手段限制其破坏力。&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>第五周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-13-weekly5/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-13-weekly5/</guid><pubDate>Mon, 13 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;​	这一周可以以国庆为界可以分为两部分，第一部分是国企时期的对项目的推进即相关知识的学习。不过不知道是因为项目变复杂了，还是学习时间太久，感觉有点倦怠了🫩，于是，我便开始第二段是对期中考的学习。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;对 Gin 的继续学习，主要学习了路由组、使用中间件、自定义中间件、使用 BasicAuth 中间件的内容、JSON 的模型绑定和验证和自定义响应格式（不过现在有点忘了是什么了🫠）&lt;/li&gt;
&lt;li&gt;对上周 Gorm 的复习，感觉基础的 Gorm 就是在 &lt;code&gt;db.delete()&lt;/code&gt; 这些基础方法再加上 &lt;code&gt;model()&lt;/code&gt;、&lt;code&gt;where()&lt;/code&gt; 等来实现更多的、更准确的功能，也学习了 &lt;code&gt;iserror&lt;/code&gt; 的错误判断&lt;/li&gt;
&lt;li&gt;在 AI 的帮助下，实现了基本的分层项目结构，基本完成了上周的预期目标，理解了相关的内容（但是感觉如果自己独立写有点虚🫠）&lt;/li&gt;
&lt;li&gt;开始期中考的学习，数据结构的知识基本学习完成（不过做题效果不是很好），通过蜂考学习大学物理的电磁学内容（至高斯定理部分），刚选择好概率论的 b 站视频😇&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;继续期中考知识的学习✅&lt;/li&gt;
&lt;li&gt;如果学的快的话，会给项目写一个 tag 系统，为了&lt;strong&gt;从零搭建的实践&lt;/strong&gt;，就像前面说的，感觉自己独立写有点虚🫠。✅&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>第四周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-07-weekly4/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-10-07-weekly4/</guid><pubDate>Tue, 07 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;​	由于上一周经历了国庆假期，星期一又是中秋节 🎑，所以拖着拖着，到了周二才开始写周报。不过，由于国庆假期摆烂的原因，也没什么好写的。但为了每周一份的周报，我还是在中秋节前夕，在 AI 的帮助下完成了一些内容，辅助着国庆前的老本，堪堪写一些内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;学习了 SQL 的语法，在 sql 之母上完成了十几道题目，对 SQL 有了基本的了解&lt;/li&gt;
&lt;li&gt;学习了 Gorm 的概述、模型声明和 CRUD 接口等比较基础和简单的内容（自我感觉查询因为类似于 SQL 语法，更易懂点）&lt;/li&gt;
&lt;li&gt;完成了智能笔记项目的 CRUD 内容，并连接上了 MySQL 数据库&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;项目开发继续&lt;/strong&gt;✅
&lt;ul&gt;
&lt;li&gt;分层项目结构&lt;/li&gt;
&lt;li&gt;统一响应与错误处理&lt;/li&gt;
&lt;li&gt;.env 环境变量管理&lt;/li&gt;
&lt;li&gt;结构化日志&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;根据项目继续学习相关知识&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Go 语言：错误处理、包管理、环境变量...&lt;/li&gt;
&lt;li&gt;Gin：路由分组、中间件...✅&lt;/li&gt;
&lt;li&gt;Gorm：tag、错误处理...✅&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>面向对象编程感悟</title><link>https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-09-30-oop/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-09-30-oop/</guid><pubDate>Tue, 30 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;面向对象，不知从何时起盘旋在我的脑海中，或许是学习Java，亦或是更早。不过，我一直都没特别理解这个东西，更不要说封装、继承等概念了，是我脑海中不断徘徊的乌云。直到现在，我重新审视，通过B站、知乎等网站，我终于有所感悟和理解，于是写下这篇文章。&lt;/p&gt;
&lt;p&gt;这里不着重于结构体和方法的理解和实现，只是单纯谈谈这个思想罢了👌&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;OOP即面向对象编程(Object Oriented Programming)&lt;/strong&gt;，与之相对的是面向过程编程。面向过程和面向对象的区别，用我在知乎上看到的一句话说就是——&lt;strong&gt;面向过程是编年体，面向对象是纪传体&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面向过程&lt;/strong&gt;，关注的是做事，关注的是&quot;步骤&quot;。把要实现的事情，拆分成一个个步骤，依次完成。解决问题时，思考的是&quot;先做什么，再做什么，最后做什么&quot;。在我看来这个视角类似于实施者，由于生活中我们就是以这种思想来生活，所以不可避免的更熟悉和理解面向过程编程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面向对象&lt;/strong&gt;则不一样，它关注的是对象，是找人。解决问题时，思考的是&quot;这个问题中有哪些&lt;strong&gt;参与者&lt;/strong&gt;？这些参与者有哪些&lt;strong&gt;属性&lt;/strong&gt;和&lt;strong&gt;行为&lt;/strong&gt;？它们之间如何&lt;strong&gt;交互&lt;/strong&gt;？&quot;在这里，面向对象先把事务分解到对象身上，描述各个对象的作用，然后才是他们之间的交互。这里的视角类似于管理者。&lt;/p&gt;
&lt;p&gt;基于这一思想，面向对象发展出&lt;strong&gt;封装、继承和多态&lt;/strong&gt;这三大特性。&lt;/p&gt;
&lt;p&gt;关于OOP的三特性形象化理解，假设你有一台洗衣机，要用它洗衣服，你关心它内部是怎么洗的么？你不关心，你只要按一个按钮就好了，这就是&lt;strong&gt;封装&lt;/strong&gt;。不同型号的洗衣机洗衣方式不同，但是都能洗衣，而且你也只关心洗衣机的这个洗衣功能而已，所以你可以将全部洗衣机进行抽象，最终抽象出一个接口洗衣机，它有一个方法洗衣，这就是&lt;strong&gt;多态&lt;/strong&gt;。相同品牌或者系列的洗衣机可能有类似的内部细节，这些细节可以组成一个模板，作为基类或者父类，而具体的某款产品则是子类，这是&lt;strong&gt;继承&lt;/strong&gt;。 使用时，你通过上下文取得洗衣机接口的一个实例，调用其的洗衣方法，你就可以完成洗衣服操作了。至于它是如何洗衣服的你压根不关心。这就是OOP。&lt;/p&gt;
&lt;p&gt;在面向对象编程的概念中，类、对象、方法和属性在Java中体现的尤为明显，在Golang中则有不同的实现方式。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;传统OOP概念&lt;/th&gt;
&lt;th&gt;Go中的实现&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;类(Class)&lt;/td&gt;
&lt;td&gt;结构体(Struct)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;对象(Object)&lt;/td&gt;
&lt;td&gt;结构体实例(Struct Instance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;方法(Method)&lt;/td&gt;
&lt;td&gt;带有接收者的函数(Method)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;属性(Fields)&lt;/td&gt;
&lt;td&gt;结构体字段(Struct Fields)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;1. 封装&lt;/h3&gt;
&lt;p&gt;Go使用结构体和方法实现封装：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

// 定义结构体（类似类）
type Person struct {
    name string // 私有字段（小写开头）
    Age  int    // 公共字段（大写开头）
}

// 结构体方法（接收者）
func (p *Person) GetName() string {
    return p.name
}

func (p *Person) SetName(name string) {
    p.name = name
}

func main() {
    p := Person{}
    p.SetName(&quot;Alice&quot;)
    p.Age = 30
    fmt.Println(p.GetName()) // 输出: Alice
    fmt.Println(p.Age)       // 输出: 30
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 组合（替代继承）&lt;/h3&gt;
&lt;p&gt;Go使用组合而不是继承来实现代码复用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Employee struct {
    Person      // 嵌入Person，获得其所有字段和方法
    Company string
}

func main() {
    e := Employee{}
    e.SetName(&quot;Bob&quot;) // 使用Person的方法
    e.Age = 35
    e.Company = &quot;Google&quot;
    
    fmt.Printf(&quot;%s works at %s&quot;, e.GetName(), e.Company)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 多态（通过接口实现）&lt;/h3&gt;
&lt;p&gt;Go的接口是隐式实现的，类型只需实现接口的所有方法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 定义接口
type Speaker interface {
    Speak() string
}

// 实现接口的类型1
type Dog struct{}

func (d Dog) Speak() string {
    return &quot;Woof!&quot;
}

// 实现接口的类型2
type Cat struct{}

func (c Cat) Speak() string {
    return &quot;Meow!&quot;
}

func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

func main() {
    dog := Dog{}
    cat := Cat{}
    
    MakeSound(dog) // 输出: Woof!
    MakeSound(cat) // 输出: Meow!
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>第三周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-09-29-weekly3/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-09-29-weekly3/</guid><pubDate>Mon, 29 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;已完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Go 语言学习&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;完成了 &lt;code&gt;Tour of Go&lt;/code&gt; 的大部分练习。&lt;/li&gt;
&lt;li&gt;但是也跳过了一些练习，&lt;code&gt;image&lt;/code&gt; 接口等内容目前不急需；&lt;code&gt;二叉查找树&lt;/code&gt; 等概念需要继续沉淀。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Go by Example 推进&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;已学习到 &lt;code&gt;goroutine&lt;/code&gt; 的 &lt;code&gt;rate-limiting&lt;/code&gt; 部分。&lt;/li&gt;
&lt;li&gt;重点学习了&lt;code&gt;闭包&lt;/code&gt;和&lt;code&gt;goroutine&lt;/code&gt;及其&lt;code&gt;timer&lt;/code&gt;、&lt;code&gt;tickers&lt;/code&gt;、&lt;code&gt;waitgroup&lt;/code&gt; 等内容。&lt;/li&gt;
&lt;li&gt;但是也跳过了 &lt;code&gt;范型&lt;/code&gt;、&lt;code&gt;枚举&lt;/code&gt;、&lt;code&gt;迭代器的 range&lt;/code&gt; 等目前不会的内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;项目开发 - 智能笔记&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;开始完成智能笔记项目，准备一边学一边开发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;迈出第一步&lt;/strong&gt;：成功让 API 服务运行起来。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gin 框架学习&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;初步开始Gin的学习，掌握了 &lt;code&gt;HTTP 方法&lt;/code&gt;、&lt;code&gt;路由&lt;/code&gt;、&lt;code&gt;路由参数&lt;/code&gt;、&lt;code&gt;JSON&lt;/code&gt;、&lt;code&gt;Query&lt;/code&gt; 和 &lt;code&gt;Post Form&lt;/code&gt; 的使用。&lt;/li&gt;
&lt;li&gt;计划在后续开发 &lt;code&gt;JWT&lt;/code&gt;、&lt;code&gt;日志&lt;/code&gt; 等功能时进行更深入的学习。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具与环境&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;安装了 &lt;code&gt;Postman&lt;/code&gt;、&lt;code&gt;MySQL&lt;/code&gt; 等开发工具。&lt;/li&gt;
&lt;li&gt;成功申请了 &lt;code&gt;GitHub 教育福利&lt;/code&gt;（费了我好大劲，在使用 VPN 的情况下）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;项目开发继续&lt;/strong&gt;✅
&lt;ul&gt;
&lt;li&gt;学习 &lt;code&gt;SQL&lt;/code&gt; 基础语法。&lt;/li&gt;
&lt;li&gt;初步学习 &lt;code&gt;Gorm&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;实现笔记的完整 &lt;strong&gt;CRUD&lt;/strong&gt; 功能。&lt;/li&gt;
&lt;li&gt;实现数据持久化，接入 &lt;code&gt;MySQL&lt;/code&gt; 数据库。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;学校课业（可能）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可能&lt;/strong&gt;需要回顾学校知识，为 &lt;strong&gt;10 月中下旬&lt;/strong&gt; 的期中考做准备。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>第二周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-09-22-weekly2/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/2025-09-22-weekly2/</guid><pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;解决了上周博客留下来的问题，有了一个简陋但功能完备的网站 🥳。&lt;/li&gt;
&lt;li&gt;在 &lt;a href=&quot;https://tour.go-zh.org/&quot;&gt;Tour of Go&lt;/a&gt; 上基本完成了所有内容的学习，包括切片、接口、并发等知识点。&lt;/li&gt;
&lt;li&gt;持续推进 &lt;a href=&quot;https://gobyexample.com/&quot;&gt;Go by Example&lt;/a&gt; 的学习，目前完成 &lt;code&gt;switch&lt;/code&gt; 部分，进入数组相关内容（不得不说gobyexample确实不赖，对于这些基础知识我也能学到新的特性）。&lt;/li&gt;
&lt;li&gt;做了一些学习笔记。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;巩固已学知识，搞懂 Tour of Go 中的练习题。✅&lt;/li&gt;
&lt;li&gt;继续学习 Go by Example 的后续内容。✅&lt;/li&gt;
&lt;li&gt;（可能）了解一些常用标准库包的基本用法。&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>Golang之接口</title><link>https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-09-19-interface/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/2025-09-19-interface/</guid><pubDate>Sat, 20 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Golang之接口&lt;/h1&gt;
&lt;p&gt;接口是我在tour of go上遇到的第一个难点，因此我打算再开一篇来着重记录，不仅是当下对此的沉淀与思考，也是对未来的提醒与照应。为了方便自己的查看，便独立于之前的知识碎片。&lt;/p&gt;
&lt;h2&gt;接口（interface）&lt;/h2&gt;
&lt;h3&gt;接口的定义&lt;/h3&gt;
&lt;p&gt;接口（Interface）本质上就是&lt;strong&gt;定义了一组方法签名（Method Signatures）的集合&lt;/strong&gt;。它只关心**“做什么”&lt;strong&gt;，而不关心&lt;/strong&gt;“怎么做”**。&lt;/p&gt;
&lt;p&gt;它规定：&lt;strong&gt;“任何类型，只要你实现了我的合同里规定的所有这些方法，那我就认为你实现了这个接口。”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;每个接口类型由任意个方法签名组成，接口的定义格式如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type 接口类型名 interface{
    方法名1( 参数列表1 ) 返回值列表1
    方法名2( 参数列表2 ) 返回值列表2
    …
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;如何实现接口？（“隐式实现”）&lt;/h3&gt;
&lt;p&gt;Go 接口的实现是 &lt;strong&gt;“隐式”&lt;/strong&gt; 的。这意味着你&lt;strong&gt;不需要&lt;/strong&gt;像 Java 那样明确地写 &lt;code&gt;implements Speaker&lt;/code&gt;。只需要让这个类型拥有接口里规定的所有方法，它就自动实现了该接口！&lt;/p&gt;
&lt;p&gt;这是 Go 的哲学——“鸭子类型”（如果它走起来像鸭子，叫起来像鸭子，那它就是鸭子）。&lt;/p&gt;
&lt;h2&gt;接口值&lt;/h2&gt;
&lt;p&gt;接口也是值。它们可以像其它值一样传递。&lt;/p&gt;
&lt;p&gt;接口值可以用作函数的参数或返回值。&lt;/p&gt;
&lt;p&gt;接口值可以看作两部分&lt;strong&gt;具体类型&lt;/strong&gt;和&lt;strong&gt;该类型的值&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可以把接口值想象成一个特殊的“盒子”。&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这个盒子上贴着一个&lt;strong&gt;标签&lt;/strong&gt;，写着里面装的东西的类型（&lt;code&gt;*main.Dog&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;盒子里装着&lt;strong&gt;实际的值&lt;/strong&gt;（一个 &lt;code&gt;Dog&lt;/code&gt; 结构体的实例）。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;var s Speaker      // 接口变量 s，此时它是一个空的“盒子”，里面是 nil
s = Dog{Name: &quot;Rex&quot;} // 赋值后，s 这个“盒子”里：
                     // - 标签：main.Dog
                     // - 值：{Rex}

fmt.Printf(&quot;(%v, %T)\n&quot;, s, s) // 输出：({Rex}, main.Dog)
                               // 值部分 和 类型部分
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当你调用 &lt;code&gt;s.Speak()&lt;/code&gt; 时，Go 会打开这个“盒子”，根据标签找到类型 &lt;code&gt;Dog&lt;/code&gt;，然后执行 &lt;code&gt;Dog&lt;/code&gt; 的 &lt;code&gt;Speak&lt;/code&gt; 方法。&lt;/p&gt;
&lt;h2&gt;底层值为 nil 的接口值&lt;/h2&gt;
&lt;p&gt;即便接口内的具体值为 nil，方法仍然会被 nil 接收者调用。保存了 nil 具体值的接口其自身并不为 nil。&lt;/p&gt;
&lt;h2&gt;nil 接口值&lt;/h2&gt;
&lt;p&gt;nil 接口值既不保存值也不保存具体类型。&lt;/p&gt;
&lt;p&gt;为 nil 接口调用方法会产生运行时错误，因为接口的元组内并未包含能够指明该调用哪个 &lt;strong&gt;具体&lt;/strong&gt; 方法的类型。&lt;/p&gt;
&lt;h2&gt;空接口（interface{}/any）&lt;/h2&gt;
&lt;p&gt;空接口可保存任何类型的值（因为每个类型都至少实现了零个方法）&lt;/p&gt;
&lt;p&gt;空接口被用来处理未知类型的值&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tips&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;空接口&lt;/strong&gt;是一个接口&lt;strong&gt;类型&lt;/strong&gt;。因为它没有规定任何方法，所以Go语言规定&lt;strong&gt;所有类型都自动实现了空接口&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;nil接口值&lt;/strong&gt;指的是一个接口变量的&lt;strong&gt;当前状态是“空”的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;它们之间的关系是正交的：&lt;strong&gt;你可以有一个&lt;/strong&gt;空接口类型的nil接口值&lt;/strong&gt;，也可以有一个&lt;strong&gt;非空的自定义接口类型的nil接口值&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;类型断言&lt;/h2&gt;
&lt;p&gt;由于接口变量可以持有任意实现它的类型的值，有时我们需要知道它背后具体的实际值是什么。&lt;/p&gt;
&lt;p&gt;在 Go 语言中，接口断言是一种检查接口变量是否具有特定具体类型的方法。接口断言的基本语法如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;value, ok := interfaceVariable.(Type)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;interfaceVariable&lt;/code&gt; 是一个接口类型的变量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Type&lt;/code&gt; 是你想要断言的具体类型&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;interfaceVariable&lt;/code&gt; 实际上是一个 &lt;code&gt;Type&lt;/code&gt; 类型的值，那么 &lt;code&gt;value&lt;/code&gt; 将会被赋值为该值，并且 &lt;code&gt;ok&lt;/code&gt; 将会是 &lt;code&gt;true&lt;/code&gt;。如果 &lt;code&gt;interfaceVariable&lt;/code&gt; 不是 &lt;code&gt;Type&lt;/code&gt; 类型，那么 &lt;code&gt;value&lt;/code&gt; 将会是 &lt;code&gt;Type&lt;/code&gt; 类型的零值，而 &lt;code&gt;ok&lt;/code&gt; 将会是 &lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;对于空接口 &lt;code&gt;interface{}&lt;/code&gt;，任何类型的值都可以被赋值给它，因此对接口断言的需求更加常见&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;类型选择&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;类型选择&lt;/strong&gt; 是一种按顺序从几个类型断言中选择分支的结构。&lt;/p&gt;
&lt;p&gt;类型选择与一般的 switch 语句相似，不过类型选择中的 case 为类型（而非值）， 它们针对给定接口值所存储的值的类型进行比较。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;switch v := i.(type) {
case T:
    // v 的类型为 T
case S:
    // v 的类型为 S
default:
    // 没有匹配，v 与 i 的类型相同
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;类型选择中的声明与类型断言 &lt;code&gt;i.(T)&lt;/code&gt; 的语法相同，只是具体类型 &lt;code&gt;T&lt;/code&gt; 被替换成了关键字 &lt;code&gt;type&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;多态实现&lt;/h3&gt;
&lt;p&gt;接口变量可以持有任意实现它的类型的值&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;多态（Polymorphism）&lt;/strong&gt; 指的是一个接口的调用方式，可以在运行时根据其底层实际类型的不同而表现出不同的行为&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思想：&lt;/strong&gt; 不同结构体只要实现了相同的接口，它们就可以被当作同一种类型（接口类型）来处理，但在执行接口方法时，会执行各自具体的实现。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;经典例子：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package main

import &quot;fmt&quot;

// 定义一个支付接口
type Payment interface {
    Pay(amount float64) string
}

// 实现两种不同的支付方式
type Alipay struct {
    Account string
}

func (a Alipay) Pay(amount float64) string {
    return fmt.Sprintf(&quot;使用支付宝 %s 支付了 %.2f 元&quot;, a.Account, amount)
}

type WechatPay struct {
    OpenID string
}

func (w WechatPay) Pay(amount float64) string {
    return fmt.Sprintf(&quot;使用微信 %s 支付了 %.2f 元&quot;, w.OpenID, amount)
}

// 一个通用的支付函数，它只关心传入的对象是否实现了 Payment 接口
func ProcessPayment(p Payment, amount float64) {
    result := p.Pay(amount)
    fmt.Println(result)
}

func main() {
    a := Alipay{Account: &quot;zhangsan@alipay.com&quot;}
    w := WechatPay{OpenID: &quot;wx_abcdef123456&quot;}

    // 多态的体现：ProcessPayment 函数不需要知道具体是哪种支付方式
    // 它只需要调用 Pay 方法，而具体执行哪个版本的 Pay，由运行时 p 的实际类型决定
    ProcessPayment(a, 100.5)
    ProcessPayment(w, 200.0)

    // 也可以将不同的实现放入同一个切片（接口类型切片）
    payments := []Payment{a, w}
    for _, payer := range payments {
        ProcessPayment(payer, 50.0)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;输出：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;使用支付宝 zhangsan@alipay.com 支付了 100.50 元
使用微信 wx_abcdef123456 支付了 200.00 元
使用支付宝 zhangsan@alipay.com 支付了 50.00 元
使用微信 wx_abcdef123456 支付了 50.00 元
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Go的&quot;继承&quot;&lt;/h3&gt;
&lt;p&gt;Go 语言设计者认为传统的类继承（尤其是多重继承）模型复杂且容易出错。因此，Go 彻底摒弃了 &lt;code&gt;class&lt;/code&gt; 和 &lt;code&gt;extends&lt;/code&gt; 的概念。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Go 的“继承”是通过结构体的嵌套（Embedding）来实现的，这本质上是“组合”。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// “父类”（基类）
type Animal struct {
    name string
}

func (a *Animal) Speak() {
    fmt.Println(&quot;我是:&quot;, a.name)
}

// “子类”（派生类），通过嵌入 Animal 来“继承”它的字段和方法
type Dog struct {
    Animal        // 嵌入 Animal，实现了组合
    Breed  string // 子类自己的字段
}

// 子类可以重写父类的方法
func (d *Dog) Speak() {
    d.Animal.Speak() // 可以调用“父类”的方法
    fmt.Println(&quot;汪汪汪！&quot;)
}

func main() {
    d := Dog{
        Animal: Animal{name: &quot;旺财&quot;}, // 初始化嵌入的结构体
        Breed:  &quot;柯基&quot;,
    }
    d.Speak()       // 调用子类重写后的方法
    d.Animal.Speak() // 仍然可以显式调用父类的方法
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;这种组合的优势：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;清晰简单&lt;/strong&gt;：没有复杂的继承链。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解耦&lt;/strong&gt;：&lt;code&gt;Dog&lt;/code&gt; 和 &lt;code&gt;Animal&lt;/code&gt; 是两个独立的类型，&lt;code&gt;Dog&lt;/code&gt; 只是使用了 &lt;code&gt;Animal&lt;/code&gt; 的功能。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;灵活性&lt;/strong&gt;：&lt;code&gt;Dog&lt;/code&gt; 可以轻松组合多个其他结构体（例如 &lt;code&gt;Pet&lt;/code&gt;）的功能，模拟了“多重继承”，但又没有多重继承的歧义问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;常见的接口&lt;/h2&gt;
&lt;h3&gt;1.Stringer&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://go-zh.org/pkg/fmt/&quot;&gt;&lt;code&gt;fmt&lt;/code&gt;&lt;/a&gt; 包中定义的 &lt;a href=&quot;https://go-zh.org/pkg/fmt/#Stringer&quot;&gt;&lt;code&gt;Stringer&lt;/code&gt;&lt;/a&gt; 是最普遍的接口之一。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Stringer interface {
    String() string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Stringer&lt;/code&gt; 是一个可以用字符串描述自己的类型。&lt;code&gt;fmt&lt;/code&gt; 包（还有很多包）都通过此接口来打印值。&lt;/p&gt;
&lt;h3&gt;2.error&lt;/h3&gt;
&lt;p&gt;Go 程序使用 &lt;code&gt;error&lt;/code&gt; 值来表示错误状态。&lt;/p&gt;
&lt;p&gt;与 &lt;code&gt;fmt.Stringer&lt;/code&gt; 类似，&lt;code&gt;error&lt;/code&gt; 类型是一个内建接口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type error interface {
    Error() string
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;（与 &lt;code&gt;fmt.Stringer&lt;/code&gt; 类似，&lt;code&gt;fmt&lt;/code&gt; 包也会根据对 &lt;code&gt;error&lt;/code&gt; 的实现来打印值。）&lt;/p&gt;
&lt;p&gt;通常函数会返回一个 &lt;code&gt;error&lt;/code&gt; 值，调用它的代码应当判断这个错误是否等于 &lt;code&gt;nil&lt;/code&gt; 来进行错误处理。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;i, err := strconv.Atoi(&quot;42&quot;)
if err != nil {
    fmt.Printf(&quot;couldn&apos;t convert number: %v\n&quot;, err)
    return
}
fmt.Println(&quot;Converted integer:&quot;, i)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;error&lt;/code&gt; 为 nil 时表示成功；非 nil 的 &lt;code&gt;error&lt;/code&gt; 表示失败。&lt;/p&gt;
&lt;h3&gt;3.Readers&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;io&lt;/code&gt; 包指定了 &lt;code&gt;io.Reader&lt;/code&gt; 接口，它表示数据流的读取端。&lt;/p&gt;
&lt;p&gt;Go 标准库包含了该接口的&lt;a href=&quot;https://cs.opensource.google/search?q=Read(%5Cw%2B%5Cs%5B%5Dbyte)&amp;amp;ss=go%2Fgo&quot;&gt;许多实现&lt;/a&gt;，包括文件、网络连接、压缩和加密等等。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;io.Reader&lt;/code&gt; 接口有一个 &lt;code&gt;Read&lt;/code&gt; 方法：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;func (T) Read(b []byte) (n int, err error)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Read&lt;/code&gt; 用数据填充给定的字节切片并返回填充的字节数和错误值。在遇到数据流的结尾时，它会返回一个 &lt;code&gt;io.EOF&lt;/code&gt; 错误。&lt;/p&gt;
&lt;h3&gt;4.Image&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://go-zh.org/pkg/image/#Image&quot;&gt;&lt;code&gt;image&lt;/code&gt;&lt;/a&gt; 包定义了 &lt;code&gt;Image&lt;/code&gt; 接口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package image

type Image interface {
    ColorModel() color.Model
    Bounds() Rectangle
    At(x, y int) color.Color
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意:&lt;/strong&gt; &lt;code&gt;Bounds&lt;/code&gt; 方法的返回值 &lt;code&gt;Rectangle&lt;/code&gt; 实际上是一个 &lt;a href=&quot;https://go-zh.org/pkg/image/#Rectangle&quot;&gt;&lt;code&gt;image.Rectangle&lt;/code&gt;&lt;/a&gt;，它在 &lt;code&gt;image&lt;/code&gt; 包中声明。&lt;/p&gt;
</content:encoded></item><item><title>Golang的知识碎片（基础篇）</title><link>https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/first-post/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E6%8A%80%E6%9C%AF/first-post/</guid><pubDate>Sun, 14 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Golang的知识碎片&lt;/h1&gt;
&lt;p&gt;在此之前golang单纯看蓝山的文档，感觉学的很浅很零碎，所以打算重新看一遍。因为go by example、tour go和蓝山工作室的文档比较完善，所以下方将着重提及一些之前不太清楚的零碎知识，提醒自己。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;0.Go 语言的零值机制&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 Go 语言中，所有变量在声明时都会被自动初始化为其类型的&lt;strong&gt;零值&lt;/strong&gt;（zero value）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数值类型：&lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;布尔类型：&lt;code&gt;false&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;字符串类型：&lt;code&gt;&quot;&quot;&lt;/code&gt;（空字符串）&lt;/li&gt;
&lt;li&gt;指针、接口、切片、映射、通道：&lt;code&gt;nil&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;结构体：每个字段都初始化为其类型的零值&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;1.变量声明&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;关于变量的声明包括两部分，类型和初始值，变量会从初始值中推断出类型或从类型中推断出初始值（即零值）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.返回值&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Go 的返回值可以被命名（向前面的参数一样），return后面没有参数，就会返回没有命名的返回值&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.条件语句前简短语句&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;for和&lt;code&gt;if&lt;/code&gt; 语句可以在条件表达式前执行一个简短语句&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4.无条件的switch(类似于if-else)&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;switch {
case x &amp;lt; 0:
    fmt.Println(&quot;Negative&quot;)
case x == 0:
    fmt.Println(&quot;Zero&quot;)
default:
    fmt.Println(&quot;Positive&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;5.defer推迟/defer栈&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;defer&lt;/code&gt; 语句会将函数调用推迟到外层函数返回之后执行&lt;/li&gt;
&lt;li&gt;被推迟的函数调用会被压入一个&lt;strong&gt;栈&lt;/strong&gt;中，当外层函数返回时，被推迟的函数会按照&lt;strong&gt;后进先出&lt;/strong&gt;（LIFO）的顺序执行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;6.函数闭包&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;闭包 = 函数 + 外部变量变量&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;状态保持&lt;/strong&gt;：闭包可以记住并修改外部变量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;独立实例&lt;/strong&gt;：每次调用外部函数都会创建新的闭包实例&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实用性强&lt;/strong&gt;：用于需要保持状态的场景&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如何判断外部变量&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&quot;这个变量是在内层函数内部定义的，还是外部定义的？&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;再问&lt;/strong&gt;：&quot;内层函数是否使用了这个外部变量？&quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如果两个答案都是&quot;是&quot;&lt;/strong&gt;：那么这个变量就是被捕获的外部变量&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;7.方法&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;方法可以看作有接收者的函数，不过带指针/值参数的函数必须接受一个指针/值，不然会报错，而以指针/值为接收者的方法被调用时，接收者既能为值又能为指针，不过能不能生效另说&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;8.接收者类型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接收者有两种类型，&lt;strong&gt;值接收者&lt;/strong&gt;和&lt;strong&gt;指针接收者&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用指针接收者的两个原因：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.方法需要修改接收者的值，值接收者只能改变副本，指针可以改变原始值&lt;/p&gt;
&lt;p&gt;2.提高效率，每次方法调用时，Go 需要将整个结构体的数据&lt;strong&gt;复制&lt;/strong&gt;一份给方法使用。如果结构体非常大，这个复制操作的开销会很大。而Go 只需要复制一个&lt;strong&gt;指针&lt;/strong&gt;（通常是一个机器字长的大小，如 8 字节），开销极小。&lt;/p&gt;
&lt;p&gt;所以，大部分的时候使用指针&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tips&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对于一个特定的类型，你应该决定是使用值接收者还是指针接收者，并&lt;strong&gt;为该类型的所有方法保持一致&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;9.值类型/引用类型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是 Go 语言中一个非常重要的概念，决定了变量如何被分配内存、如何被赋值以及如何被传递给函数。&lt;/p&gt;
&lt;h4&gt;值类型 (Value Types)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;包括：&lt;/strong&gt; 所有基本数据类型（如 &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;float64&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;）、&lt;strong&gt;数组（Array）&lt;/strong&gt;、结构体（&lt;code&gt;struct&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;行为特点：&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;变量直接存储值本身。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;赋值操作和函数传参时，会创建值的完整副本。&lt;/strong&gt; 修改副本不会影响原始值。&lt;/li&gt;
&lt;li&gt;在内存中，通常被分配在&lt;strong&gt;栈（Stack）&lt;/strong&gt; 上（但编译器也可能决定分配在堆上）。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 值类型示例：数组
arr1 := [3]int{1, 2, 3}
arr2 := arr1 // 将 arr1 的【所有值】完整地复制一份给 arr2

arr2[0] = 100 // 修改副本

fmt.Println(arr1) // 输出: [1 2 3] (原值未改变)
fmt.Println(arr2) // 输出: [100 2 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;引用类型 (Reference Types)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;包括：&lt;/strong&gt; &lt;strong&gt;切片（Slice）、映射（Map）、通道（Channel）、指针（Pointer）、函数（Function）。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;行为特点：&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;变量存储的是一个“引用”（可以理解为内存地址），这个引用指向底层真正存储数据的内存空间。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;赋值操作和函数传参时，复制的是这个“引用”（内存地址），而不是底层数据本身。&lt;/strong&gt; 多个变量可以共享同一份底层数据。通过任何一个变量修改底层数据，其他所有引用它的变量都会“看到”这个变化。&lt;/li&gt;
&lt;li&gt;底层数据通常存储在&lt;strong&gt;堆（Heap）&lt;/strong&gt; 上。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;// 引用类型示例：切片
slice1 := []int{1, 2, 3}
slice2 := slice1 // 复制的是引用（地址），现在 slice1 和 slice2 指向同一个底层数组

slice2[0] = 100 // 通过 slice2 修改底层数组

fmt.Println(slice1) // 输出: [100 2 3] (原值被改变了！)
fmt.Println(slice2) // 输出: [100 2 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;总结对比表&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;值类型&lt;/th&gt;
&lt;th&gt;引用类型&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;代表类型&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;array&lt;/code&gt;, &lt;code&gt;struct&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;slice&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;channel&lt;/code&gt;, &lt;code&gt;pointer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;变量存储内容&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;实际的数据值&lt;/td&gt;
&lt;td&gt;指向底层数据的地址（引用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;赋值/传参行为&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;复制整个数据值，创建独立副本&lt;/td&gt;
&lt;td&gt;复制引用地址，共享底层数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;修改副本的影响&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;不影响原始数据&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;影响&lt;/strong&gt;原始数据&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;内存主要位置&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;栈&lt;/td&gt;
&lt;td&gt;堆（数据本身），变量本身可能在栈&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;10.匿名函数/结构体...&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;暂时不太懂，标记一下&lt;/p&gt;
</content:encoded></item><item><title>第一周总结</title><link>https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/weekly-1/</link><guid isPermaLink="true">https://sheep44044.github.io/posts/%E5%91%A8%E6%8A%A5/25%E7%A7%8B/weekly-1/</guid><pubDate>Sat, 13 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本周主要完成了以下三件事情：&lt;/p&gt;
&lt;h2&gt;完成事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;熟悉 Mac 并配置软件环境&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开始熟悉 macOS 操作系统。&lt;/li&gt;
&lt;li&gt;使用 Jetbrans Toolbox 安装 Goland 等开发工具。&lt;/li&gt;
&lt;li&gt;通过 Homebrew 包管理器安装并管理 Git、Typora 等软件。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;学习并使用 Git&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过教程网站 &lt;a href=&quot;https://learngitbranching.js.org/?demo=&amp;amp;locale=zh_CN&quot;&gt;learngitbranching.js.org&lt;/a&gt; 的git小游戏来学习和练习 Git 操作。&lt;/li&gt;
&lt;li&gt;成功配置 Git 并与我的 GitHub 账户进行关联。&lt;/li&gt;
&lt;li&gt;实现了在 Goland IDE 中集成并使用 Git。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;利用 Hugo 搭建博客&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;Hugo&lt;/code&gt; 静态网站生成器初步搭建了个人博客。&lt;/li&gt;
&lt;li&gt;实现了基本功能：主页文章展示、包含“文章”和“周报”等菜单的导航栏。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;下周计划&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;解决博客的一个小问题：博客在互联网上登入时会错误跳转到本地。✅&lt;/li&gt;
&lt;li&gt;复习 Golang 的知识。✅&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item></channel></rss>