<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>张副官</title>
  
  
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://www.zhangfuguan.top/"/>
  <updated>2023-12-15T16:49:55.414Z</updated>
  <id>http://www.zhangfuguan.top/</id>
  
  <author>
    <name>张副官</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>秋游皖南川藏线</title>
    <link href="http://www.zhangfuguan.top/2023/12/16/qiuyouchuanzangxian/"/>
    <id>http://www.zhangfuguan.top/2023/12/16/qiuyouchuanzangxian/</id>
    <published>2023-12-15T16:41:27.000Z</published>
    <updated>2023-12-15T16:49:55.414Z</updated>
    
    <content type="html"><![CDATA[<p>自古逢秋悲寂寥</p><p><img src="/2023/12/16/qiuyouchuanzangxian/1.jpeg" alt="图片"></p><p>今年因为工作的原因，我和影姐俩一直没出过上海，可是出游的计划每周都会提起，求而不得的东西尤其显得珍贵。这周四又再次提起出去玩玩，想来在新公司已经996一个月了，调休用不完，所以就下周一请假，加上这周末俩天，三天的时间也能去周边溜达一下。开始想去的是黄山，赶上淡季不会太堵，攻略和酒店都看好之后，我突发奇想去瞅了一下天气，发现黄山周六60%会下中雨，所以临时改了方案，可是直到睡觉前都没看好，不过咱们俩决定了这周一定要出去，明天八点起床再说。第二天起床之后，我去之前加的周边游的群里问了一下，群主推荐了他之前在皖南川藏线的游记，整条线路都是自然风光，很契合我们俩的口味，二话没说立刻开整，洗漱了一下并且点了早餐外卖，9点30从浦东出发，第一站目的地：皖南川藏线东入口。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/2.png" alt="图片"></p><p>我们是从浦东金杨出发、上沪渝高速从广德收费站下车，到达广德收费站已经是下午1点多，于是下高速后一路在沿线觅食，在一个镇子上面的小面馆吃了一碗三鲜面和番茄鸡蛋面，味道真的很不错，感觉汤底是自己熬出来的，而且价格实惠。吃完之后看到旁边有旁边小卖部想着买点零食去路上吃，于是发现了我非常喜欢吃的炒年糕片（不知道当地是不是这样叫的），开始以为是猫耳朵，后来下午吃的时候才发现脆脆的、米香十足、微微甜，和猫耳朵的味道截然不同，后面一路上一直没找到有，回来在网上买回来的也差强人意。 吃完午餐之后一路西行，其实此时已经感受这边独特的景色，满山遍野都是竹子，真的是竹林竹海，加上今年秋冬来的迟滞，气温还维持在26度上下，一些树叶也是深绿，所以给的感觉还停留在夏天。中途还会穿越宁国市，可以加一些补给，看到了影姐喜欢点的奶茶店，问她喝不喝，她眯着眼睛让我别吵她睡觉，后来提起此事，说我故意的不提醒她，不让她喝奶茶。大约下午两点半我们就到达“皖南川藏线”的东入口。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/3.png" alt="图片"></p><p>打卡流程走完之后就真正开始了这次主线，我们的第一个目的地是水墨汀溪，第一天的酒店就预定在那。大约行驶40分钟就到酒店了，我们这次预定的是一家农家乐，感觉一般，整个房间虽然有个阳台，但是通风不行。办理好酒店入住之后我们俩就打算去周边逛逛。这边主要的一个景点是早上7点去水墨汀溪那边坐竹排，悠悠行驶在水雾弥漫之中。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/4.png" alt="图片"></p><p>晚上在酒店的臭鳜鱼，我们俩口味重，提前说了要了中辣，还能接受。第二天吃完早餐便离开了酒店，前往青龙湾左东风桥码头坐船，酒店到码头不到20分钟行驶旅程，我们到的时候已经零散有几个人上船，9点开始出发。青龙湾比较大，水很清澈，加之今年是暖秋，树叶都没有变黄，让人感觉身处盛夏。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/5.png" alt="图片"></p><p>邮轮会达到青龙寺脚下，有1个小时的时间前往青龙寺游玩，其实就是一个200来步的石阶，寺庙不大，现在也是淡季，所以人流不多。我们俩很快就游玩了，便开始了下一个目的地：落羽红杉林。其实这个时间在往年看来恰是红杉林树叶正红之时，不过今年入冬较晚，气温居高不下，所以我们来的时候叶子大概只红了三分之一。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/6.png" alt="图片"></p><p>游玩打开半小时之后，就准备觅食了，在沿途还看到了一片金色的稻田。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/7.png" alt="图片"></p><p>吃了当地的咸菜炖猪脚，味道还行，价格也能接受。吃香喝足直奔今天最后一个景点：桃林六道湾。桃林六道湾主要游玩点在于沿途的风景和较为有挑战的路线。沿路此起彼伏、蜿蜒曲折的柏油路，路两侧由之前的竹林逐渐过渡到丛灌树木，路面干净整洁，两侧的民房也是错落有致。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/8.png" alt="图片"></p><p>其实走完桃林六道湾我们的旅途差不多就接近尾声，我问老婆要不要直接回上海，她说太累了没必要，虽然现在才4点半，毕竟也要开将近5个小时的车程。我们便去水墨汀溪附近找了一家民宿休息，前往民宿路程中秋风肃起，漫天的落叶在空中肆意的摇曳，天空已经愈发暗沉，街上行人和车辆也不见一二，此时顿感秋意正浓。第二天9点多在民宿吃了点面条，直奔上海。</p><p><img src="/2023/12/16/qiuyouchuanzangxian/9.png" alt="图片"></p><hr><p><strong>《题西溪无相院》</strong></p><p>宋代 &#x2F; 张先</p><p>积水涵虚上下清，几家门静岸痕平。</p><p>浮萍破处见山影，小艇归时闻棹声。</p><p>入郭僧寻尘里去，过桥人似鉴中行。</p><p>已凭暂雨添秋色，莫放修芦碍月生。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;自古逢秋悲寂寥&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/2023/12/16/qiuyouchuanzangxian/1.jpeg&quot; alt=&quot;图片&quot;&gt;&lt;/p&gt;
&lt;p&gt;今年因为工作的原因，我和影姐俩一直没出过上海，可是出游的计划每周都会提起，求而不得的东西尤其显得珍贵。这周四又
      
    
    </summary>
    
      <category term="意味" scheme="http://www.zhangfuguan.top/categories/%E6%84%8F%E5%91%B3/"/>
    
    
      <category term="意味" scheme="http://www.zhangfuguan.top/tags/%E6%84%8F%E5%91%B3/"/>
    
  </entry>
  
  <entry>
    <title>斋见</title>
    <link href="http://www.zhangfuguan.top/2023/09/11/zhai-md/"/>
    <id>http://www.zhangfuguan.top/2023/09/11/zhai-md/</id>
    <published>2023-09-11T15:51:36.000Z</published>
    <updated>2023-09-11T16:05:22.555Z</updated>
    
    <content type="html"><![CDATA[<p>昔人已乘黄鹤去，此地空余黄鹤楼。<br>黄鹤一去不复返，白云千载空悠悠。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;昔人已乘黄鹤去，此地空余黄鹤楼。&lt;br&gt;黄鹤一去不复返，白云千载空悠悠。&lt;/p&gt;

      
    
    </summary>
    
      <category term="斋见" scheme="http://www.zhangfuguan.top/categories/%E6%96%8B%E8%A7%81/"/>
    
    
  </entry>
  
  <entry>
    <title>二叉树层次遍历</title>
    <link href="http://www.zhangfuguan.top/2023/06/30/%E4%BA%8C%E5%8F%89%E6%A0%91%E5%B1%82%E6%AC%A1%E9%81%8D%E5%8E%86/"/>
    <id>http://www.zhangfuguan.top/2023/06/30/二叉树层次遍历/</id>
    <published>2023-06-29T17:00:25.000Z</published>
    <updated>2023-06-29T17:05:57.978Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://leetcode.cn/problems/binary-tree-level-order-traversal/submissions/">leetcode-二叉树层序遍历</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * type TreeNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Left *TreeNode</span></span><br><span class="line"><span class="comment"> *     Right *TreeNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">levelOrder</span><span class="params">(root *TreeNode)</span></span> [][]<span class="type">int</span> &#123;</span><br><span class="line">    <span class="comment">// write code here</span></span><br><span class="line">    <span class="keyword">if</span> root == <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    res := <span class="built_in">make</span>([][]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line">    <span class="comment">// 使用slice来保存队列</span></span><br><span class="line">    list := <span class="built_in">make</span>([]*TreeNode, <span class="number">0</span>)</span><br><span class="line">    <span class="comment">// 从root节点开始</span></span><br><span class="line">    list = <span class="built_in">append</span>(list, root)</span><br><span class="line">    listLen := <span class="built_in">len</span>(list)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> <span class="built_in">len</span>(list) &gt; <span class="number">0</span> &#123;</span><br><span class="line">        <span class="comment">// 下一层的数量</span></span><br><span class="line">        nextLevelLen := <span class="number">0</span></span><br><span class="line">        <span class="comment">// 本轮的结果</span></span><br><span class="line">        path := <span class="built_in">make</span>([]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 每一层遍历</span></span><br><span class="line">        <span class="keyword">for</span> listLen &gt; <span class="number">0</span> &#123;</span><br><span class="line">            <span class="comment">// 弹出一个节点</span></span><br><span class="line">            node := list[<span class="number">0</span>]</span><br><span class="line">            listLen--</span><br><span class="line">            path = <span class="built_in">append</span>(path, node.Val)</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 如果list只有一个元素，则重新初始化一下</span></span><br><span class="line">            <span class="keyword">if</span> <span class="built_in">len</span>(list) == <span class="number">0</span> &#123;</span><br><span class="line">                list = <span class="built_in">make</span>([]*TreeNode, <span class="number">0</span>)</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                list = list[<span class="number">1</span>:]</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> node.Left != <span class="literal">nil</span> &#123;</span><br><span class="line">                list = <span class="built_in">append</span>(list, node.Left)</span><br><span class="line">                nextLevelLen++</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> node.Right != <span class="literal">nil</span> &#123;</span><br><span class="line">                list = <span class="built_in">append</span>(list, node.Right)</span><br><span class="line">                nextLevelLen++</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 遍历完成</span></span><br><span class="line">        res = <span class="built_in">append</span>(res, path)</span><br><span class="line">        listLen = nextLevelLen</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/binary-tree-level-order-traversal/submissions/&quot;&gt;leetcode-二叉树层序遍历&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight g
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="二叉树" scheme="http://www.zhangfuguan.top/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
    
  </entry>
  
  <entry>
    <title>lru简易理解版本</title>
    <link href="http://www.zhangfuguan.top/2023/06/29/lru%E7%AE%80%E6%98%93%E7%90%86%E8%A7%A3%E7%89%88%E6%9C%AC/"/>
    <id>http://www.zhangfuguan.top/2023/06/29/lru简易理解版本/</id>
    <published>2023-06-28T16:03:22.000Z</published>
    <updated>2023-12-18T16:09:22.842Z</updated>
    
    <content type="html"><![CDATA[<h3 id="分析需求"><a href="#分析需求" class="headerlink" title="分析需求"></a>分析需求</h3><h4 id="Get"><a href="#Get" class="headerlink" title="Get"></a>Get</h4><ol><li>如果节点存在：</li></ol><ul><li>将节点从当前位置删除</li><li>将节点移动到第一个位置</li></ul><ol start="2"><li>如果节点不存在: 直接返回-1</li></ol><h4 id="Put"><a href="#Put" class="headerlink" title="Put"></a>Put</h4><ol><li>如果节点存在：</li></ol><ul><li>更新value</li><li>将节点从当前位置删除</li><li>将节点移动到第一个位置</li></ul><ol start="2"><li>如果节点不存在：size &lt; cap</li></ol><ul><li>将节点直接移动到第一个位置</li><li>节点放入map</li><li>size+1</li></ul><ol start="3"><li>如果节点不存在：size &gt;&#x3D; cap (其实不存在&gt;情况，这里方便理解)</li></ol><ul><li>将节点直接移动到第一个位置</li><li>将末尾节点删除</li><li>将末尾节点从map删除</li></ul><h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>归纳下来主要有俩个操作：</p><ul><li>将节点直接移动到第一个位置</li><li>将节点从当前位置删除</li><li>备注：为了便于操作， 我们将tail和head设置为虚拟节点，这样就不需要考虑边界情况，操作起来非常nice</li></ul><h3 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 节点</span></span><br><span class="line"><span class="keyword">type</span> Node <span class="keyword">struct</span> &#123;</span><br><span class="line">    Key <span class="type">int</span></span><br><span class="line">    Value <span class="type">int</span></span><br><span class="line">    Next *Node</span><br><span class="line">    Pre *Node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> LRUCache <span class="keyword">struct</span> &#123;</span><br><span class="line">    Cap <span class="type">int</span></span><br><span class="line">    Size <span class="type">int</span></span><br><span class="line">    NodeMap <span class="keyword">map</span>[<span class="type">int</span>]*Node</span><br><span class="line">    <span class="comment">// 头部指针</span></span><br><span class="line">    Head *Node</span><br><span class="line">    <span class="comment">// 末尾指针</span></span><br><span class="line">    Tail *Node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Constructor</span><span class="params">(capacity <span class="type">int</span>)</span></span> LRUCache &#123;</span><br><span class="line">    lru := LRUCache&#123;</span><br><span class="line">        Cap: capacity,</span><br><span class="line">        Size: <span class="number">0</span>,</span><br><span class="line">    &#125;</span><br><span class="line">    lru.NodeMap = <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">int</span>]*Node, <span class="number">0</span>)</span><br><span class="line">    lru.Tail = &amp;Node&#123;&#125;</span><br><span class="line">    lru.Head = &amp;Node&#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> lru</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将节点移动放置到头部节点</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *LRUCache)</span></span> moveToHead(node *Node) &#123;</span><br><span class="line">    <span class="keyword">if</span> this.Size == <span class="number">0</span> &#123;</span><br><span class="line">        this.Head.Next = node</span><br><span class="line">        node.Pre = this.Head</span><br><span class="line">        this.Tail.Pre = node</span><br><span class="line">        node.Next = this.Tail</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 节点的Next是之前头部节点的next</span></span><br><span class="line">    node.Next = this.Head.Next</span><br><span class="line">    <span class="comment">// 之前的第一个节点的pre节点是当前节点</span></span><br><span class="line">    this.Head.Next.Pre = node</span><br><span class="line">    <span class="comment">// 节点的pre节点是头部指针</span></span><br><span class="line">    node.Pre = this.Head</span><br><span class="line">    <span class="comment">// 头部指针next指向node</span></span><br><span class="line">    this.Head.Next = node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 删除节点</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *LRUCache)</span></span> delNode(node *Node) &#123;</span><br><span class="line">    node.Pre.Next = node.Next</span><br><span class="line">    node.Next.Pre = node.Pre</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *LRUCache)</span></span> Get(key <span class="type">int</span>) <span class="type">int</span> &#123;</span><br><span class="line">    node, ok := this.NodeMap[key]</span><br><span class="line">    <span class="keyword">if</span> !ok &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 1. 将节点从当前位置删除</span></span><br><span class="line">    this.delNode(node)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 2. 将该节点移动到头部位置</span></span><br><span class="line">    this.moveToHead(node)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> node.Value</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(this *LRUCache)</span></span> Put(key <span class="type">int</span>, value <span class="type">int</span>)  &#123;</span><br><span class="line">    existNode, ok := this.NodeMap[key]</span><br><span class="line">    <span class="keyword">if</span> ok &#123;</span><br><span class="line">        <span class="comment">// 如果已经存在</span></span><br><span class="line">        existNode.Value = value</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 从当前位置删除</span></span><br><span class="line">        this.delNode(existNode)</span><br><span class="line">        <span class="comment">// 移动到头部位置</span></span><br><span class="line">        this.moveToHead(existNode)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    node := &amp;Node&#123;</span><br><span class="line">        Key: key,</span><br><span class="line">        Value: value,</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 首先加载到map中</span></span><br><span class="line">    this.NodeMap[key] = node</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 1. 如果size &lt; cap</span></span><br><span class="line">    <span class="keyword">if</span> this.Size &lt; this.Cap &#123;</span><br><span class="line">        <span class="comment">// 1.1 将节点放到头部位置</span></span><br><span class="line">        this.moveToHead(node)</span><br><span class="line">        <span class="comment">// 1.2 size+1</span></span><br><span class="line">        this.Size++</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 2. 如果size = cap</span></span><br><span class="line">        <span class="comment">// 2.1 讲节点放到头部位置</span></span><br><span class="line">        this.moveToHead(node)</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 2.2 删除末尾节点</span></span><br><span class="line">        nowTailPre := this.Tail.Pre</span><br><span class="line">        this.delNode(nowTailPre)</span><br><span class="line">        <span class="comment">// 从map里面删除</span></span><br><span class="line">        <span class="built_in">delete</span>(this.NodeMap, nowTailPre.Key)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><a href="https://leetcode.cn/problems/lru-cache/solution/yi-kan-jiu-dong-de-xie-fa-by-adjutantz-1k1z/">飞向：leetcode-lru</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;分析需求&quot;&gt;&lt;a href=&quot;#分析需求&quot; class=&quot;headerlink&quot; title=&quot;分析需求&quot;&gt;&lt;/a&gt;分析需求&lt;/h3&gt;&lt;h4 id=&quot;Get&quot;&gt;&lt;a href=&quot;#Get&quot; class=&quot;headerlink&quot; title=&quot;Get&quot;&gt;&lt;/a&gt;Ge
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="hash" scheme="http://www.zhangfuguan.top/tags/hash/"/>
    
      <category term="双向链表" scheme="http://www.zhangfuguan.top/tags/%E5%8F%8C%E5%90%91%E9%93%BE%E8%A1%A8/"/>
    
  </entry>
  
  <entry>
    <title>双指针-链表拆分与合并</title>
    <link href="http://www.zhangfuguan.top/2023/06/20/%E8%A3%85%E6%8C%87%E9%92%88%E9%93%BE%E8%A1%A8%E6%8B%86%E5%88%86%E4%B8%8E%E5%90%88%E5%B9%B6/"/>
    <id>http://www.zhangfuguan.top/2023/06/20/装指针链表拆分与合并/</id>
    <published>2023-06-20T15:08:30.000Z</published>
    <updated>2023-06-23T11:05:01.336Z</updated>
    
    <content type="html"><![CDATA[<h3 id="教程"><a href="#教程" class="headerlink" title="教程"></a>教程</h3><p><a href="https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-8f30d/shuang-zhi-0f7cc/">双指针技巧秒杀七道链表题目</a></p><h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><h4 id="合并两个有序链表"><a href="#合并两个有序链表" class="headerlink" title="合并两个有序链表"></a>合并两个有序链表</h4><p><a href="https://leetcode.cn/problems/merge-two-sorted-lists/">力扣-21-合并两个有序链表</a></p><ul><li>只用两个指针指向两个链表，每次取值的时候移动，如果俩链表中至少有一个遍历完成则结束，把没遍历完成的链表直接放在新链表的后面<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * type ListNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Next *ListNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">mergeTwoLists</span><span class="params">(list1 *ListNode, list2 *ListNode)</span></span> *ListNode &#123;</span><br><span class="line">    <span class="comment">// 此处纯属优化</span></span><br><span class="line">    <span class="keyword">if</span> list1 == <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> list2</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> list2 == <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> list1</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    head := &amp;ListNode&#123;&#125;</span><br><span class="line">    <span class="comment">// 这里为啥要重新赋值一下，因为最终结果需要返回第一个节点</span></span><br><span class="line">    node := head</span><br><span class="line">    p1 := list1</span><br><span class="line">    p2 := list2</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> p1 != <span class="literal">nil</span> &amp;&amp; p2 != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> p1.Val &lt; p2.Val &#123;</span><br><span class="line">            node.Next = p1</span><br><span class="line">            p1 = p1.Next</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            node.Next = p2</span><br><span class="line">            p2 = p2.Next</span><br><span class="line">        &#125;</span><br><span class="line">        node = node.Next</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 为啥有下面这两行，是因为可能某一个遍历完成，而另外一个还没有，姐可以直接放在后面了</span></span><br><span class="line">    <span class="keyword">if</span> p1 != <span class="literal">nil</span> &#123;</span><br><span class="line">        node.Next = p1</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> p2 != <span class="literal">nil</span> &#123;</span><br><span class="line">        node.Next = p2</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 这里为啥是next, 因为我们为了方便head是一个无效的节点</span></span><br><span class="line">    <span class="keyword">return</span> head.Next</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ul><h4 id="分隔链表"><a href="#分隔链表" class="headerlink" title="分隔链表"></a>分隔链表</h4><p><a href="https://leetcode.cn/problems/partition-list/">力扣-86-分隔链表</a></p><ul><li>使用两个链表分别保存小于和大于或等于的值，最后合并。需要注意俩个点：1. 目标链表每遍历一个节点就把指针往后移动，并断开前面的节点；2. 合并的时候只需要判断保存大值的连边是否为空，如果不为空直接放在小值连边后面，最后返回小值链表的头部（注意：我们为了操作方便，在定义链表的时候第一个节点是无效节点，所以表头节点是第二个节点）。<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * type ListNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Next *ListNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">partition</span><span class="params">(head *ListNode, x <span class="type">int</span>)</span></span> *ListNode &#123;</span><br><span class="line">    p1 := &amp;ListNode&#123;&#125;</span><br><span class="line">    p1Head := p1</span><br><span class="line">    p2 := &amp;ListNode&#123;&#125;</span><br><span class="line">    p2Head := p2</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> head != <span class="literal">nil</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> head.Val &lt; x &#123;</span><br><span class="line">            p1.Next = head</span><br><span class="line">            p1 = p1.Next</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            p2.Next = head</span><br><span class="line">            p2 = p2.Next</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 断开已经处理完成的节点</span></span><br><span class="line">        temp := head.Next</span><br><span class="line">        head.Next = <span class="literal">nil</span></span><br><span class="line">        head = temp</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 大值链表不为空就直接放在后面</span></span><br><span class="line">    <span class="keyword">if</span> p2Head.Next != <span class="literal">nil</span> &#123;</span><br><span class="line">        p1.Next = p2Head.Next</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> p1Head.Next</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h4 id="反馈倒数第K个节点"><a href="#反馈倒数第K个节点" class="headerlink" title="反馈倒数第K个节点"></a>反馈倒数第K个节点</h4><p><a href="https://leetcode.cn/problems/kth-node-from-end-of-list-lcci/">力扣-2-返回倒数第K个节点</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * type ListNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Next *ListNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">kthToLast</span><span class="params">(head *ListNode, k <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    p := head</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">1</span>; i &lt;= k; i++ &#123;</span><br><span class="line">        head = head.Next</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> head != <span class="literal">nil</span> &#123;</span><br><span class="line">        head = head.Next</span><br><span class="line">        p = p.Next</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> p.Val</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="返回中间接点"><a href="#返回中间接点" class="headerlink" title="返回中间接点"></a>返回中间接点</h4><ul><li>其实就是利用快慢指针</li></ul><p><a href="https://leetcode.cn/problems/middle-of-the-linked-list/submissions/">力扣-876-链表中加结点</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">middleNode</span><span class="params">(head *ListNode)</span></span> *ListNode &#123;</span><br><span class="line">    fast, slow := head, head</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> fast != <span class="literal">nil</span> &amp;&amp; fast.Next != <span class="literal">nil</span> &#123;</span><br><span class="line">        fast = fast.Next.Next</span><br><span class="line">        slow = slow.Next</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> slow</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="环形链表"><a href="#环形链表" class="headerlink" title="环形链表"></a>环形链表</h4><p><a href="https://leetcode.cn/problems/linked-list-cycle/submissions/">力扣-141-环形链表</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">hasCycle</span><span class="params">(head *ListNode)</span></span> <span class="type">bool</span> &#123;</span><br><span class="line">    fast, slow := head, head</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> fast != <span class="literal">nil</span> &amp;&amp; fast.Next != <span class="literal">nil</span> &#123;</span><br><span class="line">        slow = slow.Next</span><br><span class="line">        fast = fast.Next.Next</span><br><span class="line">        <span class="keyword">if</span> slow == fast &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="环形链表II"><a href="#环形链表II" class="headerlink" title="环形链表II"></a>环形链表II</h4><p><a href="https://www.bilibili.com/video/BV1KG4y1G7cu/?vd_source=2cb3c639254a66c279203f3687b0bee9">环形链表II【基础算法精讲 07】_哔哩哔哩_bilibili</a><br><a href="https://leetcode.cn/problems/linked-list-cycle-ii/submissions/">力扣-142-环形链表II</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * type ListNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Next *ListNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">detectCycle</span><span class="params">(head *ListNode)</span></span> *ListNode &#123;</span><br><span class="line">    slow, fast := head, head</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> fast != <span class="literal">nil</span> &amp;&amp; fast.Next != <span class="literal">nil</span> &#123;</span><br><span class="line">        fast = fast.Next.Next</span><br><span class="line">        slow = slow.Next</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> fast == slow &#123;</span><br><span class="line">            <span class="keyword">for</span> head != slow &#123;</span><br><span class="line">                head = head.Next</span><br><span class="line">                slow = slow.Next</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">return</span> slow</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="相交链表"><a href="#相交链表" class="headerlink" title="相交链表"></a>相交链表</h4><p><a href="https://leetcode.cn/problems/intersection-of-two-linked-lists/">力扣-160-相交链表</a></p><h5 id="双指针-暴力破解"><a href="#双指针-暴力破解" class="headerlink" title="双指针-暴力破解"></a>双指针-暴力破解</h5><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * type ListNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Next *ListNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getIntersectionNode</span><span class="params">(headA, headB *ListNode)</span></span> *ListNode &#123;</span><br><span class="line">    <span class="keyword">for</span> headA != <span class="literal">nil</span> &#123;</span><br><span class="line">        tempB := headB</span><br><span class="line">        <span class="keyword">for</span> tempB != <span class="literal">nil</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> tempB == headA &#123;</span><br><span class="line">                <span class="keyword">return</span> tempB</span><br><span class="line">            &#125;</span><br><span class="line">            tempB = tempB.Next</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        headA = headA.Next</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="双指针-拼接"><a href="#双指针-拼接" class="headerlink" title="双指针-拼接"></a>双指针-拼接</h5><ul><li>把两个链表拼接到一起<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for singly-linked list.</span></span><br><span class="line"><span class="comment"> * type ListNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Next *ListNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">getIntersectionNode</span><span class="params">(headA, headB *ListNode)</span></span> *ListNode &#123;</span><br><span class="line">    a, b := headA, headB</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> a != b &#123;</span><br><span class="line">        <span class="keyword">if</span> a == <span class="literal">nil</span> &#123;</span><br><span class="line">            a = headB</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            a = a.Next</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> b == <span class="literal">nil</span> &#123;</span><br><span class="line">            b = headA</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            b = b.Next</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> a</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;教程&quot;&gt;&lt;a href=&quot;#教程&quot; class=&quot;headerlink&quot; title=&quot;教程&quot;&gt;&lt;/a&gt;教程&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="双指针" scheme="http://www.zhangfuguan.top/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
  </entry>
  
  <entry>
    <title>双指针-N数之和</title>
    <link href="http://www.zhangfuguan.top/2023/06/15/n%E6%95%B0%E4%B9%8B%E5%92%8C/"/>
    <id>http://www.zhangfuguan.top/2023/06/15/n数之和/</id>
    <published>2023-06-15T15:08:13.000Z</published>
    <updated>2023-06-20T15:07:57.002Z</updated>
    
    <content type="html"><![CDATA[<h3 id="教程"><a href="#教程" class="headerlink" title="教程"></a>教程</h3><p><a href="https://www.bilibili.com/video/BV1bP411c7oJ/?vd_source=2cb3c639254a66c279203f3687b0bee9">两数之和 三数之和【基础算法精讲 02】_哔哩哔哩_bilibili</a><br><a href="https://labuladong.github.io/algo/di-ling-zh-bfe1b/yi-ge-fang-894da/">一个方法团灭 nSum 问题 :: labuladong的算法小抄</a></p><h3 id><a href="#" class="headerlink" title></a></h3><h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><h4 id="两数之和"><a href="#两数之和" class="headerlink" title="两数之和"></a>两数之和</h4><p><a href="https://leetcode.cn/problems/two-sum/">力扣-1-两数之和</a></p><h5 id="hash表"><a href="#hash表" class="headerlink" title="hash表"></a>hash表</h5><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">twoSum</span><span class="params">(nums []<span class="type">int</span>, target <span class="type">int</span>)</span></span> []<span class="type">int</span> &#123;</span><br><span class="line">    numsMap := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">int</span>]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> i, v := <span class="keyword">range</span> nums &#123;</span><br><span class="line">        <span class="keyword">if</span> index, ok := numsMap[target-v]; ok &#123;</span><br><span class="line">            <span class="keyword">return</span> []<span class="type">int</span>&#123;index, i&#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        numsMap[v] = i</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="暴力破解双遍历"><a href="#暴力破解双遍历" class="headerlink" title="暴力破解双遍历"></a>暴力破解双遍历</h5><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">twoSum</span><span class="params">(nums []<span class="type">int</span>, target <span class="type">int</span>)</span></span> []<span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i&lt; <span class="built_in">len</span>(nums); i++ &#123;</span><br><span class="line">        <span class="keyword">for</span> j := i+<span class="number">1</span>; j&lt;<span class="built_in">len</span>(nums); j++ &#123;</span><br><span class="line">            <span class="keyword">if</span> nums[i] + nums[j] == target &#123;</span><br><span class="line">                <span class="keyword">return</span> []<span class="type">int</span>&#123;i, j&#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="三数之和"><a href="#三数之和" class="headerlink" title="三数之和"></a>三数之和</h4><p><a href="https://leetcode.cn/problems/3sum/">力扣-15-三数之和</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">threeSum</span><span class="params">(nums []<span class="type">int</span>)</span></span> [][]<span class="type">int</span> &#123;</span><br><span class="line">    <span class="comment">// 排序</span></span><br><span class="line">    sort.Ints(nums)</span><br><span class="line">    <span class="comment">// 保存结果</span></span><br><span class="line">    res := <span class="built_in">make</span>([][]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line">    <span class="comment">// 数组长度</span></span><br><span class="line">    n := <span class="built_in">len</span>(nums)</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 这里为什么-2？</span></span><br><span class="line">    <span class="comment">// 因为这是有序数组，如果有复合条件的结果[下表i,j,k]必然是i&lt;j&lt;k， 所以需要给j, k预留位置</span></span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; n<span class="number">-2</span>; i++ &#123;</span><br><span class="line">        <span class="comment">// 首先nums是有序数组</span></span><br><span class="line">        <span class="comment">// 如果某一列中最小的两个数之和加起来都大于0，则说明和其余的数加起来必然大于0</span></span><br><span class="line">        <span class="keyword">if</span> i &gt; <span class="number">0</span> &amp;&amp; nums[i]+nums[i<span class="number">-1</span>] &gt; <span class="number">0</span> &#123;</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 元素相同，避免重复，则跳过</span></span><br><span class="line">        <span class="keyword">if</span> i&gt;<span class="number">0</span> &amp;&amp; nums[i] == nums[i<span class="number">-1</span>] &#123;</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        j := i+<span class="number">1</span> <span class="comment">// 中间位置</span></span><br><span class="line">        k := n<span class="number">-1</span> <span class="comment">// 最大值的位置，即最右边的位置</span></span><br><span class="line">        <span class="keyword">for</span> j &lt; k &#123;</span><br><span class="line">            sum := nums[i]+nums[j]+nums[k]</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> sum == <span class="number">0</span> &#123;</span><br><span class="line">                res = <span class="built_in">append</span>(res, []<span class="type">int</span>&#123;nums[i], nums[j], nums[k]&#125;)</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 还需要排除重复的</span></span><br><span class="line">                j++</span><br><span class="line">                <span class="keyword">for</span> j &lt; k &amp;&amp; nums[j]==nums[j<span class="number">-1</span>] &#123;</span><br><span class="line">                    j++</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                k--</span><br><span class="line">                <span class="keyword">for</span> j &lt; k &amp;&amp; nums[k] == nums[k+<span class="number">1</span>] &#123;</span><br><span class="line">                    k--</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            <span class="keyword">if</span> sum &lt; <span class="number">0</span> &#123;</span><br><span class="line">                <span class="comment">// 小于0， 则说明中间值太小了，j需要往右边移动</span></span><br><span class="line">                j++</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> sum &gt; <span class="number">0</span> &#123;</span><br><span class="line">                <span class="comment">// 大于0，则说明中间值太大了，需要将最右边的k往左边移动</span></span><br><span class="line">                k--</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="四数之和"><a href="#四数之和" class="headerlink" title="四数之和"></a>四数之和</h4><p><a href="https://leetcode.cn/problems/4sum/submissions/">力扣-18-四数之和</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 其实和三数之和是一个意思，就是先固定第一个数，然后三个数按照三数之和来处理</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">fourSum</span><span class="params">(nums []<span class="type">int</span>, target <span class="type">int</span>)</span></span> [][]<span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(nums) &lt; <span class="number">4</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">    &#125;</span><br><span class="line">    sort.Ints(nums)</span><br><span class="line"></span><br><span class="line">    res := <span class="built_in">make</span>([][]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line">    <span class="keyword">for</span> i :=<span class="number">0</span>; i&lt;<span class="built_in">len</span>(nums)<span class="number">-3</span>; i++ &#123;</span><br><span class="line">        <span class="keyword">if</span> i &gt; <span class="number">0</span> &amp;&amp; nums[i<span class="number">-1</span>] == nums[i] &#123;</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        <span class="keyword">for</span> j := i+<span class="number">1</span>; j&lt;<span class="built_in">len</span>(nums)<span class="number">-2</span>; j++ &#123;</span><br><span class="line">            <span class="keyword">if</span> j&gt;i+<span class="number">1</span> &amp;&amp; nums[j] == nums[j<span class="number">-1</span>] &#123;</span><br><span class="line">                <span class="keyword">continue</span></span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            k := j+<span class="number">1</span></span><br><span class="line">            r := <span class="built_in">len</span>(nums)<span class="number">-1</span></span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> k &lt; r &#123;</span><br><span class="line">                sum := nums[i]+nums[j]+nums[k]+nums[r]</span><br><span class="line">                <span class="keyword">if</span> sum &lt; target &#123;</span><br><span class="line">                    k++</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> sum  &gt; target &#123;</span><br><span class="line">                    r--</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">if</span> sum == target &#123;</span><br><span class="line">                    res = <span class="built_in">append</span>(res, []<span class="type">int</span>&#123;nums[i],nums[j],nums[k],nums[r]&#125;)</span><br><span class="line">                    k++</span><br><span class="line">                    <span class="keyword">for</span> k &lt; r &amp;&amp; nums[k]==nums[k<span class="number">-1</span>] &#123;</span><br><span class="line">                        k++    </span><br><span class="line">                    &#125;</span><br><span class="line">                    r--</span><br><span class="line">                     <span class="keyword">for</span> k &lt; r &amp;&amp; nums[r]==nums[r+<span class="number">1</span>] &#123;</span><br><span class="line">                        r--    </span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;教程&quot;&gt;&lt;a href=&quot;#教程&quot; class=&quot;headerlink&quot; title=&quot;教程&quot;&gt;&lt;/a&gt;教程&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1bP411c7oJ/?vd_source=2cb3c6
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="双指针" scheme="http://www.zhangfuguan.top/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
  </entry>
  
  <entry>
    <title>二叉树深度问题</title>
    <link href="http://www.zhangfuguan.top/2023/06/13/%E4%BA%8C%E5%8F%89%E6%A0%91%E6%B7%B1%E5%BA%A6%E9%97%AE%E9%A2%98/"/>
    <id>http://www.zhangfuguan.top/2023/06/13/二叉树深度问题/</id>
    <published>2023-06-13T00:11:10.000Z</published>
    <updated>2023-06-13T00:13:02.306Z</updated>
    
    <content type="html"><![CDATA[<h3 id="最小深度"><a href="#最小深度" class="headerlink" title="最小深度"></a>最小深度</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">minDepth</span><span class="params">(root *TreeNode)</span></span> <span class="type">int</span> &#123;</span><br><span class="line"><span class="keyword">if</span> root == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line">minDepth := math.MaxInt64</span><br><span class="line"><span class="keyword">var</span> dfs <span class="function"><span class="keyword">func</span><span class="params">(node *TreeNode, depth <span class="type">int</span>)</span></span></span><br><span class="line">dfs = <span class="function"><span class="keyword">func</span><span class="params">(node *TreeNode, depth <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">depth ++</span><br><span class="line"><span class="keyword">if</span> node.Left == <span class="literal">nil</span> &amp;&amp; node.Right == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">if</span> depth &lt; minDepth &#123;</span><br><span class="line">minDepth = depth </span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">dfs(node.Left, depth)</span><br><span class="line">dfs(node.Right, depth)</span><br><span class="line">&#125;</span><br><span class="line">dfs(root, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">return</span> minDepth</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="最大深度"><a href="#最大深度" class="headerlink" title="最大深度"></a>最大深度</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">maxDepth</span><span class="params">(root *TreeNode)</span></span> <span class="type">int</span> &#123;</span><br><span class="line"><span class="keyword">if</span> root == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">&#125;</span><br><span class="line">minDepth := <span class="number">0</span></span><br><span class="line"><span class="keyword">var</span> dfs <span class="function"><span class="keyword">func</span><span class="params">(node *TreeNode, depth <span class="type">int</span>)</span></span></span><br><span class="line">dfs = <span class="function"><span class="keyword">func</span><span class="params">(node *TreeNode, depth <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">depth ++</span><br><span class="line"><span class="keyword">if</span> node.Left == <span class="literal">nil</span> &amp;&amp; node.Right == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">if</span> depth &gt; minDepth &#123;</span><br><span class="line">minDepth = depth </span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">dfs(node.Left, depth)</span><br><span class="line">dfs(node.Right, depth)</span><br><span class="line">&#125;</span><br><span class="line">dfs(root, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">return</span> minDepth</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;最小深度&quot;&gt;&lt;a href=&quot;#最小深度&quot; class=&quot;headerlink&quot; title=&quot;最小深度&quot;&gt;&lt;/a&gt;最小深度&lt;/h3&gt;&lt;figure class=&quot;highlight go&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="dfs" scheme="http://www.zhangfuguan.top/tags/dfs/"/>
    
      <category term="二叉树" scheme="http://www.zhangfuguan.top/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
    
  </entry>
  
  <entry>
    <title>dfs-岛屿问题</title>
    <link href="http://www.zhangfuguan.top/2023/06/11/dfs-%E5%B2%9B%E5%B1%BF%E9%97%AE%E9%A2%98/"/>
    <id>http://www.zhangfuguan.top/2023/06/11/dfs-岛屿问题/</id>
    <published>2023-06-11T05:03:27.000Z</published>
    <updated>2023-06-11T05:05:49.439Z</updated>
    
    <content type="html"><![CDATA[<h3 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h3><p><a href="https://leetcode.cn/problems/number-of-islands/submissions/">力扣-200-岛屿数量</a><br><a href="https://leetcode.cn/problems/max-area-of-island/submissions/">力扣-695-岛屿最大面积</a><br><a href="https://leetcode.cn/problems/number-of-closed-islands/">力扣-1254-封闭岛屿数量</a></p><h4 id="思路讲解"><a href="#思路讲解" class="headerlink" title="思路讲解"></a>思路讲解</h4><p><a href="https://labuladong.github.io/algo/di-san-zha-24031/bao-li-sou-96f79/yi-wen-mia-4f482/">labuladong-一文搞定岛屿问题</a></p><h4 id="岛屿数量"><a href="#岛屿数量" class="headerlink" title="岛屿数量"></a>岛屿数量</h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">numIslands</span><span class="params">(grid [][]<span class="type">byte</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(grid) == <span class="number">0</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(grid[<span class="number">0</span>]) == <span class="number">0</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 记录总的结果</span></span><br><span class="line">    res := <span class="number">0</span></span><br><span class="line">    m := <span class="built_in">len</span>(grid)</span><br><span class="line">    n := <span class="built_in">len</span>(grid[<span class="number">0</span>])</span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i&lt;m; i++ &#123;</span><br><span class="line">        <span class="keyword">for</span> j := <span class="number">0</span>; j&lt;n; j++ &#123;</span><br><span class="line">            <span class="keyword">if</span> grid[i][j] == <span class="string">&#x27;1&#x27;</span> &#123;</span><br><span class="line">                res++</span><br><span class="line">                toWater(grid, i, j)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">toWater</span><span class="params">(grid [][]<span class="type">byte</span>, i, j <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">    m := <span class="built_in">len</span>(grid)</span><br><span class="line">    n := <span class="built_in">len</span>(grid[<span class="number">0</span>])</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> dfs <span class="function"><span class="keyword">func</span><span class="params">(grid [][]<span class="type">byte</span>, r, c <span class="type">int</span>)</span></span></span><br><span class="line">    dfs = <span class="function"><span class="keyword">func</span><span class="params">(grid [][]<span class="type">byte</span>, r, c <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">if</span> r &lt; <span class="number">0</span> || c &lt; <span class="number">0</span> || r &gt;= m || c &gt;= n &#123;</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 已经是海水</span></span><br><span class="line">        <span class="keyword">if</span> grid[r][c] == <span class="string">&#x27;0&#x27;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 遍历过的陆地转为海水</span></span><br><span class="line">        grid[r][c] = <span class="string">&#x27;0&#x27;</span></span><br><span class="line"></span><br><span class="line">        dfs(grid, r<span class="number">-1</span>, c)</span><br><span class="line">        dfs(grid, r+<span class="number">1</span>, c)</span><br><span class="line">        dfs(grid, r, c<span class="number">-1</span>)</span><br><span class="line">        dfs(grid, r, c+<span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    dfs(grid, i, j)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="岛屿最大面积"><a href="#岛屿最大面积" class="headerlink" title="岛屿最大面积"></a>岛屿最大面积</h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">maxAreaOfIsland</span><span class="params">(grid [][]<span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    m := <span class="built_in">len</span>(grid)</span><br><span class="line">    n := <span class="built_in">len</span>(grid[<span class="number">0</span>])</span><br><span class="line">    maxIsland := <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> i:=<span class="number">0</span>; i&lt;m; i++ &#123;</span><br><span class="line">        <span class="keyword">for</span> j:=<span class="number">0</span>; j&lt;n; j++ &#123;</span><br><span class="line">            <span class="keyword">if</span> grid[i][j] == <span class="number">1</span> &#123;</span><br><span class="line">                nowIsland := toWater(grid, i, j)</span><br><span class="line">                <span class="keyword">if</span> nowIsland &gt; maxIsland &#123;</span><br><span class="line">                    maxIsland = nowIsland</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> maxIsland</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">toWater</span><span class="params">(grid [][]<span class="type">int</span>, i, j <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    m := <span class="built_in">len</span>(grid)</span><br><span class="line">    n := <span class="built_in">len</span>(grid[<span class="number">0</span>])</span><br><span class="line">    sum := <span class="number">0</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">var</span> dfs <span class="function"><span class="keyword">func</span><span class="params">(grid [][]<span class="type">int</span>, r, c <span class="type">int</span>)</span></span></span><br><span class="line">    dfs = <span class="function"><span class="keyword">func</span><span class="params">(grid [][]<span class="type">int</span>, r, c <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">if</span> r &lt; <span class="number">0</span> || c &lt; <span class="number">0</span> || r&gt;=m || c &gt;= n &#123;</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> grid[r][c] == <span class="number">0</span> &#123;</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">        sum++</span><br><span class="line">        grid[r][c] = <span class="number">0</span></span><br><span class="line"></span><br><span class="line">        dfs(grid, r<span class="number">-1</span>, c)</span><br><span class="line">        dfs(grid, r+<span class="number">1</span>, c)</span><br><span class="line">        dfs(grid, r, c<span class="number">-1</span>)</span><br><span class="line">        dfs(grid, r, c+<span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    dfs(grid, i, j)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> sum</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="封闭岛屿数量"><a href="#封闭岛屿数量" class="headerlink" title="封闭岛屿数量"></a>封闭岛屿数量</h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">closedIsland</span><span class="params">(grid [][]<span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    m := <span class="built_in">len</span>(grid)</span><br><span class="line">    n := <span class="built_in">len</span>(grid[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 把第一行和最后一行的岛屿转为海水</span></span><br><span class="line">    <span class="keyword">for</span> j := <span class="number">0</span>; j&lt;n; j++ &#123;</span><br><span class="line">        toWater(grid, <span class="number">0</span>, j)</span><br><span class="line">        toWater(grid, m<span class="number">-1</span>, j)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 把第一列和最后一列转为海水</span></span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i&lt;m; i++ &#123;</span><br><span class="line">        toWater(grid, i, <span class="number">0</span>)</span><br><span class="line">        toWater(grid, i, n<span class="number">-1</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    res := <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i :=<span class="number">0</span>; i&lt;m; i++ &#123;</span><br><span class="line">        <span class="keyword">for</span> j := <span class="number">0</span>; j&lt;n; j++ &#123;</span><br><span class="line">            <span class="keyword">if</span> grid[i][j] == <span class="number">0</span> &#123;</span><br><span class="line">                res++</span><br><span class="line">                toWater(grid,i,j)</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">toWater</span><span class="params">(grid [][]<span class="type">int</span>, i, j <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">    m := <span class="built_in">len</span>(grid)</span><br><span class="line">    n := <span class="built_in">len</span>(grid[<span class="number">0</span>])</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> dfs <span class="function"><span class="keyword">func</span><span class="params">(grid [][]<span class="type">int</span>, r, c <span class="type">int</span>)</span></span></span><br><span class="line">    dfs = <span class="function"><span class="keyword">func</span><span class="params">(grid [][]<span class="type">int</span>, r, c <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">if</span> r &lt; <span class="number">0</span> || c &lt; <span class="number">0</span> || r &gt;=m || c &gt;=n &#123;</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> grid[r][c] == <span class="number">1</span> &#123;</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        grid[r][c] = <span class="number">1</span></span><br><span class="line"></span><br><span class="line">        dfs(grid, r, c<span class="number">-1</span>)</span><br><span class="line">        dfs(grid, r, c+<span class="number">1</span>)</span><br><span class="line">        dfs(grid, r<span class="number">-1</span>, c)</span><br><span class="line">        dfs(grid, r+<span class="number">1</span>, c)</span><br><span class="line">    &#125;</span><br><span class="line">    dfs(grid, i, j)</span><br><span class="line">    <span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;题目&quot;&gt;&lt;a href=&quot;#题目&quot; class=&quot;headerlink&quot; title=&quot;题目&quot;&gt;&lt;/a&gt;题目&lt;/h3&gt;&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/number-of-islands/submissions/&quot;&gt;
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="dfs" scheme="http://www.zhangfuguan.top/tags/dfs/"/>
    
  </entry>
  
  <entry>
    <title>双指针-子数字问题</title>
    <link href="http://www.zhangfuguan.top/2023/06/11/%E5%8F%8C%E6%8C%87%E9%92%88-%E5%AD%90%E6%95%B0%E5%AD%97%E9%97%AE%E9%A2%98/"/>
    <id>http://www.zhangfuguan.top/2023/06/11/双指针-子数字问题/</id>
    <published>2023-06-11T04:54:30.000Z</published>
    <updated>2023-06-11T04:58:21.885Z</updated>
    
    <content type="html"><![CDATA[<h4 id="题目大纲"><a href="#题目大纲" class="headerlink" title="题目大纲"></a>题目大纲</h4><p><a href="https://leetcode.cn/problems/minimum-size-subarray-sum/submissions/">力扣-209-长度最小的子数组</a><br><a href="https://leetcode.cn/problems/subarray-product-less-than-k/submissions/">力扣-713-乘积小于K的子数组</a><br><a href="https://leetcode.cn/problems/max-consecutive-ones-iii/">力扣-1004-最大连续1的个数III</a><br><a href="https://leetcode.cn/problems/replace-the-substring-for-balanced-string/">力扣-1234-替换子串得到平衡串</a><br><a href="https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/">力扣-1658-将x减到0的最小操作数</a></p><h4 id="思路讲解"><a href="#思路讲解" class="headerlink" title="思路讲解"></a>思路讲解</h4><p><a href="https://www.bilibili.com/video/BV1hd4y1r7Gq/?vd_source=2cb3c639254a66c279203f3687b0bee9">同向双指针 滑动窗口【基础算法精讲 01】_哔哩哔哩_bilibili</a></p><h4 id="长度最小的子数组"><a href="#长度最小的子数组" class="headerlink" title="长度最小的子数组"></a>长度最小的子数组</h4><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">minSubArrayLen</span><span class="params">(target <span class="type">int</span>, nums []<span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    minLen := <span class="built_in">len</span>(nums)+<span class="number">1</span> <span class="comment">// 这里保证初始量比最大值还大就行，还有一种方式是直接用math.MaxInt</span></span><br><span class="line">    left := <span class="number">0</span></span><br><span class="line">    sum := <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> right:= <span class="number">0</span>; right &lt; <span class="built_in">len</span>(nums); right++ &#123;</span><br><span class="line">        sum = sum + nums[right]</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> sum &gt;= target &#123;</span><br><span class="line">            nowLen := right-left+<span class="number">1</span></span><br><span class="line">            <span class="keyword">if</span> nowLen &lt; minLen &#123;</span><br><span class="line">                minLen = nowLen</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 移动左指针</span></span><br><span class="line">            sum = sum - nums[left]</span><br><span class="line">            left++</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> minLen == <span class="built_in">len</span>(nums)+<span class="number">1</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> minLen</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="乘积小于k的子数组"><a href="#乘积小于k的子数组" class="headerlink" title="乘积小于k的子数组"></a>乘积小于k的子数组</h4><ul><li>核心点在于：假设左指针为left，右指针为right，则固定right点，所有满足条件的子数组数量为：right-left+1<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">numSubarrayProductLessThanK</span><span class="params">(nums []<span class="type">int</span>, k <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> k &lt;= <span class="number">1</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    res := <span class="number">0</span></span><br><span class="line">    left := <span class="number">0</span></span><br><span class="line">    product := <span class="number">1</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> right := <span class="number">0</span>; right &lt; <span class="built_in">len</span>(nums); right++ &#123;</span><br><span class="line">        product = product * nums[right]</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> product &gt;= k &#123;</span><br><span class="line">            product = product/nums[left]</span><br><span class="line">            left++</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        res = res + (right-left+<span class="number">1</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> res</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ul><h4 id="无重复字符的最小子串"><a href="#无重复字符的最小子串" class="headerlink" title="无重复字符的最小子串"></a>无重复字符的最小子串</h4><h5 id="使用简单map"><a href="#使用简单map" class="headerlink" title="使用简单map"></a>使用简单map</h5><ul><li>首先使用map保存right遍历过的节点，key为字符对应的字节，value为字节在字符串数组中的位置</li><li>如果没有重复，则当前无重复结果now+1，并且把当前字符加入到map中</li><li>如果有重复，则把left指针移动到重复节点的后面一个，并且需要删除原来left-》重复节点，最后把当前节点计入map<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">lengthOfLongestSubstring</span><span class="params">(s <span class="type">string</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(s) == <span class="number">0</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    strMap := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">byte</span>]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line">    left := <span class="number">0</span></span><br><span class="line">    now := <span class="number">0</span></span><br><span class="line">    max := <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> right:=<span class="number">0</span>; right &lt; <span class="built_in">len</span>(s); right++ &#123;</span><br><span class="line">        <span class="keyword">if</span> existIndex, ok := strMap[s[right]]; ok &#123;</span><br><span class="line">            <span class="keyword">for</span> left &lt; existIndex+<span class="number">1</span> &#123;</span><br><span class="line">                <span class="built_in">delete</span>(strMap, s[left])</span><br><span class="line">                left++</span><br><span class="line">            &#125;</span><br><span class="line">            left = existIndex+<span class="number">1</span></span><br><span class="line">            strMap[s[right]] = right</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            strMap[s[right]] = right</span><br><span class="line">            now = right-left+<span class="number">1</span></span><br><span class="line">            <span class="keyword">if</span> now &gt; max &#123;</span><br><span class="line">                max = now</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> max</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><img src="/2023/06/11/%E5%8F%8C%E6%8C%87%E9%92%88-%E5%AD%90%E6%95%B0%E5%AD%97%E9%97%AE%E9%A2%98/1.jpg" alt="image.png"></li></ul><p>有更好的做法》》》》》 hhhh, 是我看大佬教程学到的，上面是自己琢磨的。</p><h5 id="使用map计数器"><a href="#使用map计数器" class="headerlink" title="使用map计数器"></a>使用map计数器</h5><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">lengthOfLongestSubstring</span><span class="params">(s <span class="type">string</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(s) == <span class="number">0</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    strCounter := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">byte</span>]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line">    left := <span class="number">0</span></span><br><span class="line">    max := <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> right := <span class="number">0</span>; right &lt; <span class="built_in">len</span>(s); right++ &#123;</span><br><span class="line">        strCounter[s[right]]++</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> strCounter[s[right]] &gt; <span class="number">1</span> &#123;</span><br><span class="line">            strCounter[s[left]]--</span><br><span class="line">            left++</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> right-left+<span class="number">1</span> &gt; max &#123;</span><br><span class="line">            max = right-left+<span class="number">1</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> max</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="最大连续1的个数III"><a href="#最大连续1的个数III" class="headerlink" title="最大连续1的个数III"></a>最大连续1的个数III</h4><p>关键在于Counter的设计</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">longestOnes</span><span class="params">(nums []<span class="type">int</span>, k <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(nums) &lt;= k &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">len</span>(nums)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    left := <span class="number">0</span></span><br><span class="line">    maxLen := <span class="number">0</span></span><br><span class="line">    zeroCounter := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">int</span>]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> right := <span class="number">0</span>; right &lt; <span class="built_in">len</span>(nums); right++ &#123;</span><br><span class="line">        zeroCounter[nums[right]]++</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> nums[right] == <span class="number">0</span> &#123;</span><br><span class="line">            <span class="keyword">for</span> zeroCounter[nums[right]] &gt; k &#123;</span><br><span class="line">                zeroCounter[nums[left]]--</span><br><span class="line">                left++</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> right-left+<span class="number">1</span> &gt; maxLen &#123;</span><br><span class="line">            maxLen = right-left+<span class="number">1</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> maxLen</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="替换子串得到平衡串"><a href="#替换子串得到平衡串" class="headerlink" title="替换子串得到平衡串"></a>替换子串得到平衡串</h4><ul><li>假设字符串长度为n</li><li>如果Q&#x2F;W&#x2F;E&#x2F;R的出现次数都等于n&#x2F;4，则说明已经平衡了</li><li>如果除了子串之外的字符Q&#x2F;W&#x2F;E&#x2F;R的出现次数都小于或等于n&#x2F;4，说明可以通过子串的填补来实现平衡；如果大于n&#x2F;4则说明无法通过当前子串来实现平衡（因为你无法改变子串之外的字符，比如QQQ[QWERR]，子串QWERR之外的字符中Q出现了三次大于2，则你无论如何改变子串都无法实现平衡；反之，如果是这样的QQR[QWERR]，则可以将子串改变为[WWERE]&#x3D;&gt;QQRWWERE,便实现了平衡）。<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">balancedString</span><span class="params">(s <span class="type">string</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    counter := <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">byte</span>]<span class="type">int</span>, <span class="number">0</span>)</span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i&lt;<span class="built_in">len</span>(s); i++ &#123;</span><br><span class="line">        counter[s[i]]++</span><br><span class="line">    &#125;</span><br><span class="line">    left := <span class="number">0</span></span><br><span class="line">    m := <span class="built_in">len</span>(s)/<span class="number">4</span></span><br><span class="line">    min := math.MaxInt <span class="comment">// 其实这个只是定义一个最大值</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 如果WQER四个字符的个数恰好是m，则说明已经是平衡字符串了</span></span><br><span class="line">    <span class="keyword">if</span> counter[<span class="string">&#x27;Q&#x27;</span>] == m &amp;&amp;</span><br><span class="line">        counter[<span class="string">&#x27;W&#x27;</span>] == m &amp;&amp;</span><br><span class="line">          counter[<span class="string">&#x27;E&#x27;</span>] == m &amp;&amp;</span><br><span class="line">            counter[<span class="string">&#x27;R&#x27;</span>] == m &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> right:=<span class="number">0</span>; right&lt;<span class="built_in">len</span>(s); right++ &#123;</span><br><span class="line">        <span class="comment">// 属于子串范围的就应该减去</span></span><br><span class="line">        counter[s[right]]--</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> counter[<span class="string">&#x27;Q&#x27;</span>] &lt;= m &amp;&amp;</span><br><span class="line">                counter[<span class="string">&#x27;W&#x27;</span>] &lt;= m &amp;&amp;</span><br><span class="line">                    counter[<span class="string">&#x27;E&#x27;</span>] &lt;= m &amp;&amp;</span><br><span class="line">                        counter[<span class="string">&#x27;R&#x27;</span>] &lt;= m &#123;</span><br><span class="line">            <span class="keyword">if</span> right-left+<span class="number">1</span> &lt; min &#123;</span><br><span class="line">                min = right-left+<span class="number">1</span></span><br><span class="line">            &#125;</span><br><span class="line">            counter[s[left]]++ <span class="comment">// 移除了子串的范围就应该放到其他的里面， counter始终是维护子串之外的数据</span></span><br><span class="line">            left++</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> min</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h5 id="将X减到0的最小操作数"><a href="#将X减到0的最小操作数" class="headerlink" title="将X减到0的最小操作数"></a>将X减到0的最小操作数</h5><ul><li>其实这一题和上面：<a href="https://leetcode.cn/problems/minimum-size-subarray-sum/submissions/">力扣-209-长度最小的子数组</a>是一模一样的， 可以理解为和为allSum-x的最小子串，稍微变了一下而已<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">minOperations</span><span class="params">(nums []<span class="type">int</span>, x <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    left := <span class="number">0</span></span><br><span class="line">    min := math.MaxInt</span><br><span class="line">    sum := <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    allSum := <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> _, v := <span class="keyword">range</span> nums &#123;</span><br><span class="line">        allSum = allSum + v</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 总和小于指定的值，肯定不符合</span></span><br><span class="line">    <span class="keyword">if</span> allSum &lt; x &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 其实这一题可以转变一个思路，就是求满足子串总和=allSum-x的最小子串</span></span><br><span class="line">    otherSum := allSum - x</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> right:=<span class="number">0</span>; right&lt;<span class="built_in">len</span>(nums); right++ &#123;</span><br><span class="line">        sum = sum + nums[right]</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> sum &gt; otherSum &#123;</span><br><span class="line">            sum = sum - nums[left]</span><br><span class="line">            left++</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> sum == otherSum &#123;</span><br><span class="line">            subNumsLen := right-left+<span class="number">1</span></span><br><span class="line">            otherNumerLen := <span class="built_in">len</span>(nums) - subNumsLen</span><br><span class="line">            <span class="keyword">if</span> otherNumerLen &lt; min &#123;</span><br><span class="line">                min = otherNumerLen</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> min == math.MaxInt &#123;</span><br><span class="line">        min = <span class="number">-1</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> min</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h4 id=&quot;题目大纲&quot;&gt;&lt;a href=&quot;#题目大纲&quot; class=&quot;headerlink&quot; title=&quot;题目大纲&quot;&gt;&lt;/a&gt;题目大纲&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/minimum-size-subarray-su
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="双指针" scheme="http://www.zhangfuguan.top/tags/%E5%8F%8C%E6%8C%87%E9%92%88/"/>
    
  </entry>
  
  <entry>
    <title>go适配器模式</title>
    <link href="http://www.zhangfuguan.top/2023/06/02/go%E9%80%82%E9%85%8D%E5%99%A8%E6%A8%A1%E5%BC%8F/"/>
    <id>http://www.zhangfuguan.top/2023/06/02/go适配器模式/</id>
    <published>2023-06-02T15:53:20.000Z</published>
    <updated>2023-12-18T16:15:50.549Z</updated>
    
    <content type="html"><![CDATA[<p>适配器模式是一种结构型设计模式，它允许具有不兼容接口的对象进行协作。这种模式通常用于以下情况：</p><ol><li>当你想使用某个现有类，但其接口与你的代码不兼容时。</li><li>当你想重用多个现有子类，但它们缺少一些无法添加到超类中的通用功能时。<br>适配器模式的解决方案是创建一个适配器类，它充当你的代码和遗留类、第三方类或任何其他具有奇怪接口的类之间的翻译器。适配器包装了一个对象，隐藏了其背后的转换复杂性。被包装的对象甚至不知道适配器的存在。</li></ol><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">a := NewAdapter()</span><br><span class="line">a.Pay(<span class="string">&quot;张三&quot;</span>, <span class="number">12</span>, <span class="string">&quot;aliyun&quot;</span>)</span><br><span class="line">a.Pay(<span class="string">&quot;李四&quot;</span>, <span class="number">200</span>, <span class="string">&quot;wx&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> AliyunPayInterface <span class="keyword">interface</span> &#123;</span><br><span class="line">Pay(name <span class="type">string</span>, payment <span class="type">float64</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> AliyunPay <span class="keyword">struct</span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(a AliyunPay)</span></span> Pay(name <span class="type">string</span>, payment <span class="type">float64</span>) &#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;用户【%s】支付宝支付金额【%f】元 \n&quot;</span>, name, payment)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> WxPayInterface <span class="keyword">interface</span> &#123;</span><br><span class="line">Pay(name <span class="type">string</span>, payment <span class="type">float64</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">type</span> WxPay <span class="keyword">struct</span> &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(w WxPay)</span></span> Pay(name <span class="type">string</span>, payment <span class="type">float64</span>) &#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;用户【%s】微信支付金额【%f】元 \n&quot;</span>, name, payment)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Apadter <span class="keyword">struct</span> &#123;</span><br><span class="line">AliyunPayInterface</span><br><span class="line">WxPayInterface</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(a Apadter)</span></span> Pay(name <span class="type">string</span>, payment <span class="type">float64</span>, channel <span class="type">string</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> channel == <span class="string">&quot;aliyun&quot;</span> &#123;</span><br><span class="line">a.AliyunPayInterface.Pay(name, payment)</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> channel == <span class="string">&quot;wx&quot;</span> &#123;</span><br><span class="line">a.WxPayInterface.Pay(name, payment)</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;不支持的支付渠道&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewAdapter</span><span class="params">()</span></span> Apadter &#123;</span><br><span class="line"><span class="keyword">return</span> Apadter&#123;</span><br><span class="line">AliyunPay&#123;&#125;,</span><br><span class="line">WxPay&#123;&#125;,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;适配器模式是一种结构型设计模式，它允许具有不兼容接口的对象进行协作。这种模式通常用于以下情况：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当你想使用某个现有类，但其接口与你的代码不兼容时。&lt;/li&gt;
&lt;li&gt;当你想重用多个现有子类，但它们缺少一些无法添加到超类中的通用功能时。&lt;br&gt;适配器
      
    
    </summary>
    
    
      <category term="go" scheme="http://www.zhangfuguan.top/tags/go/"/>
    
      <category term="设计模式" scheme="http://www.zhangfuguan.top/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>go观察者模式</title>
    <link href="http://www.zhangfuguan.top/2023/06/02/go%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F/"/>
    <id>http://www.zhangfuguan.top/2023/06/02/go观察者模式/</id>
    <published>2023-06-02T15:50:53.000Z</published>
    <updated>2023-06-02T15:52:50.349Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">sub := NewSubject(<span class="string">&quot;东北&quot;</span>)</span><br><span class="line">sub.Register(Observer&#123;</span><br><span class="line">Uid:  <span class="number">123</span>,</span><br><span class="line">Name: <span class="string">&quot;张三&quot;</span>,</span><br><span class="line">&#125;)</span><br><span class="line">sub.Register(Observer&#123;</span><br><span class="line">Uid:  <span class="number">124</span>,</span><br><span class="line">Name: <span class="string">&quot;李四&quot;</span>,</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">sub.NotifyAll()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ObserverInterface 观察者</span></span><br><span class="line"><span class="keyword">type</span> ObserverInterface <span class="keyword">interface</span> &#123;</span><br><span class="line">Notify()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Observer 具体观察者</span></span><br><span class="line"><span class="keyword">type</span> Observer <span class="keyword">struct</span> &#123;</span><br><span class="line">Uid  <span class="type">int32</span></span><br><span class="line">Name <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(o Observer)</span></span> Notify() &#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;观察者【%d】：%s \n&quot;</span>, o.Uid, o.Name)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// SubjectInterface 主体，也就是观察者模式的主体</span></span><br><span class="line"><span class="keyword">type</span> SubjectInterface <span class="keyword">interface</span> &#123;</span><br><span class="line">Register(o ObserverInterface)</span><br><span class="line">Deregister(o ObserverInterface)</span><br><span class="line">NotifyAll()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Subject <span class="keyword">struct</span> &#123;</span><br><span class="line">observerMap <span class="keyword">map</span>[<span class="type">int32</span>]Observer</span><br><span class="line">name        <span class="type">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewSubject</span><span class="params">(name <span class="type">string</span>)</span></span> *Subject &#123;</span><br><span class="line"><span class="keyword">return</span> &amp;Subject&#123;</span><br><span class="line">name:        name,</span><br><span class="line">observerMap: <span class="keyword">map</span>[<span class="type">int32</span>]Observer&#123;&#125;,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(s *Subject)</span></span> Register(o Observer) &#123;</span><br><span class="line"><span class="keyword">if</span> _, ok := s.observerMap[o.Uid]; ok &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">s.observerMap[o.Uid] = o</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(s *Subject)</span></span> Deregister(o Observer) &#123;</span><br><span class="line"><span class="keyword">if</span> _, ok := s.observerMap[o.Uid]; !ok &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">delete</span>(s.observerMap, o.Uid)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(s *Subject)</span></span> NotifyAll() &#123;</span><br><span class="line"><span class="keyword">for</span> _, o := <span class="keyword">range</span> s.observerMap &#123;</span><br><span class="line">o.Notify()</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;figure class=&quot;highlight go&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;l
      
    
    </summary>
    
    
      <category term="go" scheme="http://www.zhangfuguan.top/tags/go/"/>
    
      <category term="设计模式" scheme="http://www.zhangfuguan.top/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"/>
    
  </entry>
  
  <entry>
    <title>dfs之查找二叉树最大深度</title>
    <link href="http://www.zhangfuguan.top/2023/06/01/dfs%E4%B9%8B%E6%9F%A5%E6%89%BE%E4%BA%8C%E5%8F%89%E6%A0%91%E6%9C%80%E5%A4%A7%E6%B7%B1%E5%BA%A6/"/>
    <id>http://www.zhangfuguan.top/2023/06/01/dfs之查找二叉树最大深度/</id>
    <published>2023-06-01T15:47:21.000Z</published>
    <updated>2023-06-23T11:05:04.474Z</updated>
    
    <content type="html"><![CDATA[<p>传送到leetcode: <a href="https://leetcode.cn/problems/maximum-depth-of-binary-tree/">leetcode-104</a></p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Definition for a binary tree node.</span></span><br><span class="line"><span class="comment"> * type TreeNode struct &#123;</span></span><br><span class="line"><span class="comment"> *     Val int</span></span><br><span class="line"><span class="comment"> *     Left *TreeNode</span></span><br><span class="line"><span class="comment"> *     Right *TreeNode</span></span><br><span class="line"><span class="comment"> * &#125;</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">// dfs实现</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">maxDepth</span><span class="params">(root *TreeNode)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    max := <span class="number">0</span></span><br><span class="line">    startDeep := <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> dfs <span class="function"><span class="keyword">func</span><span class="params">(node *TreeNode, startDeep <span class="type">int</span>)</span></span></span><br><span class="line">    dfs = <span class="function"><span class="keyword">func</span><span class="params">(node *TreeNode, startDeep <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line">            <span class="keyword">return</span></span><br><span class="line">        &#125;</span><br><span class="line">        startDeep = startDeep + <span class="number">1</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> node.Left == <span class="literal">nil</span> &amp;&amp; node.Right == <span class="literal">nil</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> startDeep &gt; max &#123;</span><br><span class="line">                max = startDeep</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        dfs(node.Left, startDeep)</span><br><span class="line">        dfs(node.Right, startDeep)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    dfs(root, startDeep)</span><br><span class="line">    <span class="keyword">return</span> max</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;传送到leetcode: &lt;a href=&quot;https://leetcode.cn/problems/maximum-depth-of-binary-tree/&quot;&gt;leetcode-104&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight go&quot;&gt;&lt;tabl
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="dfs" scheme="http://www.zhangfuguan.top/tags/dfs/"/>
    
  </entry>
  
  <entry>
    <title>go实现lru</title>
    <link href="http://www.zhangfuguan.top/2023/05/31/go%E5%AE%9E%E7%8E%B0lru/"/>
    <id>http://www.zhangfuguan.top/2023/05/31/go实现lru/</id>
    <published>2023-05-31T14:25:23.000Z</published>
    <updated>2023-05-31T14:37:00.166Z</updated>
    
    <content type="html"><![CDATA[<p>原理：定义lru结构的时候主要包含一个哈希表和双向链表，哈希表便于获取指定key的数据（复杂度O(1)），把每次热点数据都更新到表头，则从表头到表尾访问热度依次递减，溢出的时候直接删除表尾数据即可。</p><p><img src="/2023/05/31/go%E5%AE%9E%E7%8E%B0lru/6081685543618_.pic.jpg" alt="lru"></p><p>go代码实现：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;log&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">log.Print(<span class="string">&quot;zlru...&quot;</span>)</span><br><span class="line"></span><br><span class="line">l := NewLruCache(<span class="number">5</span>)</span><br><span class="line">l.Put(<span class="number">1</span>, <span class="number">11</span>)</span><br><span class="line">l.Put(<span class="number">2</span>, <span class="number">22</span>)</span><br><span class="line">l.Put(<span class="number">3</span>, <span class="number">33</span>)</span><br><span class="line">l.Put(<span class="number">4</span>, <span class="number">44</span>)</span><br><span class="line">l.Put(<span class="number">5</span>, <span class="number">55</span>)</span><br><span class="line"></span><br><span class="line">log.Println(<span class="string">&quot;case1-------------------------------&gt;&quot;</span>)</span><br><span class="line">log.Printf(<span class="string">&quot;head: %+v&quot;</span>, l.list.head)</span><br><span class="line">log.Printf(<span class="string">&quot;tail: %+v&quot;</span>, l.list.tail)</span><br><span class="line">log.Printf(<span class="string">&quot;len: %d&quot;</span>, l.size)</span><br><span class="line">l.list.Range()</span><br><span class="line"></span><br><span class="line">log.Println(<span class="string">&quot;case2-------------------------------&gt;&quot;</span>)</span><br><span class="line">l.Put(<span class="number">6</span>, <span class="number">66</span>)</span><br><span class="line">log.Printf(<span class="string">&quot;head: %+v&quot;</span>, l.list.head)</span><br><span class="line">log.Printf(<span class="string">&quot;tail: %+v&quot;</span>, l.list.tail)</span><br><span class="line">log.Printf(<span class="string">&quot;len: %d&quot;</span>, l.size)</span><br><span class="line">l.list.Range()</span><br><span class="line"></span><br><span class="line">log.Println(<span class="string">&quot;case3-------------------------------&gt;&quot;</span>)</span><br><span class="line">l.Get(<span class="number">3</span>)</span><br><span class="line">log.Printf(<span class="string">&quot;head: %+v&quot;</span>, l.list.head)</span><br><span class="line">log.Printf(<span class="string">&quot;tail: %+v&quot;</span>, l.list.tail)</span><br><span class="line">log.Printf(<span class="string">&quot;len: %d&quot;</span>, l.size)</span><br><span class="line">l.list.Range()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(l *linkList)</span></span> Range() &#123;</span><br><span class="line"><span class="keyword">for</span> node := l.head; node != <span class="literal">nil</span>; node = node.next &#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;key: %d, value: %d \n&quot;</span>, node.key, node.value)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 双向链表节点</span></span><br><span class="line"><span class="keyword">type</span> linkNode <span class="keyword">struct</span> &#123;</span><br><span class="line">key   <span class="type">int</span></span><br><span class="line">value <span class="type">int</span></span><br><span class="line">prev  *linkNode</span><br><span class="line">next  *linkNode</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 双向链表</span></span><br><span class="line"><span class="keyword">type</span> linkList <span class="keyword">struct</span> &#123;</span><br><span class="line">head *linkNode</span><br><span class="line">tail *linkNode</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// lru缓存结构</span></span><br><span class="line"><span class="keyword">type</span> lruCache <span class="keyword">struct</span> &#123;</span><br><span class="line"><span class="built_in">cap</span>      <span class="type">int</span></span><br><span class="line">size     <span class="type">int</span></span><br><span class="line">cacheMap <span class="keyword">map</span>[<span class="type">int</span>]*linkNode</span><br><span class="line">list     *linkList</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">newNode</span><span class="params">(k, v <span class="type">int</span>)</span></span> *linkNode &#123;</span><br><span class="line"><span class="keyword">return</span> &amp;linkNode&#123;</span><br><span class="line">key:   k,</span><br><span class="line">value: k,</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// NewLruCache 初始化一个新的lru</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">NewLruCache</span><span class="params">(<span class="built_in">cap</span> <span class="type">int</span>)</span></span> *lruCache &#123;</span><br><span class="line">l := &amp;lruCache&#123;</span><br><span class="line"><span class="built_in">cap</span>:  <span class="built_in">cap</span>,</span><br><span class="line">size: <span class="number">0</span>,</span><br><span class="line">&#125;</span><br><span class="line">l.cacheMap = <span class="built_in">make</span>(<span class="keyword">map</span>[<span class="type">int</span>]*linkNode, <span class="number">0</span>)</span><br><span class="line">l.list = &amp;linkList&#123;</span><br><span class="line">head: <span class="literal">nil</span>,</span><br><span class="line">tail: <span class="literal">nil</span>,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> l</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 主要是需要实现两个操作：Get/Put</span></span><br><span class="line"><span class="comment">// Get 获取指定key的值：</span></span><br><span class="line"><span class="comment">//     1. 如果key存在，则需要将该key所在的节点：（1）从当前位置删除，（2）移动到链表头部</span></span><br><span class="line"><span class="comment">//     2. 如果不存在直接返回-1</span></span><br><span class="line"><span class="comment">// Put 新增元素：</span></span><br><span class="line"><span class="comment">//     1. 如果key存在，则需要将该key所在的节点：（1）更新当前节点的值，（2）从当前位置删除，（2）移动到链表头部</span></span><br><span class="line"><span class="comment">//     2. 如果key不存在，则需要：（1）新生成一个节点NewNode, （2）将NewNode放在链表头部，（3）链表长度加1，如果此时链表长度未超过容量cap则直接返回，（4）如果加1后的链表长度超过容量则删除链表末尾节点，删除map中的元素</span></span><br><span class="line"><span class="comment">// 其实归结下来有以下几个基础操作：</span></span><br><span class="line"><span class="comment">//  （1）删除一个已经存在的元素 （2）删除链表中末尾元素（3）将元素放在链表头部</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(l *lruCache)</span></span> removeNode(node *linkNode) &#123;</span><br><span class="line"><span class="comment">// 如果node是最后一个元素, 并且prev元素不为空</span></span><br><span class="line"><span class="keyword">if</span> node.next == <span class="literal">nil</span> &amp;&amp; node.prev != <span class="literal">nil</span> &#123;</span><br><span class="line">node.prev.next = <span class="literal">nil</span></span><br><span class="line">l.list.tail = node.prev</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果node是第一个元素, 并且next元素不为空</span></span><br><span class="line"><span class="keyword">if</span> node.prev == <span class="literal">nil</span> &amp;&amp; node.next != <span class="literal">nil</span> &#123;</span><br><span class="line">node.next.prev = <span class="literal">nil</span></span><br><span class="line">l.list.head = node.next</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果只有一个元素</span></span><br><span class="line"><span class="keyword">if</span> node.prev == <span class="literal">nil</span> &amp;&amp; node.next == <span class="literal">nil</span> &#123;</span><br><span class="line">l.list.tail = <span class="literal">nil</span></span><br><span class="line">l.list.head = <span class="literal">nil</span></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 删除中间元素</span></span><br><span class="line">node.prev.next = node.next</span><br><span class="line">node.next.prev = node.prev</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(l *lruCache)</span></span> removeTail() &#123;</span><br><span class="line"><span class="keyword">if</span> l.list.tail == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">l.removeNode(l.list.tail)</span><br><span class="line"><span class="built_in">delete</span>(l.cacheMap, l.list.tail.key)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(l *lruCache)</span></span> moveHead(node *linkNode) &#123;</span><br><span class="line"><span class="comment">// 一个元素都没有</span></span><br><span class="line"><span class="keyword">if</span> l.list.head == <span class="literal">nil</span> &#123;</span><br><span class="line">l.list.head = node</span><br><span class="line">l.list.tail = node</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">headNode := l.list.head</span><br><span class="line"><span class="comment">// 新节点的next指向头部节点</span></span><br><span class="line">node.next = headNode</span><br><span class="line"><span class="comment">// 头部节点的prev指向新节点</span></span><br><span class="line">headNode.prev = node</span><br><span class="line"><span class="comment">// 新节点的prev设置为nil</span></span><br><span class="line">node.prev = <span class="literal">nil</span></span><br><span class="line"><span class="comment">// 双向链表的头部指向新的节点</span></span><br><span class="line">l.list.head = node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(l *lruCache)</span></span> Get(key <span class="type">int</span>) <span class="type">int</span> &#123;</span><br><span class="line"><span class="comment">// 判断key是否存在</span></span><br><span class="line">node, ok := l.cacheMap[key]</span><br><span class="line"><span class="keyword">if</span> !ok &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 删除节点在之前的位置</span></span><br><span class="line">l.removeNode(node)</span><br><span class="line"><span class="comment">// 将节点移动到头部</span></span><br><span class="line">l.moveHead(node)</span><br><span class="line"><span class="keyword">return</span> node.value</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(l *lruCache)</span></span> Put(key, value <span class="type">int</span>) &#123;</span><br><span class="line"><span class="comment">// 判断节点是否存在</span></span><br><span class="line">node, ok := l.cacheMap[key]</span><br><span class="line"><span class="keyword">if</span> !ok &#123;</span><br><span class="line"><span class="comment">// 如果不存在则需要新生产一个node， 并指向链表头部</span></span><br><span class="line">newNode := newNode(key, value)</span><br><span class="line"><span class="comment">// 向cap里面新增一对k/v</span></span><br><span class="line">l.cacheMap[key] = newNode</span><br><span class="line"><span class="comment">// 将新增的node放在链表头部</span></span><br><span class="line">l.moveHead(newNode)</span><br><span class="line"><span class="comment">// 链表长度加1</span></span><br><span class="line">l.size++</span><br><span class="line"><span class="comment">// 如果长度超过容量则需要删除链表末尾元素</span></span><br><span class="line"><span class="keyword">if</span> l.size &gt; l.<span class="built_in">cap</span> &#123;</span><br><span class="line">l.removeTail()</span><br><span class="line">l.size--</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果新增元素已经存在</span></span><br><span class="line"><span class="comment">// 更新元素的值</span></span><br><span class="line">node.value = value</span><br><span class="line"><span class="comment">// 将元素从当前位置删除</span></span><br><span class="line">l.removeNode(node)</span><br><span class="line"><span class="comment">// 将元素移动到链表头部</span></span><br><span class="line">l.moveHead(node)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;原理：定义lru结构的时候主要包含一个哈希表和双向链表，哈希表便于获取指定key的数据（复杂度O(1)），把每次热点数据都更新到表头，则从表头到表尾访问热度依次递减，溢出的时候直接删除表尾数据即可。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/2023/05/31/go%E5%AE
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>go容易忽视的黑坑系列2</title>
    <link href="http://www.zhangfuguan.top/2023/05/28/go%E5%AE%B9%E6%98%93%E5%BF%BD%E8%A7%86%E7%9A%84%E9%BB%91%E5%9D%91%E7%B3%BB%E5%88%972/"/>
    <id>http://www.zhangfuguan.top/2023/05/28/go容易忽视的黑坑系列2/</id>
    <published>2023-05-28T13:15:26.000Z</published>
    <updated>2023-05-31T14:23:24.450Z</updated>
    
    <content type="html"><![CDATA[<ol><li>推断下面代码输出结果：<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">var</span> f = <span class="function"><span class="keyword">func</span><span class="params">(i <span class="type">int</span>)</span></span> &#123;</span><br><span class="line">fmt.Println(<span class="string">&quot;x&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">f := <span class="function"><span class="keyword">func</span><span class="params">(i <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="built_in">println</span>(i)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> i &gt; <span class="number">0</span> &#123;</span><br><span class="line">f(i<span class="number">-1</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">f(<span class="number">10</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>可能有同学会测试为：<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">3</span><br><span class="line">2</span><br><span class="line">1</span><br><span class="line">0</span><br></pre></td></tr></table></figure>但实际是：<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">3</span><br><span class="line">x</span><br></pre></td></tr></table></figure>这是因为main函数在构造的时候全局f函数已经构造完成，所以使用的是全局f函数。而且如果改成为我们想像的逻辑，反而会报错：<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">fi := <span class="function"><span class="keyword">func</span><span class="params">(i <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="built_in">println</span>(i)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> i &gt; <span class="number">0</span> &#123;</span><br><span class="line">fi(i<span class="number">-1</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">f(<span class="number">3</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 错误：</span></span><br><span class="line"># command-line-arguments</span><br><span class="line">./main.<span class="keyword">go</span>:<span class="number">314</span>:<span class="number">4</span>: undefined: fi</span><br></pre></td></tr></table></figure></li></ol>]]></content>
    
    <summary type="html">
    
      
      
        &lt;ol&gt;
&lt;li&gt;推断下面代码输出结果：&lt;figure class=&quot;highlight go&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/spa
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>N皇后问题</title>
    <link href="http://www.zhangfuguan.top/2023/05/28/N%E7%9A%87%E5%90%8E%E9%97%AE%E9%A2%98/"/>
    <id>http://www.zhangfuguan.top/2023/05/28/N皇后问题/</id>
    <published>2023-05-28T12:20:23.000Z</published>
    <updated>2023-05-28T12:24:20.595Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 是否冲突</span></span><br><span class="line"><span class="comment">//  0/0  0/1  0/2  0/3</span></span><br><span class="line"><span class="comment">//  1/0  1/1  1/2  1/3</span></span><br><span class="line"><span class="comment">//  2/0  2/1  2/2  2/3</span></span><br><span class="line"><span class="comment">//  3/0  3/1  3/2  3/3</span></span><br><span class="line"><span class="comment">// 1. 判断是否属于同一列</span></span><br><span class="line"><span class="comment">// 2. 判断左边斜线上是否有冲突</span></span><br><span class="line"><span class="comment">//    *</span></span><br><span class="line"><span class="comment">//      *</span></span><br><span class="line"><span class="comment">//        *</span></span><br><span class="line"><span class="comment">// 2. 判断右边斜线上是否有冲突</span></span><br><span class="line"><span class="comment">//           *</span></span><br><span class="line"><span class="comment">//          *</span></span><br><span class="line"><span class="comment">//        *</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">totalNQueens</span><span class="params">(n <span class="type">int</span>)</span></span> <span class="type">int</span> &#123;</span><br><span class="line">    <span class="comment">// 结果</span></span><br><span class="line">    res := <span class="built_in">make</span>([][]<span class="type">string</span>, <span class="number">0</span>)</span><br><span class="line">    <span class="comment">// 初始化path</span></span><br><span class="line">    path := <span class="built_in">make</span>([]<span class="type">string</span>, <span class="number">0</span>)</span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i&lt; n ; i++ &#123;</span><br><span class="line">        path = <span class="built_in">append</span>(path, strings.Repeat(<span class="string">&quot;.&quot;</span>, n))</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 从第一行开始</span></span><br><span class="line">    row := <span class="number">0</span></span><br><span class="line"></span><br><span class="line">    backtrack(row, path, &amp;res)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">len</span>(res)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">backtrack</span><span class="params">(row <span class="type">int</span>, path []<span class="type">string</span>, res *[][]<span class="type">string</span>)</span></span> &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(path) == row &#123;</span><br><span class="line">        temp := <span class="built_in">make</span>([]<span class="type">string</span>, <span class="built_in">len</span>(path))</span><br><span class="line">        <span class="built_in">copy</span>(temp, path)</span><br><span class="line">        *res = <span class="built_in">append</span>(*res, temp)</span><br><span class="line">        <span class="keyword">return</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    n := <span class="built_in">len</span>(path)</span><br><span class="line">    <span class="keyword">for</span> col := <span class="number">0</span>; col&lt;n; col++ &#123;</span><br><span class="line">        <span class="keyword">if</span> !isConflict(path, row, col) &#123;</span><br><span class="line">            <span class="keyword">continue</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        rowBytes := []<span class="type">byte</span>(path[row])</span><br><span class="line">        rowBytes[col] = <span class="string">&#x27;Q&#x27;</span></span><br><span class="line">        path[row] = <span class="type">string</span>(rowBytes)</span><br><span class="line"></span><br><span class="line">        backtrack(row+<span class="number">1</span>, path, res)</span><br><span class="line"></span><br><span class="line">        rowBytes[col] = <span class="string">&#x27;.&#x27;</span></span><br><span class="line">        path[row] = <span class="type">string</span>(rowBytes)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">isConflict</span><span class="params">(path []<span class="type">string</span>, row, col <span class="type">int</span>)</span></span> <span class="type">bool</span> &#123;</span><br><span class="line">    <span class="comment">// 同一列</span></span><br><span class="line">    n := <span class="built_in">len</span>(path)</span><br><span class="line">    <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; n; i++ &#123;</span><br><span class="line">        <span class="keyword">if</span> path[i][col] == <span class="string">&#x27;Q&#x27;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 左上方</span></span><br><span class="line">    r := row<span class="number">-1</span></span><br><span class="line">    c := col<span class="number">-1</span> </span><br><span class="line">    <span class="keyword">for</span> r &gt;= <span class="number">0</span> &amp;&amp; c &gt;= <span class="number">0</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> path[r][c] == <span class="string">&#x27;Q&#x27;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">        c = c - <span class="number">1</span></span><br><span class="line">        r = r - <span class="number">1</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 右上方</span></span><br><span class="line">    r = row<span class="number">-1</span></span><br><span class="line">    c = col+ <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> r &gt;=<span class="number">0</span> &amp;&amp; c &lt; n &#123;</span><br><span class="line">        <span class="keyword">if</span> path[r][c] == <span class="string">&#x27;Q&#x27;</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line">        c = c + <span class="number">1</span></span><br><span class="line">        r = r - <span class="number">1</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;figure class=&quot;highlight go&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;l
      
    
    </summary>
    
    
      <category term="go" scheme="http://www.zhangfuguan.top/tags/go/"/>
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="回溯" scheme="http://www.zhangfuguan.top/tags/%E5%9B%9E%E6%BA%AF/"/>
    
  </entry>
  
  <entry>
    <title>goroutine池简单实现</title>
    <link href="http://www.zhangfuguan.top/2023/05/21/goroutine%E6%B1%A0%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0/"/>
    <id>http://www.zhangfuguan.top/2023/05/21/goroutine池简单实现/</id>
    <published>2023-05-21T14:00:43.000Z</published>
    <updated>2023-05-21T14:48:34.541Z</updated>
    
    <content type="html"><![CDATA[<h3 id="不可复用的简单实现"><a href="#不可复用的简单实现" class="headerlink" title="不可复用的简单实现"></a>不可复用的简单实现</h3><p>其实就是基于有缓冲channel的特性，每创建一个goroutine就向goroutine里面发送一个数据，goroutine任务完成之后就消费一条channel里面的数据，当channel满了之后就阻塞。</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="comment">// 最多50个goroutine</span></span><br><span class="line">ch := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">struct</span>&#123;&#125;, <span class="number">100</span>)</span><br><span class="line">wg := sync.WaitGroup&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt;= <span class="number">1000</span>; i++ &#123;</span><br><span class="line">ch &lt;- <span class="keyword">struct</span>&#123;&#125;&#123;&#125;</span><br><span class="line">wg.Add(<span class="number">1</span>)</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">(num <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">wg.Done()</span><br><span class="line">&lt;-ch</span><br><span class="line">&#125;()</span><br><span class="line">DoSomething(num)</span><br><span class="line">&#125;(i)</span><br><span class="line">&#125;</span><br><span class="line">wg.Wait()</span><br><span class="line">fmt.Println(<span class="string">&quot;Done&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">DoSomething</span><span class="params">(num <span class="type">int</span>)</span></span>&#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;k....: %d \n&quot;</span>, num)</span><br><span class="line">time.Sleep(time.Second)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面方案实现简单，但缺点是会不断创建和销毁goroutine，不可服用，性能较差。</p><h3 id="可复用的pool"><a href="#可复用的pool" class="headerlink" title="可复用的pool"></a>可复用的pool</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">jobParams := <span class="built_in">make</span>([]JobParams, <span class="number">0</span>)</span><br><span class="line">jobParams = <span class="built_in">append</span>(jobParams,</span><br><span class="line">JobParams&#123; <span class="string">&quot;张三&quot;</span>, <span class="number">18</span>&#125;,</span><br><span class="line">JobParams&#123; <span class="string">&quot;李斯&quot;</span>, <span class="number">28</span>&#125;,</span><br><span class="line">JobParams&#123; <span class="string">&quot;赵武&quot;</span>, <span class="number">8</span>&#125;,</span><br><span class="line">JobParams&#123; <span class="string">&quot;王二&quot;</span>, <span class="number">1</span>&#125;,</span><br><span class="line">JobParams&#123; <span class="string">&quot;利好&quot;</span>, <span class="number">7</span>&#125;,</span><br><span class="line">JobParams&#123; <span class="string">&quot;六七&quot;</span>, <span class="number">2</span>&#125;,</span><br><span class="line">JobParams&#123; <span class="string">&quot;问候&quot;</span>, <span class="number">23</span>&#125;,</span><br><span class="line">)</span><br><span class="line">jobParamsCh := <span class="built_in">make</span>(<span class="keyword">chan</span> JobParams, <span class="number">1000</span>)</span><br><span class="line"></span><br><span class="line">wg := sync.WaitGroup&#123;&#125;</span><br><span class="line"></span><br><span class="line">wg.Add(<span class="number">1</span>)</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">defer</span> wg.Done()</span><br><span class="line">workPool(<span class="number">2</span>, jobParamsCh)</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line">wg.Add(<span class="number">1</span>)</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">defer</span> wg.Done()</span><br><span class="line"><span class="keyword">for</span> _, v := <span class="keyword">range</span> jobParams &#123;</span><br><span class="line">jobParamsCh &lt;- v</span><br><span class="line">&#125;</span><br><span class="line">&#125;()</span><br><span class="line"></span><br><span class="line">wg.Wait()</span><br><span class="line">fmt.Println(<span class="string">&quot;Done...&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">workPool</span><span class="params">(size <span class="type">int</span>, jobParamCh <span class="keyword">chan</span> JobParams)</span></span> &#123;</span><br><span class="line">wg := sync.WaitGroup&#123;&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">1</span>; i&lt;= size; i++ &#123;</span><br><span class="line">wg.Add(<span class="number">1</span>)</span><br><span class="line"><span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">defer</span> wg.Done()</span><br><span class="line"><span class="keyword">for</span> &#123;</span><br><span class="line"><span class="keyword">select</span> &#123;</span><br><span class="line"><span class="keyword">case</span> params := &lt;-jobParamCh:</span><br><span class="line">Job(params)</span><br><span class="line">time.Sleep(time.Second)</span><br><span class="line"><span class="keyword">default</span>:</span><br><span class="line">fmt.Println(<span class="string">&quot;wait...&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;()</span><br><span class="line">&#125;</span><br><span class="line">wg.Wait()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> JobParams <span class="keyword">struct</span> &#123;</span><br><span class="line">UserName <span class="type">string</span></span><br><span class="line">Age <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Job</span><span class="params">(params JobParams)</span></span> &#123;</span><br><span class="line"><span class="comment">// doSomethings for example:</span></span><br><span class="line">fmt.Printf(<span class="string">&quot;Hello, I&#x27;m %s and %d years old. \n&quot;</span>, params.UserName, params.Age)</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>其实就在在每个goroutine里面去获取需要处理的参数，然后调用对应的逻辑函数逐个处理。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;不可复用的简单实现&quot;&gt;&lt;a href=&quot;#不可复用的简单实现&quot; class=&quot;headerlink&quot; title=&quot;不可复用的简单实现&quot;&gt;&lt;/a&gt;不可复用的简单实现&lt;/h3&gt;&lt;p&gt;其实就是基于有缓冲channel的特性，每创建一个goroutine就向gorout
      
    
    </summary>
    
    
      <category term="go" scheme="http://www.zhangfuguan.top/tags/go/"/>
    
      <category term="goroutine" scheme="http://www.zhangfuguan.top/tags/goroutine/"/>
    
  </entry>
  
  <entry>
    <title>go容易忽视的黑坑系列1</title>
    <link href="http://www.zhangfuguan.top/2023/05/15/go%E5%AE%B9%E6%98%93%E5%BF%BD%E8%A7%86%E7%9A%84%E9%BB%91%E5%9D%91%E7%B3%BB%E5%88%971/"/>
    <id>http://www.zhangfuguan.top/2023/05/15/go容易忽视的黑坑系列1/</id>
    <published>2023-05-15T15:58:02.000Z</published>
    <updated>2023-05-15T16:02:42.339Z</updated>
    
    <content type="html"><![CDATA[<ol><li>先看下面代码，是否有问题。</li></ol><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">   <span class="keyword">const</span> sh = <span class="string">&quot;zhang&quot;</span></span><br><span class="line">   fmt.Println(&amp;sh, sh)</span><br><span class="line"></span><br><span class="line">   <span class="keyword">var</span> nl <span class="type">string</span> = <span class="string">&quot;san&quot;</span></span><br><span class="line">   fmt.Println(&amp;nl, nl)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>运行结果：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">☁  test_all  go run main.go</span><br><span class="line"><span class="comment"># command-line-arguments</span></span><br><span class="line">./main.go:7:14: cannot take the address of sh</span><br></pre></td></tr></table></figure><p>在go中，不同于变量是在运行时分配内存空间，常量通常会被编译器在预处理阶段直接展开，作为指令数据使用，所以常量无法寻址。</p><ol start="2"><li>单向channel关闭</li></ol><ul><li>只读channel不允许关闭</li></ul><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">ch := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">string</span>, <span class="number">1000</span>)</span><br><span class="line">ch &lt;- <span class="string">&quot;name&quot;</span></span><br><span class="line">RecvSim(ch)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">RecvSim</span><span class="params">(ch &lt;- <span class="keyword">chan</span> <span class="type">string</span>)</span></span> &#123;</span><br><span class="line">fmt.Println(&lt;-ch)</span><br><span class="line"><span class="built_in">close</span>(ch)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">☁  test_all  go run main.go</span><br><span class="line"><span class="comment"># command-line-arguments</span></span><br><span class="line">./main.go:35:7: invalid operation: close(ch) (cannot close receive-only channel)</span><br></pre></td></tr></table></figure><ul><li>只写channel可以关闭</li></ul><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span>&#123;</span><br><span class="line">ch := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">string</span>, <span class="number">1000</span>)</span><br><span class="line">SendSim(ch)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SendSim</span><span class="params">(ch <span class="keyword">chan</span> &lt;- <span class="type">string</span>)</span></span> &#123;</span><br><span class="line">ch &lt;- <span class="string">&quot;zzz...&quot;</span></span><br><span class="line"><span class="built_in">close</span>(ch)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="3"><li>判断下面代码输出的结果：<br>情况A:</li></ol><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> T <span class="keyword">struct</span> &#123;</span><br><span class="line">ls []<span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">foo</span><span class="params">(t T)</span></span> &#123;</span><br><span class="line">t.ls[<span class="number">0</span>] = <span class="number">100</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">t := T&#123;</span><br><span class="line">ls: []<span class="type">int</span>&#123;<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>&#125;,</span><br><span class="line">&#125;</span><br><span class="line">foo(t)</span><br><span class="line"></span><br><span class="line">fmt.Println(t.ls)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>正确答案是：[100,2,3]</p><p>情况B:</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> T <span class="keyword">struct</span> &#123;</span><br><span class="line">ls []<span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">foo</span><span class="params">(t T)</span></span> &#123;</span><br><span class="line">t.ls = <span class="built_in">append</span>(t.ls, <span class="number">100</span>)</span><br><span class="line">t.ls[<span class="number">0</span>] = <span class="number">1000</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">t := T&#123;</span><br><span class="line">ls: []<span class="type">int</span>&#123;<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>&#125;,</span><br><span class="line">&#125;</span><br><span class="line">foo(t)</span><br><span class="line"></span><br><span class="line">fmt.Println(t.ls)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>正确答案：[1,2,3]</p><p>函数foo参数t虽然是传传递，但是复制后的参数t的ls字段最开始指向底层的数组是公用的，所以情况A修改了第一个元素的值也会影响到原来的变量；而情况B犹豫追加了一个元素，导致函数foo的参数t底层数据进行了重新内存分配，指向了新的底层数组，所以不会影响原来的值。</p><ol start="4"><li>context.WithValue容易忽视的陷阱。</li></ol><p>查看下面的代码，说出下面代码输出的结果：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">   ctx0 := context.Background()</span><br><span class="line">   ctx := context.WithValue(ctx0, <span class="string">&quot;name&quot;</span>, <span class="string">&quot;zhangliang&quot;</span>)</span><br><span class="line">   ctx = context.WithValue(ctx0, <span class="string">&quot;age&quot;</span>, <span class="number">12</span>)</span><br><span class="line">   fmt.Println(ctx.Value(<span class="string">&quot;name&quot;</span>))</span><br><span class="line">   fmt.Println(ctx.Value(<span class="string">&quot;age&quot;</span>))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>正确结果是：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">☁  test_all  <span class="keyword">go</span> run main.<span class="keyword">go</span></span><br><span class="line">&lt;<span class="literal">nil</span>&gt;</span><br><span class="line"><span class="number">12</span></span><br></pre></td></tr></table></figure><p>这是因为每组context只允许存储一对key-value，后面的age把前面的name覆盖了。正确写法是：</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">ctx0 := context.Background()</span><br><span class="line">ctx1 := context.WithValue(ctx0, <span class="string">&quot;name&quot;</span>, <span class="string">&quot;zhangliang&quot;</span>)</span><br><span class="line">ctx2 := context.WithValue(ctx1, <span class="string">&quot;age&quot;</span>, <span class="number">12</span>)</span><br><span class="line">fmt.Println(ctx2.Value(<span class="string">&quot;name&quot;</span>))</span><br><span class="line">fmt.Println(ctx2.Value(<span class="string">&quot;age&quot;</span>))</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">☁  test_all  go run main.go</span><br><span class="line">zhangliang</span><br><span class="line">12</span><br></pre></td></tr></table></figure><p>此时的ctx2结构如下：<br><img src="/2023/05/15/go%E5%AE%B9%E6%98%93%E5%BF%BD%E8%A7%86%E7%9A%84%E9%BB%91%E5%9D%91%E7%B3%BB%E5%88%971/bO7tSIlTMeu38TUh6Qrl6S2zdLf6kxlupmIpsGnlnys.png" alt="001"></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;ol&gt;
&lt;li&gt;先看下面代码，是否有问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;figure class=&quot;highlight go&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>二叉搜索树插入于删除操作</title>
    <link href="http://www.zhangfuguan.top/2023/03/26/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E6%8F%92%E5%85%A5%E4%BA%8E%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C/"/>
    <id>http://www.zhangfuguan.top/2023/03/26/二叉搜索树插入于删除操作/</id>
    <published>2023-03-26T13:33:50.000Z</published>
    <updated>2023-05-15T15:56:03.956Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><p>二叉排序树（Binary Sarech&#x2F;Sort Tree）或者是一颗空树；或者是具有如下性质的二叉树：</p><blockquote><p>(1) 若它的左子树不空，则 <strong>左子树</strong> 上所有结点的值 <strong>均小于</strong> 它的根结点的值；<br>(2) 若它的右子树不空，则 <strong>右子树</strong> 上所有结点的值 <strong>均大于</strong> 它的根结点的值；<br>(3) 它的 <strong>左、右子树又分别为二叉排序树</strong> 。</p></blockquote><p>比如一下值: 8、3、10、1、6、14、4、7、13，构造BTS的过程如下：<br><img src="/2023/03/26/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E6%8F%92%E5%85%A5%E4%BA%8E%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C/1.jpeg"></p><h2 id="存储结构"><a href="#存储结构" class="headerlink" title="存储结构"></a>存储结构</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Node <span class="keyword">struct</span> &#123;</span><br><span class="line">    Value <span class="type">string</span></span><br><span class="line">    Left *Node</span><br><span class="line">    Right *Node</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="查找"><a href="#查找" class="headerlink" title="查找"></a>查找</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// SearchBST 这里假设值都是int，不做异常预期判断了，咱们就简单理解算法即可</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SearchBST</span><span class="params">(targetNode *Node,value <span class="type">int</span>)</span></span> *Node &#123;</span><br><span class="line"><span class="comment">// 如果根节点为nil， 则肯定不存在</span></span><br><span class="line"><span class="keyword">if</span> targetNode ==  <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> value == targetNode.Value.(<span class="type">int</span>)  &#123;</span><br><span class="line"><span class="keyword">return</span> targetNode</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> value &lt; targetNode.Value.(<span class="type">int</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> SearchBST(targetNode.Left, value)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> value &gt; targetNode.Value.(<span class="type">int</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> SearchBST(targetNode.Right, value)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="插入"><a href="#插入" class="headerlink" title="插入"></a>插入</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">InsertBST</span><span class="params">(targetNode *Node, value <span class="type">int</span>)</span></span> &#123;</span><br><span class="line"><span class="keyword">if</span> targetNode == <span class="literal">nil</span> &#123;</span><br><span class="line">targetNode.Value = value</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> targetNode.Value.(<span class="type">int</span>) == value &#123;</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> value &lt; targetNode.Value.(<span class="type">int</span>) &#123;</span><br><span class="line"><span class="comment">// 如果当前节点不存在左子树，则将该目标节点作为当前节点的左子树</span></span><br><span class="line"><span class="keyword">if</span> targetNode.Left == <span class="literal">nil</span> &#123;</span><br><span class="line">targetNode.Left = &amp;Node&#123;</span><br><span class="line">Value: value,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">InsertBST(targetNode.Left, value)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> value &gt; targetNode.Value.(<span class="type">int</span>) &#123;</span><br><span class="line"><span class="comment">// 如果当前节点不存在右子树，则将该目标节点作为当前节点的右子树</span></span><br><span class="line"><span class="keyword">if</span> targetNode.Right == <span class="literal">nil</span> &#123;</span><br><span class="line">targetNode.Right = &amp;Node&#123;</span><br><span class="line">Value: value,</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line">InsertBST(targetNode.Right, value)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h2><p>删除二叉搜索树的节点相对而言复杂一点，如果待删除的节点同时包含左右子树，删除后如何恢复搜索树是一个问题。<br><img src="/2023/03/26/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E6%8F%92%E5%85%A5%E4%BA%8E%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C/3.jpeg"><br>比如删除节点8， 那么是选举3作为根节点还是10呢？所以就需要我们一点点去梳理：</p><ol><li>如果删除的节点是叶子结点（即没有左右子树），那么直接删除即可，比如上面的1、7、9、13.</li><li>如果删除的节点只有左子树或者只有右子树，则删除后将子节点直接指向删除节点的位置即可，比如6、14</li><li>还有一种情况就是同时存在左右子树的情况，比如8，为了维持删除后的树依然符合二叉搜索树特性，其实可以将左子树的最大值或者右子树的最小值转移到删除点位置比如将7放在8的位置，但是这里的7是叶子结点，直接删除即可，如果7还包含左右子树，其实可以递归删除替换即可。我们可以用一个比较大的BST来举例：<br><img src="/2023/03/26/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E6%8F%92%E5%85%A5%E4%BA%8E%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C/2.jpeg"><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">DeleteBST</span><span class="params">(node *Node, value <span class="type">int</span>)</span></span> *Node &#123;</span><br><span class="line"><span class="comment">// 如果二叉搜索树为nil，则直接返回</span></span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果当前节点的值等于待删除值</span></span><br><span class="line"><span class="keyword">if</span> node.Value == value &#123;</span><br><span class="line"><span class="comment">// 如果当前节点没有左右子树，则直接删除</span></span><br><span class="line"><span class="keyword">if</span> node.Left == <span class="literal">nil</span> &amp;&amp; node.Right == <span class="literal">nil</span> &#123;</span><br><span class="line">node = <span class="literal">nil</span></span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 只有右边子树，直接用右子树覆盖</span></span><br><span class="line"><span class="keyword">if</span> node.Left == <span class="literal">nil</span> &#123;</span><br><span class="line">node = node.Right</span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 只有左子树，直接用左子树覆盖</span></span><br><span class="line"><span class="keyword">if</span> node.Right == <span class="literal">nil</span> &#123;</span><br><span class="line">node = node.Left</span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> node.Left != <span class="literal">nil</span> &amp;&amp; node.Right != <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="comment">// 找到左子树中最大值，将其设置为当前的值</span></span><br><span class="line">maxInLeft := FindMaxInNodeBST(node.Left)</span><br><span class="line">node.Value = maxInLeft.Value</span><br><span class="line">node.Left = DeleteBST(node.Left, maxInLeft.Value.(<span class="type">int</span>))</span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 有左子树，并且当前节点的值小于目标值，则进入左子树递归查找删除</span></span><br><span class="line"><span class="keyword">if</span> node.Left != <span class="literal">nil</span> &amp;&amp; value &lt; node.Value.(<span class="type">int</span>)  &#123;</span><br><span class="line">node.Left =  DeleteBST(node.Left, value)</span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 有右子树，并且当前节点的值大于目标值，则进入右子树递归查找删除</span></span><br><span class="line"><span class="keyword">if</span> node.Right != <span class="literal">nil</span> &amp;&amp; value &gt; node.Value.(<span class="type">int</span>) &#123;</span><br><span class="line">node.Right = DeleteBST(node.Right, value)</span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">FindMaxInNodeBST</span><span class="params">(node *Node)</span></span> *Node &#123;</span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 树中的最大值肯定在根节点或者右子树中</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 如果左右子树都为空，则就是当前节点</span></span><br><span class="line"><span class="keyword">if</span> node.Left == <span class="literal">nil</span> &amp;&amp; node.Right == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> node</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ol>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;概念&quot;&gt;&lt;a href=&quot;#概念&quot; class=&quot;headerlink&quot; title=&quot;概念&quot;&gt;&lt;/a&gt;概念&lt;/h2&gt;&lt;p&gt;二叉排序树（Binary Sarech&amp;#x2F;Sort Tree）或者是一颗空树；或者是具有如下性质的二叉树：&lt;/p&gt;
&lt;blockqu
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="二叉树" scheme="http://www.zhangfuguan.top/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
    
  </entry>
  
  <entry>
    <title>二叉树遍历</title>
    <link href="http://www.zhangfuguan.top/2023/03/25/%E4%BA%8C%E5%8F%89%E6%A0%91%E9%81%8D%E5%8E%86/"/>
    <id>http://www.zhangfuguan.top/2023/03/25/二叉树遍历/</id>
    <published>2023-03-24T16:16:01.000Z</published>
    <updated>2023-03-24T16:24:12.184Z</updated>
    
    <content type="html"><![CDATA[<h2 id="方式"><a href="#方式" class="headerlink" title="方式"></a>方式</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><ul><li>前序遍历：递归遍历根-&gt;左-&gt;右</li><li>中序遍历：递归遍历左-&gt;根-&gt;右</li><li>后续遍历：递归遍历左-&gt;右-&gt;中</li><li>层序遍历：由根节点开始一层层的遍历</li></ul><p>其实前序遍历、中序遍历、后序遍历里面的前、中、后指的是根结点的位置。以下面这棵树来举例说明。<br><img src="/2023/03/25/%E4%BA%8C%E5%8F%89%E6%A0%91%E9%81%8D%E5%8E%86/yuque_mind.jpeg"></p><h3 id="存储结构"><a href="#存储结构" class="headerlink" title="存储结构"></a>存储结构</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">type</span> Node <span class="keyword">struct</span> &#123;</span><br><span class="line">    Value <span class="type">string</span></span><br><span class="line">    Left *Node</span><br><span class="line">    Right *Node</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="前序遍历"><a href="#前序遍历" class="headerlink" title="前序遍历"></a>前序遍历</h2><p>前序遍历要求先遍历根节点，然后遍历左子树，左后便利右子树。注意这里指的是【子树】不是孩子。所以遍历顺序为：<br>A,B,D,H,I,E,J,C,F,K,G</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">PreRange</span><span class="params">(node *Node)</span></span> []<span class="type">string</span>  &#123;</span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">list := <span class="built_in">make</span>([]<span class="type">string</span>, <span class="number">0</span>)</span><br><span class="line">list = <span class="built_in">append</span>(list, node.Value)</span><br><span class="line"></span><br><span class="line">leftList := PreRange(node.Left)</span><br><span class="line"><span class="keyword">if</span> leftList != <span class="literal">nil</span> &#123;</span><br><span class="line">list = <span class="built_in">append</span>(list, leftList...)</span><br><span class="line">&#125;</span><br><span class="line">rightList := PreRange(node.Right)</span><br><span class="line"><span class="keyword">if</span> rightList != <span class="literal">nil</span> &#123;</span><br><span class="line">list = <span class="built_in">append</span>(list, rightList...)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> list</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="中序遍历"><a href="#中序遍历" class="headerlink" title="中序遍历"></a>中序遍历</h2><p>中序遍历要求先遍历左子树，然后遍历根节点，最后遍历右子树。所以顺序为：<br>H,D,I,B,E,J,A,F,K,C,G</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">MidRange</span><span class="params">(node *Node)</span></span> []<span class="type">string</span> &#123;</span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">list := <span class="built_in">make</span>([]<span class="type">string</span>,<span class="number">0</span>)</span><br><span class="line">leftList := MidRange(node.Left)</span><br><span class="line"><span class="keyword">if</span> leftList != <span class="literal">nil</span> &#123;</span><br><span class="line">list = <span class="built_in">append</span>(list, leftList...)</span><br><span class="line">&#125;</span><br><span class="line">list = <span class="built_in">append</span>(list, node.Value)</span><br><span class="line">rightList := MidRange(node.Right)</span><br><span class="line"><span class="keyword">if</span> rightList != <span class="literal">nil</span> &#123;</span><br><span class="line">list = <span class="built_in">append</span>(list, rightList...)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> list</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="后续遍历"><a href="#后续遍历" class="headerlink" title="后续遍历"></a>后续遍历</h2><p>后序遍历要求先遍历左子树，然后遍历右子树，最后遍历根节点。所以顺序为：<br>H,I,D,J,E,B,K,F,G,C,A</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SufRange</span><span class="params">(node *Node)</span></span> []<span class="type">string</span> &#123;</span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line">list := <span class="built_in">make</span>([]<span class="type">string</span>,<span class="number">0</span>)</span><br><span class="line">leftList := SufRange(node.Left)</span><br><span class="line"><span class="keyword">if</span> leftList != <span class="literal">nil</span> &#123;</span><br><span class="line">list = <span class="built_in">append</span>(list, leftList...)</span><br><span class="line">&#125;</span><br><span class="line">rightList := SufRange(node.Right)</span><br><span class="line"><span class="keyword">if</span> rightList != <span class="literal">nil</span> &#123;</span><br><span class="line">list = <span class="built_in">append</span>(list, rightList...)</span><br><span class="line">&#125;</span><br><span class="line">list = <span class="built_in">append</span>(list, node.Value)</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> list</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="层序遍历"><a href="#层序遍历" class="headerlink" title="层序遍历"></a>层序遍历</h2><p>层序遍历其实就是从根节点开始从左到右一层层开始遍历所有节点， 所以顺序为：<br>A,B,C,D,E,F,G,H,I,J,K</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">LevelTraversal</span><span class="params">(node *Node)</span></span> []<span class="type">string</span> &#123;</span><br><span class="line"><span class="keyword">if</span> node == <span class="literal">nil</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">nodeList := <span class="built_in">make</span>([]*Node, <span class="number">0</span>)</span><br><span class="line">nodeList = <span class="built_in">append</span>(nodeList, node)</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> RecursionTraversal(nodeList)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">RecursionTraversal</span><span class="params">(nodeList []*Node)</span></span> []<span class="type">string</span> &#123;</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(nodeList) == <span class="number">0</span> &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">nil</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">list := <span class="built_in">make</span>([]<span class="type">string</span>,<span class="number">0</span>)</span><br><span class="line">nextNodeList := <span class="built_in">make</span>([]*Node, <span class="number">0</span>)</span><br><span class="line"><span class="keyword">for</span> _, node := <span class="keyword">range</span> nodeList &#123;</span><br><span class="line">list = <span class="built_in">append</span>(list, node.Value)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> node.Left != <span class="literal">nil</span> &#123;</span><br><span class="line">nextNodeList = <span class="built_in">append</span>(nextNodeList, node.Left)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> node.Right != <span class="literal">nil</span> &#123;</span><br><span class="line">nextNodeList =<span class="built_in">append</span>(nextNodeList, node.Right)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span>(nextNodeList) &gt; <span class="number">0</span> &#123;</span><br><span class="line">s := RecursionTraversal(nextNodeList)</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">len</span>(s) &gt; <span class="number">0</span> &#123;</span><br><span class="line"> list = <span class="built_in">append</span>(list, s...)</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> list</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;方式&quot;&gt;&lt;a href=&quot;#方式&quot; class=&quot;headerlink&quot; title=&quot;方式&quot;&gt;&lt;/a&gt;方式&lt;/h2&gt;&lt;h3 id=&quot;概念&quot;&gt;&lt;a href=&quot;#概念&quot; class=&quot;headerlink&quot; title=&quot;概念&quot;&gt;&lt;/a&gt;概念&lt;/h3&gt;&lt;ul&gt;
&lt;
      
    
    </summary>
    
    
      <category term="算法" scheme="http://www.zhangfuguan.top/tags/%E7%AE%97%E6%B3%95/"/>
    
      <category term="二叉树" scheme="http://www.zhangfuguan.top/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/"/>
    
  </entry>
  
  <entry>
    <title>分布式锁方案对比</title>
    <link href="http://www.zhangfuguan.top/2023/03/03/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E6%96%B9%E6%A1%88%E5%AF%B9%E6%AF%94/"/>
    <id>http://www.zhangfuguan.top/2023/03/03/分布式锁方案对比/</id>
    <published>2023-03-02T16:15:58.000Z</published>
    <updated>2023-03-08T15:28:32.184Z</updated>
    
    <content type="html"><![CDATA[<h1 id="分布式锁"><a href="#分布式锁" class="headerlink" title="分布式锁"></a>分布式锁</h1><p>当我们对一份数据进行修改的时候需要先读取，再修改，由于读取和修改不是原子操作，在并发的情况下，无法保证前后数据是一致的，在单点服务中我们可以使用本地锁来实现（比如：sync.Mutex），但是对于分布式系统服务，本地锁却无能为力。这时候就需要使用分布式锁来保证数据的一致性。</p><p><img src="/2023/03/03/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E6%96%B9%E6%A1%88%E5%AF%B9%E6%AF%94/iOLsHtH8yF9PIkHbVzQntyxXNNzV7__KSfDDXUZftsk.png" alt="image"></p><p>很多应用场景是需要系统保证幂等性的（如api服务或消息消费者），并发情况下或消息重复很容易造成系统重入，那么分布式锁是保障幂等的一个重要手段。还有一种场景就是商城做抢购活动、司机抢单等场景需要使用分布式锁来防止出现“超卖”现象。</p><h3 id="实现方案"><a href="#实现方案" class="headerlink" title="实现方案"></a>实现方案</h3><ul><li>基于数据库的唯一索引</li><li>基于redis的setnx</li><li>基于zookeeper</li></ul><h3 id="基于数据库"><a href="#基于数据库" class="headerlink" title="基于数据库"></a>基于数据库</h3><h4 id="基于唯一索引"><a href="#基于唯一索引" class="headerlink" title="基于唯一索引"></a>基于唯一索引</h4><p>基于数据库的实现方式的核心思想是：在数据库中创建一个表，表中包含方法名（或者变量等）等字段，并在方法名字段上创建唯一索引，想要执行某个方法，就使用这个方法名向表中插入数据，成功插入则获取锁，执行完成后删除对应的行数据释放锁。</p><ul><li>新建一张表</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `method_lock`;</span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TABLE</span> `method_lock` (</span><br><span class="line">  `id` <span class="type">int</span>(<span class="number">11</span>) unsigned <span class="keyword">NOT</span> <span class="keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="string">&#x27;主键&#x27;</span>,</span><br><span class="line">  `method_name` <span class="type">varchar</span>(<span class="number">64</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;锁定的方法名&#x27;</span>,</span><br><span class="line">  `<span class="keyword">desc</span>` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">NOT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;备注信息&#x27;</span>,</span><br><span class="line">  `update_time` <span class="type">timestamp</span> <span class="keyword">NOT</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span> <span class="keyword">ON</span> <span class="keyword">UPDATE</span> <span class="built_in">CURRENT_TIMESTAMP</span>,</span><br><span class="line">  <span class="keyword">PRIMARY</span> KEY (`id`),</span><br><span class="line">  <span class="keyword">UNIQUE</span> KEY `uidx_method_name` (`method_name`) <span class="keyword">USING</span> BTREE</span><br><span class="line">) ENGINE<span class="operator">=</span>InnoDB AUTO_INCREMENT<span class="operator">=</span><span class="number">3</span> <span class="keyword">DEFAULT</span> CHARSET<span class="operator">=</span>utf8 COMMENT<span class="operator">=</span><span class="string">&#x27;锁定中的方法&#x27;</span>;</span><br></pre></td></tr></table></figure><p>核心就是利用唯一索引的不可重复插入的特性，来控制锁的获取是释放。</p><ul><li>想要执行某个方法，就使用这个方法名向表中插入数据：</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">INSERT</span> <span class="keyword">INTO</span> method_lock (method_name, <span class="keyword">desc</span>) <span class="keyword">VALUES</span> (<span class="string">&#x27;methodName&#x27;</span>, <span class="string">&#x27;测试的methodName&#x27;</span>);</span><br></pre></td></tr></table></figure><p>因为我们对<code>method_name</code>做了唯一性约束，这里如果有多个请求同时提交到数据库的话，数据库会保证只有一个操作可以成功，那么我们就可以认为操作成功的那个线程获得了该方法的锁，可以执行方法体内容。</p><ul><li>成功插入则获取锁，执行完成后删除对应的行数据释放锁：</li></ul><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">delete</span> <span class="keyword">from</span> method_lock <span class="keyword">where</span> method_name <span class="operator">=</span><span class="string">&#x27;methodName&#x27;</span>;</span><br></pre></td></tr></table></figure><h4 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h4><p>乐观锁在操作数据时非常乐观，认为别人不会同时修改数据。因此乐观锁不会上锁，只是在执行更新的时候判断一下在此期间别人是否修改了数据：如果别人修改了数据则放弃操作，否则执行操作。</p><p>乐观锁大多数是基于数据版本(version)的记录机制实现的。何谓数据版本号？即为数据增加一个版本标识，在基于数据库表的版本解决方案中，一般是通过为数据库表添加一个 “version”字段来实现读取出数据时，将此版本号一同读出，之后更新时，对此版本号加1。在更新过程中，会对版本号进行比较，如果是一致的，没有发生改变，则会成功执行本次操作；如果版本号不一致，则会更新失败。其实也可以为使用表的updated_at字段记录每次更新的时间戳，使用时间戳作为version字段。</p><p>乐观锁的优点比较明显，由于在检测数据冲突时并不依赖数据库本身的锁机制，不会影响请求的性能，当产生并发且并发量较小的时候只有少部分请求会失败。缺点是需要对表的设计增加额外的字段，增加了数据库的冗余，另外，当应用并发量高的时候，version值在频繁变化，则会导致大量请求失败，影响系统的可用性。数据库锁都是作用于同一行数据记录上，这就导致一个明显的缺点，在一些特殊场景，如大促、秒杀等活动开展的时候，大量的请求同时请求同一条记录的行锁（update），会对数据库产生很大的写压力。所以综合数据库乐观锁的优缺点，乐观锁比较适合并发量不高，并且写操作不频繁的场景。</p><h4 id="悲观锁"><a href="#悲观锁" class="headerlink" title="悲观锁"></a>悲观锁</h4><p>悲观锁在操作数据时比较悲观，认为别人会同时修改数据。因此操作数据时直接把数据锁住，直到操作完成后才会释放锁；上锁期间其他人不能修改数据。</p><p>要使用悲观锁，我们必须关闭mysql数据库的自动提交属性，因为MySQL默认使用autocommit模式，也就是说，当你执行一个更新操作后，MySQL会立刻将结果进行提交。set autocommit&#x3D;0;</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="operator">/</span><span class="operator">/</span><span class="number">0.</span>开始事务</span><br><span class="line"><span class="keyword">begin</span>;<span class="operator">/</span><span class="keyword">begin</span> work;<span class="operator">/</span><span class="keyword">start</span> transaction; (三者选一就可以)</span><br><span class="line"><span class="operator">/</span><span class="operator">/</span><span class="number">1.</span>查询出商品信息</span><br><span class="line"><span class="keyword">select</span> status <span class="keyword">from</span> t_goods <span class="keyword">where</span> id<span class="operator">=</span><span class="number">1</span> <span class="keyword">for</span> <span class="keyword">update</span>;</span><br><span class="line"><span class="operator">/</span><span class="operator">/</span><span class="number">2.</span>根据商品信息生成订单</span><br><span class="line"><span class="keyword">insert</span> <span class="keyword">into</span> t_orders (id,goods_id) <span class="keyword">values</span> (<span class="keyword">null</span>,<span class="number">1</span>);</span><br><span class="line"><span class="operator">/</span><span class="operator">/</span><span class="number">3.</span>修改商品status为<span class="number">2</span></span><br><span class="line"><span class="keyword">update</span> t_goods <span class="keyword">set</span> status<span class="operator">=</span><span class="number">2</span>;</span><br><span class="line"><span class="operator">/</span><span class="operator">/</span><span class="number">4.</span>提交事务</span><br><span class="line"><span class="keyword">commit</span>;<span class="operator">/</span><span class="keyword">commit</span> work;</span><br></pre></td></tr></table></figure><p>在悲观锁中，每一次行数据的访问都是独占的，只有当正在访问该行数据的请求事务提交以后，其他请求才能依次访问该数据，否则将阻塞等待锁的获取。悲观锁可以严格保证数据访问的安全。但是缺点也明显，即每次请求都会额外产生加锁的开销且未获取到锁的请求将会阻塞等待锁的获取，在高并发环境下，容易造成大量请求阻塞，影响系统可用性。另外，悲观锁使用不当还可能产生死锁的情况。</p><h4 id="缺陷"><a href="#缺陷" class="headerlink" title="缺陷"></a>缺陷</h4><ol><li>因为是基于数据库实现的，数据库的可用性和性能将直接影响分布式锁的可用性及性能，所以，数据库需要双机部署、数据同步、主备切换；  </li><li>不具备可重入的特性，因为同一个线程在释放锁之前，行数据一直存在，无法再次成功插入数据，所以，需要在表中新增一列，用于记录当前获取到锁的机器和线程信息，在再次获取锁的时候，先查询表中机器和线程信息是否和当前机器和线程相同，若相同则直接获取锁；  </li><li>没有锁失效机制，因为有可能出现成功插入数据后，服务器宕机了，对应的数据没有被删除，当服务恢复后一直获取不到锁，所以，需要在表中新增一列，用于记录失效时间，并且需要有定时任务清除这些失效的数据；  </li><li>不具备阻塞锁特性，获取不到锁直接返回失败，所以需要优化获取逻辑，循环多次去获取。  </li><li>在实施的过程中会遇到各种不同的问题，为了解决这些问题，实现方式将会越来越复杂；依赖数据库需要一定的资源开销，性能问题需要考虑。</li></ol><h3 id="基于redis的setnx"><a href="#基于redis的setnx" class="headerlink" title="基于redis的setnx"></a>基于redis的setnx</h3><ol><li>获取锁的时候，使用setnx加锁，并使用expire命令为锁添加一个超时时间，超过该时间则自动释放锁，锁的value值为一个随机生成的UUID，通过此在释放锁的时候进行判断。</li></ol><figure class="highlight plaintext"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">SETNX &#123;ResourceURI&#125; &#123;UUID&#125;</span><br><span class="line">EXPIRE &#123;ResourceURI&#125; &#123;timeout&#125; </span><br></pre></td></tr></table></figure><ol start="2"><li>释放锁的时候，通过UUID判断是不是该锁，若是该锁，则执行delete进行锁释放。</li></ol><figure class="highlight plaintext"><figcaption><span>Text</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">// 比对 value 与 标识</span><br><span class="line">if (redis.get(&quot;lock:168&quot;).equals(random_value))&#123;</span><br><span class="line">   redis.del(&quot;lock:168&quot;); //比对成功则删除</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure><h4 id="缺陷-1"><a href="#缺陷-1" class="headerlink" title="缺陷"></a>缺陷</h4><ol><li>setnx和expire操作的非原子特性会导致死锁问题。协程A执行setnx命令成功，结果运行协程A的服务发生异常重启，导致expire命令没有执行，那么就会由于锁没有设置超时时间形成死锁。</li><li>A线程拿到锁超时释放，但是A依旧在执行自己的业务逻辑，此时B线程立刻获得锁，B也开始执行。这显然是不被允许的，一般会采取加大过期时间或者添加守护线程，go中也可以使用context设置过期时间。</li><li>上述方案无法达到不可重入，即在同一个协程中多次加锁。可以在本地维护一个map，map的key为锁标识，value为加锁次数。 每次加锁的时候加1， 重新设置过期时间，每次释放锁的时候减1，当计数小于或等于1的时候执行删除操作删除</li></ol><h3 id="基于zookeeper"><a href="#基于zookeeper" class="headerlink" title="基于zookeeper"></a>基于zookeeper</h3><p>利用zookeeper的临时有序节点和wathcer机制来实现分布式锁的功能。具体实现步骤如下：</p><ol><li>创建一个目录lock</li><li>每个节点尝试获取锁时，首先在zookeeper的lock目录下创建一个znode节点，zookeeper的有序临时节点会自动根据创建先后顺序给节点编号。</li></ol><p><img src="/2023/03/03/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E6%96%B9%E6%A1%88%E5%AF%B9%E6%AF%94/Q8r39VsHbcEV13aoTmoBzcwJrtSP7XxGDm2s44df94Y.png" alt="image"></p><ol start="3"><li>判断当前服务节点创建的znode节点是最小节点。</li></ol><ul><li>如果序列号是最小的，则成功获取到锁。执行完操作后，把创建的节点给删掉。</li><li>如果不是，则监听比自己要小 1 的节点变化。直到拿到自己是最小的节点时获得锁。</li></ul><h4 id="缺陷-2"><a href="#缺陷-2" class="headerlink" title="缺陷"></a>缺陷</h4><p>虽然zookeeper具备高可用、可重入、阻塞锁特性，可解决失效死锁问题，但是因为需要频繁的创建和删除节点，性能上不如Redis方式。</p><h3 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h3><p><a href="https://xiaomi-info.github.io/2019/12/17/redis-distributed-lock/">小米技术团队-分布式锁的实现之 redis 篇</a></p><p><a href="https://www.cnblogs.com/liuqingzheng/p/11080501.html">刘清政的博客-分布式锁</a></p><p><a href="https://chai2010.cn/advanced-go-programming-book/ch6-cloud/ch6-02-lock.html#623-%E5%9F%BA%E4%BA%8E-redis-%E7%9A%84-setnx">go高级编程-分布式锁</a></p><p><a href="https://tech.meituan.com/2017/03/17/cache-about.html">美团技术团队-缓存那些事</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h1 id=&quot;分布式锁&quot;&gt;&lt;a href=&quot;#分布式锁&quot; class=&quot;headerlink&quot; title=&quot;分布式锁&quot;&gt;&lt;/a&gt;分布式锁&lt;/h1&gt;&lt;p&gt;当我们对一份数据进行修改的时候需要先读取，再修改，由于读取和修改不是原子操作，在并发的情况下，无法保证前后数据是一致的，在单
      
    
    </summary>
    
    
      <category term="go" scheme="http://www.zhangfuguan.top/tags/go/"/>
    
      <category term="微服务" scheme="http://www.zhangfuguan.top/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"/>
    
      <category term="高并发" scheme="http://www.zhangfuguan.top/tags/%E9%AB%98%E5%B9%B6%E5%8F%91/"/>
    
  </entry>
  
</feed>
