<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Clarklevis&#39; tech home</title>
  
  <subtitle>相信技术改变世界</subtitle>
  <link href="http://example.com/atom.xml" rel="self"/>
  
  <link href="http://example.com/"/>
  <updated>2021-08-28T11:25:18.436Z</updated>
  <id>http://example.com/</id>
  
  <author>
    <name>Clark Levis</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>【大疆】大疆面经</title>
    <link href="http://example.com/2021/08/28/%E3%80%90%E5%A4%A7%E7%96%86%E3%80%91%E5%A4%A7%E7%96%86%E9%9D%A2%E7%BB%8F/"/>
    <id>http://example.com/2021/08/28/%E3%80%90%E5%A4%A7%E7%96%86%E3%80%91%E5%A4%A7%E7%96%86%E9%9D%A2%E7%BB%8F/</id>
    <published>2021-08-28T11:14:54.000Z</published>
    <updated>2021-08-28T11:25:18.436Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>经验告诉大家，不管算法如何，八股文一定要背的熟熟的，另外如果在实习的话，实习相关的业务也一定要掌握的透透的，要用比较清晰的语言讲实习的任务讲明白</p></blockquote><ol><li>从Activity A中启动Activity B后，两个Activity的生命周期如何</li><li>aidl的原理是什么</li><li>binder是如何实现跨进程通信的</li><li>binder中有哪些组件</li><li>Handler用过吗？平时怎么使用Handler的</li><li>如果使用post发送一个延时任务的话，handler是怎么实现的</li><li>Java中的强软弱虚四种引用分别介绍一下，以及他们的区别</li><li>Java中的内存回收</li><li>什么对象会被视为垃圾</li><li>从Jvm的内存模型看，为什么Java会出现并发问题</li><li>两个无穷大数做加法如何实现：我回答的用String盛放两个数，或者放到数组中，然后通过遍历的方式对每一位进行相加，复杂度为O(n)</li><li>MVVM架构解释一下</li><li>MVVM中View和ViewModel的双向绑定</li><li>Android Compose主要对哪一层产生了影响</li><li>View的事件分发</li><li>View适配不同屏幕的方法</li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;经验告诉大家，不管算法如何，八股文一定要背的熟熟的，另外如果在实习的话，实习相关的业务也一定要掌握的透透的，要用比较清晰的语言讲实习的任务讲明白&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;从Activity A中启动Activity B</summary>
      
    
    
    
    
    <category term="面经" scheme="http://example.com/tags/%E9%9D%A2%E7%BB%8F/"/>
    
  </entry>
  
  <entry>
    <title>【剑指offer】45 把数组排成最小的数</title>
    <link href="http://example.com/2021/08/21/%E6%8A%8A%E6%95%B0%E7%BB%84%E6%8E%92%E6%88%90%E6%9C%80%E5%B0%8F%E7%9A%84%E6%95%B0/"/>
    <id>http://example.com/2021/08/21/%E6%8A%8A%E6%95%B0%E7%BB%84%E6%8E%92%E6%88%90%E6%9C%80%E5%B0%8F%E7%9A%84%E6%95%B0/</id>
    <published>2021-08-21T09:27:48.000Z</published>
    <updated>2021-08-21T09:29:42.160Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>输入一个非负整数数组，把数组里所有数字拼接起来排成一个数，打印能拼接出的所有数字中最小的一个。</p></blockquote><figure class="highlight kotlin"><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="number">1</span>:</span><br><span class="line">输入: [<span class="number">10</span>,<span class="number">2</span>]</span><br><span class="line">输出: <span class="string">&quot;102&quot;</span></span><br><span class="line"></span><br><span class="line">示例 <span class="number">2</span>:</span><br><span class="line">输入: [<span class="number">3</span>,<span class="number">30</span>,<span class="number">34</span>,<span class="number">5</span>,<span class="number">9</span>]</span><br><span class="line">输出: <span class="string">&quot;3033459&quot;</span></span><br></pre></td></tr></table></figure><blockquote><p>说明: 输出结果可能非常大，所以你需要返回一个字符串而不是整数 拼接起来的数字可能会有前导 0，最后结果不需要去掉前导 0</p></blockquote><p>这道题的目的：尽可能让高位数字为小数，单个位上的数字大的，尽可能放在低位上</p><p>算法：使用排序的方式，按照字典序对字符串进行排序：</p><blockquote><p>字典序：比较两个字符串s1和s2：按照每个相同位置上的字符进行比较，如果位置1上的两个字符的字典序不同，则字典序小的排在前面，如果字典序相同，则继续比较下面的一位</p></blockquote><p>比如：</p><figure class="highlight kotlin"><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="number">102</span>和<span class="number">120</span></span><br><span class="line">第一位相同--&gt;比较第二位</span><br><span class="line">第二位：<span class="number">0</span>&lt;<span class="number">2</span></span><br><span class="line">所以：<span class="number">102</span> &lt; <span class="number">120</span></span><br><span class="line"></span><br><span class="line">-------------------</span><br><span class="line">比较：<span class="number">5</span>和<span class="number">123</span></span><br><span class="line">第一位：<span class="number">5</span>&gt;<span class="number">1</span></span><br><span class="line">所以：<span class="number">123</span> &lt; <span class="number">5</span></span><br></pre></td></tr></table></figure><p><strong>解法1，使用小根堆的方式：</strong></p><figure class="highlight java"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">minNumber</span><span class="params">(<span class="keyword">int</span>[] nums)</span> </span>&#123;</span><br><span class="line">        PriorityQueue&lt;String&gt; queue = <span class="keyword">new</span> PriorityQueue&lt;&gt;(<span class="keyword">new</span> Comparator&lt;String&gt;() &#123;</span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(String s1, String s2)</span> </span>&#123;</span><br><span class="line">                <span class="keyword">return</span> (s1 + s2).compareTo(s2 + s1);</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">for</span> (<span class="keyword">int</span> i:nums) &#123;</span><br><span class="line">            queue.offer(<span class="string">&quot;&quot;</span> + i);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        StringBuilder result = <span class="keyword">new</span> StringBuilder();</span><br><span class="line"><span class="comment">//注意在取出元素时，不能直接遍历，而是要在取出的同时，让这个堆继续保持正确的字典序</span></span><br><span class="line">        <span class="keyword">while</span>(!queue.isEmpty())&#123;</span><br><span class="line">            result.append(queue.poll());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result.toString();</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>解法2，直接对数组进行排序：</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">minNumber</span><span class="params">(<span class="keyword">int</span>[] nums)</span></span>&#123;</span><br><span class="line">    String[] strs = <span class="keyword">new</span> String[nums.length];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nums.length; i++) &#123;</span><br><span class="line">        strs[i] = nums[i]+<span class="string">&quot;&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    Arrays.sort(strs, (x,y)-&gt;(x + y).compareTo(y + x));</span><br><span class="line">    StringBuilder result = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">    <span class="keyword">for</span> (String s: strs) &#123;</span><br><span class="line">        result.append(s);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result.toString();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>本质上都是使用了排序（字典序）</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;输入一个非负整数数组，把数组里所有数字拼接起来排成一个数，打印能拼接出的所有数字中最小的一个。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure class=&quot;highlight kotlin&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gut</summary>
      
    
    
    
    
    <category term="剑指offer" scheme="http://example.com/tags/%E5%89%91%E6%8C%87offer/"/>
    
  </entry>
  
  <entry>
    <title>【LeetCode】 数值的整数次方</title>
    <link href="http://example.com/2021/08/21/%E3%80%90LeetCode%E3%80%9150.%20%E5%AE%9E%E7%8E%B0%E6%95%B0%E5%80%BC%E7%9A%84%E6%95%B4%E6%95%B0%E6%AC%A1%E6%96%B9/"/>
    <id>http://example.com/2021/08/21/%E3%80%90LeetCode%E3%80%9150.%20%E5%AE%9E%E7%8E%B0%E6%95%B0%E5%80%BC%E7%9A%84%E6%95%B4%E6%95%B0%E6%AC%A1%E6%96%B9/</id>
    <published>2021-08-21T06:44:51.000Z</published>
    <updated>2021-08-21T07:09:03.771Z</updated>
    
    <content type="html"><![CDATA[<p>实现 pow(x, n) ，即计算 x 的 n 次幂函数（即，xn）。不得使用库函数，同时不需要考虑大数问题。</p><figure class="highlight kotlin"><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">输入：x = <span class="number">2.00000</span>, n = <span class="number">10</span></span><br><span class="line">输出：<span class="number">1024.00000</span></span><br><span class="line">输入：x = <span class="number">2.10000</span>, n = <span class="number">3</span></span><br><span class="line">输出：<span class="number">9.26100</span></span><br><span class="line">输入：x = <span class="number">2.00000</span>, n = -<span class="number">2</span></span><br><span class="line">输出：<span class="number">0.25000</span></span><br><span class="line">解释：<span class="number">2</span>-<span class="number">2</span> = <span class="number">1</span>/<span class="number">22</span> = <span class="number">1</span>/<span class="number">4</span> = <span class="number">0.25</span></span><br></pre></td></tr></table></figure><p>超时做法：简单的循环求解（递归会栈溢出）</p><figure class="highlight kotlin"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> double myPow(double x, int n) &#123;</span><br><span class="line">        <span class="keyword">if</span>(x == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        double res = <span class="number">1</span>;</span><br><span class="line">        int absN = Math.abs(n);</span><br><span class="line">        <span class="keyword">while</span>(absN &gt; <span class="number">0</span>)&#123;</span><br><span class="line">            res *= x;</span><br><span class="line">            absN--;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(n&gt;<span class="number">0</span>) <span class="keyword">return</span> res;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>/res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>快速幂方法：</strong></p><p>所谓的快速幂法就是将指数变为二进制的形式：</p><p><span class="math display">\[x^n=x^{1b_1 + 2b_2 + 4b_3 + ... + 2^{m-1}b_m}\]</span></p><p>其中的 <span class="math inline">\(b_1,b_2, ..., b_m\)</span>为二进制位上的<code>「0，1」</code></p><p>所以只需要循环遍历整个指数部分就以：</p><ul><li>计算<span class="math inline">\(x^1, x^2,...x^{2^{m-1}}\)</span>的值：循环赋值操作：<span class="math inline">\(x = x^2\)</span></li><li>获取<span class="math inline">\(b_1,b_2, ..., b_m\)</span>：<ul><li>n&amp;1（和1做与）：判断最后一位是不是1，是1的话，就可以<code>res = res * x</code> ，否则不是1，就保持原来的res不变</li><li>n&gt;&gt;1（向右位移）：判断下一位是不是1</li></ul></li></ul><figure class="highlight kotlin"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> double myPow(double x, int n) &#123;</span><br><span class="line">        <span class="keyword">if</span>(x == <span class="number">0</span>) <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        double res = <span class="number">1</span>;</span><br><span class="line">        long b = n; <span class="comment">//考虑到n的相反数可能越界</span></span><br><span class="line">        <span class="keyword">if</span>(b&lt;<span class="number">0</span>)&#123;</span><br><span class="line">            x = <span class="number">1</span>/x;</span><br><span class="line">            b = -b;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(b &gt; <span class="number">0</span>)&#123;</span><br><span class="line"><span class="comment">//按位和1做&amp;</span></span><br><span class="line">            <span class="keyword">if</span>((b &amp; <span class="number">1</span>) == <span class="number">1</span>) res *= x;</span><br><span class="line">            x *= x;</span><br><span class="line">            b = b &gt;&gt; <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;实现 pow(x, n) ，即计算 x 的 n 次幂函数（即，xn）。不得使用库函数，同时不需要考虑大数问题。&lt;/p&gt;
&lt;figure class=&quot;highlight kotlin&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span cla</summary>
      
    
    
    
    
    <category term="LeetCode" scheme="http://example.com/tags/LeetCode/"/>
    
  </entry>
  
  <entry>
    <title>【LeetCode】 LeetCode(重点题型总结)</title>
    <link href="http://example.com/2021/08/21/Leetcode(%E6%80%BB%E7%BB%93%E7%9A%84%E5%87%A0%E9%81%93%E7%BB%8F%E5%85%B8%E9%A2%98%E5%9E%8B)/"/>
    <id>http://example.com/2021/08/21/Leetcode(%E6%80%BB%E7%BB%93%E7%9A%84%E5%87%A0%E9%81%93%E7%BB%8F%E5%85%B8%E9%A2%98%E5%9E%8B)/</id>
    <published>2021-08-21T06:04:51.000Z</published>
    <updated>2021-08-21T06:46:55.782Z</updated>
    
    <content type="html"><![CDATA[<h1 id="leetcode">Leetcode</h1><h2 id="array">Array</h2><h3 id="摩尔投票">摩尔投票</h3><blockquote><p>题目背景：从一个数组中找到关键元素（关键元素的数量大于数组中元素总数的一半）</p></blockquote><p>算法思路：</p><ul><li><p>维护一个majority，用来记录可能的关键元素</p></li><li><p>维护一个count，用来记录投票数</p><ul><li>对数组中的元素进行一次循环，如果count == 0， 说明此时还没有确定关键元素，majority = num[i]， count++</li><li>如果count != 0，说明，majority中已经有了备选方案，如果当前元素 == majority，count++； 否则count- -</li></ul></li><li><p>遍历完成后，</p><ul><li>如果count == 0， 说明没有关键元素，返回-1</li><li>如果count != 0，只能说明现在的majority是众数，但不一定大于数组的一半</li></ul></li><li><p>验证：判断这个数的出现次数是否超过了一半</p></li><li><p>完毕</p></li></ul><p>伪代码：</p><figure class="highlight java"><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">int</span> <span class="title">majorityElement</span><span class="params">(<span class="keyword">int</span>[] nums)</span></span>&#123;</span><br><span class="line">    <span class="comment">//如果数组长度为0，返回-1</span></span><br><span class="line">    <span class="keyword">if</span>(nums.length()&lt;=<span class="number">0</span>)&#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">//维护两个变量majority和count</span></span><br><span class="line">    <span class="keyword">int</span> majority = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">//循环遍历所有元素</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;nums.length; i++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(count == <span class="number">0</span>)&#123;</span><br><span class="line">            majority = nums[i];</span><br><span class="line">            count++;</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(nums[i] == majority)&#123;</span><br><span class="line">                count++;</span><br><span class="line">            &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                cout--;</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="comment">//此时已经获得了众数majority</span></span><br><span class="line">    <span class="comment">//接下来判断是否满足关键元素</span></span><br><span class="line">    <span class="keyword">if</span>(count == <span class="number">0</span>)&#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="keyword">int</span> identify = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;nums.length; i++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(nums[i] == majority)&#123;</span><br><span class="line">            identify++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(identify&gt;nums.length/<span class="number">2</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> majority;</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><br></pre></td></tr></table></figure><h3 id="只出现一次的数字">136. 只出现一次的数字</h3><blockquote><p>给定一个<strong>非空</strong>整数数组，除了某个元素只出现一次以外，其余每个元素均出现两次。找出那个只出现了一次的元素。</p></blockquote><p>要求：线性时间，常数空间</p><p>算法：</p><ul><li><p>数组只能遍历一次，不能有额外的外部空间</p></li><li><p>考虑到可以使用位运算：</p><p>位运算的特征</p><figure><img src="Leetcode.assets/image-20201127184021263.png" alt="image-20201127184021263" /><figcaption aria-hidden="true">image-20201127184021263</figcaption></figure></li></ul><p>所以整个数组中的数，相同的数两两组合，最后剩下的数就是唯一的一个数，因为遵循交换律和结合律，所以可以直接遍历数组的数，求所有数的异或</p><ul><li>设定result初始值为0，遍历所有数，连续异或</li></ul><figure class="highlight java"><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">int</span> result = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nums.length; i++)&#123;</span><br><span class="line">    result ^= nums[i];</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> result;</span><br></pre></td></tr></table></figure><h3 id="最接近的三数之和">16. 最接近的三数之和</h3><blockquote><p>给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数，使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。</p><figure class="highlight plaintext"><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">输入：nums = [-1,2,1,-4], target = 1</span><br><span class="line">输出：2</span><br><span class="line">解释：与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。</span><br></pre></td></tr></table></figure></blockquote><p><strong>算法</strong>：</p><ol type="1"><li>对数组排序：O(nlogn)</li><li>对a枚举O(n)</li><li>对b和c采用双指针，两侧逼近target O(n)</li><li>优化：<ol type="1"><li>如果三数之和为target，直接返回</li><li>如果pb或者pc所指的数和之前相同，继续移动，直到一个新的数</li></ol></li></ol><p>总的时间复杂度：O(n<sup>2</sup>)</p><p><strong>代码：</strong></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">threeSumClosest</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> sub = Integer.MAX_VALUE;</span><br><span class="line">        <span class="keyword">int</span> sum = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;nums.length; i++)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j = i+<span class="number">1</span>; j&lt;nums.length; j++)&#123;</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> k = j+<span class="number">1</span>; k&lt;nums.length; k++)&#123;</span><br><span class="line">                    <span class="keyword">int</span> newSub = Math.abs(nums[i]+nums[j]+nums[k]-target);</span><br><span class="line">                    <span class="keyword">if</span> (newSub&lt;sub)&#123;</span><br><span class="line">                        sub = newSub;</span><br><span class="line">                        sum = nums[i]+nums[j]+nums[k];</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 class="keyword">return</span> sum;</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">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">threeSumClosest2</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> target)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> best = <span class="number">10000000</span>;</span><br><span class="line">        Arrays.sort(nums);</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;nums.length; i++)&#123;</span><br><span class="line">            <span class="keyword">int</span> pb = i+<span class="number">1</span>;</span><br><span class="line">            <span class="keyword">int</span> pc = nums.length-<span class="number">1</span>;</span><br><span class="line">            <span class="keyword">while</span>(pb&lt;pc)&#123;</span><br><span class="line">                <span class="keyword">int</span> sum = nums[i] + nums[pb] + nums[pc];</span><br><span class="line">                <span class="keyword">if</span>(sum == target)&#123;</span><br><span class="line">                    <span class="keyword">return</span> target;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span>(Math.abs(best-target)&gt;Math.abs(sum-target))&#123;</span><br><span class="line">                    best = sum;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span>(sum &lt; target)&#123;</span><br><span class="line">                    pb++;</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">//如果判断条件是：nums[pb+1] == nums[pb]；则当前位置的数会被跳过，可能会导致指针pb和pc不能指向数值想同的不同位置</span></span><br><span class="line">                    <span class="comment">//比如下面的例子：&#123;-1，0，1，1，55&#125;；无法使得pb指向第一个1，pc指向第二个1</span></span><br><span class="line">                    <span class="keyword">while</span>(pb&lt;pc &amp;&amp; nums[pb] == nums[pb-<span class="number">1</span>])&#123;</span><br><span class="line">                        pb++;</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 &gt; target)&#123;</span><br><span class="line">                    pc--;</span><br><span class="line">                    <span class="keyword">while</span>(pb&lt;pc &amp;&amp; nums[pc+<span class="number">1</span>] == nums[pc])&#123;</span><br><span class="line">                        pc--;</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 class="keyword">return</span> best;</span><br><span class="line"></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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[] nums = <span class="keyword">new</span> <span class="keyword">int</span>[]&#123;-<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">55</span>&#125;;</span><br><span class="line">        System.out.println(threeSumClosest2(nums, <span class="number">3</span>));</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="所有奇数长度子数组的和">1588. 所有奇数长度子数组的和</h3><p>题目：</p><blockquote><p>给你一个正整数数组 arr ，请你计算所有可能的奇数长度子数组的和。子数组 定义为原数组中的一个连续子序列。请你返回 arr 中 所有奇数长度子数组的和 。</p></blockquote><figure class="highlight plaintext"><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">输入：arr = [1,4,2,5,3]</span><br><span class="line">输出：58</span><br><span class="line">解释：所有奇数长度子数组和它们的和为：</span><br><span class="line">[1] = 1</span><br><span class="line">[4] = 4</span><br><span class="line">[2] = 2</span><br><span class="line">[5] = 5</span><br><span class="line">[3] = 3</span><br><span class="line">[1,4,2] = 7</span><br><span class="line">[4,2,5] = 11</span><br><span class="line">[2,5,3] = 10</span><br><span class="line">[1,4,2,5,3] = 15</span><br><span class="line">我们将所有值求和得到 1 + 4 + 2 + 5 + 3 + 7 + 11 + 10 + 15 = 58</span><br></pre></td></tr></table></figure><p>我的想法：维护一个窗口，编写一个可以从窗口中求和的方法，在外界循环中不断的缩小窗口，内侧循环中不断地向后移动窗口</p><figure class="highlight java"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">sumOddLengthSubarrays</span><span class="params">(<span class="keyword">int</span>[] arr)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> maxOdd = arr.length%<span class="number">2</span> == <span class="number">0</span> ? arr.length-<span class="number">1</span> : arr.length;</span><br><span class="line">        <span class="keyword">int</span> result = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(maxOdd&gt;<span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">int</span> leftBound = <span class="number">0</span>; </span><br><span class="line">            <span class="keyword">int</span> rightBound = leftBound+maxOdd-<span class="number">1</span>;</span><br><span class="line">            <span class="keyword">while</span>(rightBound&lt;arr.length)&#123;</span><br><span class="line">                result += sum(arr, leftBound, rightBound);</span><br><span class="line">                leftBound++;</span><br><span class="line">                rightBound = leftBound+maxOdd-<span class="number">1</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            maxOdd -= <span class="number">2</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">sum</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> leftBound, <span class="keyword">int</span> rightBound)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> sum = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = leftBound; i&lt;=rightBound; i++)&#123;</span><br><span class="line">            sum += nums[i];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> sum;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>LeetCode方法</strong>：</p><p>归根到底计算的是每一个元素出现的次数，当遍历到下标为 i 的元素（第i+1个元素），左边有 i 个元素，右边有length-1-i个元素</p><p>元素数为奇数的条件：左边元素的数量+1（当前元素）+右边元素的数量 = 奇数</p><p>情况1：奇数+1+奇数</p><p>情况2：偶数+1+偶数</p><p><img src="https://i.loli.net/2020/12/23/irPqgpuXKYAMxf7.png" alt="image-20201223230626771" style="zoom:80%;" /></p><p><img src="https://i.loli.net/2020/12/23/hRQAOm69BqSkKtL.png" alt="image-20201223230653230" style="zoom:67%;" /></p><p>从n个数中选择奇数个数的可能情况：(n+1)/2</p><p>从n个数中选择偶数个数的可能情况：(n/2)+1</p><p>那么当前元素可参与的长度为奇数的连续数组的可能情况：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">leftOdd * rightOdd + leftEven * rightEven</span><br></pre></td></tr></table></figure><p>只要计算出每一个数的出现次数即可：</p><figure class="highlight java"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">sumOddLengthSubarrays</span><span class="params">(<span class="keyword">int</span>[] arr)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> result = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;arr.length; i++)&#123;</span><br><span class="line">            <span class="keyword">int</span> leftOdd = (i+<span class="number">1</span>)/<span class="number">2</span>;</span><br><span class="line">            <span class="keyword">int</span> leftEven = (i/<span class="number">2</span>)+<span class="number">1</span>;</span><br><span class="line">            <span class="keyword">int</span> rightOdd = (arr.length-i)/<span class="number">2</span>;</span><br><span class="line">            <span class="keyword">int</span> rightEven = (arr.length-<span class="number">1</span>-i)/<span class="number">2</span>+<span class="number">1</span>;</span><br><span class="line">            result += arr[i]*(leftOdd*rightOdd+leftEven*rightEven);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="反转图像">832. 反转图像</h3><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line">给定一个二进制矩阵 A，我们想先水平翻转图像，然后反转图像并返回结果。</span><br><span class="line"></span><br><span class="line">水平翻转图片就是将图片的每一行都进行翻转，即逆序。例如，水平翻转 [<span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>] 的结果是 [<span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>]。</span><br><span class="line"></span><br><span class="line">反转图片的意思是图片中的 <span class="number">0</span> 全部被 <span class="number">1</span> 替换， <span class="number">1</span> 全部被 <span class="number">0</span> 替换。例如，反转 [<span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>] 的结果是 [<span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>]。</span><br><span class="line"></span><br><span class="line">示例 <span class="number">1</span>:</span><br><span class="line"></span><br><span class="line">输入: [[<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>],[<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>]]</span><br><span class="line">输出: [[<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>],[<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>]]</span><br><span class="line">解释: 首先翻转每一行: [[<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>],[<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>]]；</span><br><span class="line">     然后反转图片: [[<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>],[<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>]]</span><br><span class="line">示例 <span class="number">2</span>:</span><br><span class="line"></span><br><span class="line">输入: [[<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>],[<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>]]</span><br><span class="line">输出: [[<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>]]</span><br><span class="line">解释: 首先翻转每一行: [[<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>]]；</span><br><span class="line">然后反转图片: [[<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>],[<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>],[<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>]]</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span>[][] flipAndInvertImage(<span class="keyword">int</span>[][] A) &#123;</span><br><span class="line">        <span class="keyword">int</span> m = A.length;</span><br><span class="line">        <span class="keyword">int</span> n = A[<span class="number">0</span>].length;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;m; i++)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j&lt;(n+<span class="number">1</span>)/<span class="number">2</span>; j++)&#123; <span class="comment">//注意这里，当列数为奇数的时候，中间的一位也需要和1异或，所以交换次数要+1</span></span><br><span class="line">                swap(A[i], j, n-<span class="number">1</span>-j);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> A;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> temp = nums[i]^<span class="number">1</span>; <span class="comment">//这里通过和1异或可以改变当前数的值</span></span><br><span class="line">        nums[i] = nums[j]^<span class="number">1</span>;</span><br><span class="line">        nums[j] = temp;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="拼写单词">1160 拼写单词</h3><figure class="highlight java"><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">给你一份『词汇表』（字符串数组） words 和一张『字母表』（字符串） chars。</span><br><span class="line"></span><br><span class="line">假如你可以用 chars 中的『字母』（字符）拼写出 words 中的某个『单词』（字符串），那么我们就认为你掌握了这个单词。</span><br><span class="line"></span><br><span class="line">注意：每次拼写（指拼写词汇表中的一个单词）时，chars 中的每个字母都只能用一次。</span><br><span class="line"></span><br><span class="line">返回词汇表 words 中你掌握的所有单词的 长度之和。</span><br><span class="line"></span><br><span class="line">示例 <span class="number">1</span>：</span><br><span class="line"></span><br><span class="line">输入：words = [<span class="string">&quot;cat&quot;</span>,<span class="string">&quot;bt&quot;</span>,<span class="string">&quot;hat&quot;</span>,<span class="string">&quot;tree&quot;</span>], chars = <span class="string">&quot;atach&quot;</span></span><br><span class="line">输出：<span class="number">6</span></span><br><span class="line">解释： </span><br><span class="line">可以形成字符串 <span class="string">&quot;cat&quot;</span> 和 <span class="string">&quot;hat&quot;</span>，所以答案是 <span class="number">3</span> + <span class="number">3</span> = <span class="number">6</span>。</span><br><span class="line">示例 <span class="number">2</span>：</span><br><span class="line"></span><br><span class="line">输入：words = [<span class="string">&quot;hello&quot;</span>,<span class="string">&quot;world&quot;</span>,<span class="string">&quot;leetcode&quot;</span>], chars = <span class="string">&quot;welldonehoneyr&quot;</span></span><br><span class="line">输出：<span class="number">10</span></span><br><span class="line">解释：</span><br><span class="line">可以形成字符串 <span class="string">&quot;hello&quot;</span> 和 <span class="string">&quot;world&quot;</span>，所以答案是 <span class="number">5</span> + <span class="number">5</span> = <span class="number">10</span>。</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>算法：</p><ul><li>准备一个长度为26的数组1，用来存放chars中每个英语字母出现的次数</li><li>将chars中的字母都存放进去，索引代表字母，值代表出现的次数</li><li>遍历words中的每个单词，再准备一个数组2，用来存放每一个单词中字母的出现次数</li><li>遍历两个数组，如果可以保证每一个数组2中的对应数字都小于数组1中的数字，那么这个单词就记住了，加上它的长度就可以了</li></ul><p>代码：</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">countCharacters</span><span class="params">(String[] words, String chars)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[] cArr = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">26</span>];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">char</span> c:chars.toCharArray()</span><br><span class="line">             ) &#123;</span><br><span class="line">            cArr[c-<span class="string">&#x27;a&#x27;</span>]++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> result = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (String word:words</span><br><span class="line">             ) &#123;</span><br><span class="line">            <span class="keyword">int</span>[] wArr = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">26</span>];</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">char</span> w:word.toCharArray()</span><br><span class="line">                 ) &#123;</span><br><span class="line">                wArr[w-<span class="string">&#x27;a&#x27;</span>]++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">boolean</span> can = <span class="keyword">true</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">26</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> (wArr[i]&gt;cArr[i])&#123;</span><br><span class="line">                    can = <span class="keyword">false</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (can) &#123;</span><br><span class="line">                result += word.length();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="最长无重复子串">3 最长无重复子串</h3><figure class="highlight plaintext"><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><br><span class="line">给定一个字符串，请你找出其中不含有重复字符的 最长子串 的长度。</span><br><span class="line">示例 1:</span><br><span class="line"></span><br><span class="line">输入: s = &quot;abcabcbb&quot;</span><br><span class="line">输出: 3 </span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;abc&quot;，所以其长度为 3。</span><br><span class="line">示例 2:</span><br><span class="line"></span><br><span class="line">输入: s = &quot;bbbbb&quot;</span><br><span class="line">输出: 1</span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;b&quot;，所以其长度为 1。</span><br><span class="line">示例 3:</span><br><span class="line"></span><br><span class="line">输入: s = &quot;pwwkew&quot;</span><br><span class="line">输出: 3</span><br><span class="line">解释: 因为无重复字符的最长子串是 &quot;wke&quot;，所以其长度为 3。</span><br><span class="line">     请注意，你的答案必须是 子串 的长度，&quot;pwke&quot; 是一个子序列，不是子串。</span><br><span class="line">示例 4:</span><br><span class="line"></span><br><span class="line">输入: s = &quot;&quot;</span><br><span class="line">输出: 0</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>算法：滑动窗口+集合</p><ul><li>准备左右两个指针</li><li>右指针向右移动，并将指向的字符存进set中</li><li>如果遇到重复的字母（set中存在），则右指针停下，记录此时的长度，从set中删除左指针指向的字符，左指针向右移动，</li><li>右指针遍历完毕整个字符串，结束，返回长度size</li></ul><p>进阶版：滑动窗口+哈希表：</p><p>直接跳转到左指针移动的情况：原方法是左指针一个一个移动，直到将set中和 ==右指针==指向字符重复的字符删除，但是这样左指针会遍历一些无用的字符：原左指针的位置——&gt;发生重复字符的位置（比如：gqcdef==a== b<font color =  green>a</font>bc，即从g到标记的a的位置），这一段是多余的。</p><p>改进方案：用map存储每个字符的位置信息，如果遇到了重复字符，左指针直接跳到该重复字符的下一个位置：从g直接跳到b，从常数时间上降低了复杂度</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">lengthOfLongestSubstring</span><span class="params">(String s)</span> </span>&#123;<span class="comment">//用map优化去重</span></span><br><span class="line">       <span class="keyword">if</span>(s.length() == <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">int</span> maxSize = <span class="number">0</span>;</span><br><span class="line">       HashMap&lt;Character, Integer&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">       <span class="keyword">int</span> l = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">int</span> r = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">while</span>(l&lt;=r &amp;&amp; r&lt;s.length())&#123;</span><br><span class="line">           <span class="keyword">if</span>(map.containsKey(s.charAt(r)))&#123;</span><br><span class="line">               l = Math.max(l, map.get(s.charAt(r))+<span class="number">1</span>);</span><br><span class="line">           &#125;</span><br><span class="line">           map.put(s.charAt(r), r++);</span><br><span class="line">           maxSize = Math.max(maxSize, (r-l));</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> maxSize;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">lengthOfLongestSubstring2</span><span class="params">(String s)</span></span>&#123;<span class="comment">//用set去重</span></span><br><span class="line">       <span class="keyword">int</span> maxSize = <span class="number">0</span>;</span><br><span class="line">       HashSet&lt;Character&gt; set = <span class="keyword">new</span> HashSet&lt;&gt;();</span><br><span class="line">       <span class="keyword">int</span> l = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">int</span> r = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">while</span>(l&lt;=r &amp;&amp; r&lt;s.length())&#123;</span><br><span class="line">           <span class="keyword">while</span>(r&lt;s.length() &amp;&amp; (!set.contains(s.charAt(r))))&#123;</span><br><span class="line">               set.add(s.charAt(r++));</span><br><span class="line">           &#125;</span><br><span class="line">           maxSize = Math.max(maxSize, r-l);</span><br><span class="line">           <span class="keyword">if</span>(r == s.length()-<span class="number">1</span>)&#123;</span><br><span class="line">               <span class="keyword">return</span> maxSize;</span><br><span class="line">           &#125;</span><br><span class="line">           set.remove(s.charAt(l));</span><br><span class="line">           l++;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> maxSize;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="滑动窗口最大值">239 <span id="jump">滑动窗口最大值</span></h3><figure class="highlight java"><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="keyword">public</span> <span class="keyword">int</span>[] maxSlidingWindow(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> k) &#123;</span><br><span class="line">       PriorityQueue&lt;<span class="keyword">int</span>[]&gt; queue = <span class="keyword">new</span> PriorityQueue&lt;&gt;(<span class="keyword">new</span> Comparator&lt;<span class="keyword">int</span>[]&gt;()&#123;</span><br><span class="line">           <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(<span class="keyword">int</span>[] pair1, <span class="keyword">int</span>[] pair2)</span></span>&#123;</span><br><span class="line">               <span class="keyword">return</span> pair1[<span class="number">0</span>] != pair2[<span class="number">0</span>] ? pair2[<span class="number">0</span>] - pair1[<span class="number">0</span>] : pair2[<span class="number">1</span>] - pair2[<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">int</span>[] result = <span class="keyword">new</span> <span class="keyword">int</span>[nums.length - k + <span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;k; i++)&#123;</span><br><span class="line">           queue.offer(<span class="keyword">new</span> <span class="keyword">int</span>[]&#123;nums[i],i&#125;);</span><br><span class="line">       &#125;</span><br><span class="line">       result[<span class="number">0</span>] = queue.peek()[<span class="number">0</span>];</span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i+k-<span class="number">1</span>&lt;nums.length; i++)&#123;</span><br><span class="line">           queue.offer(<span class="keyword">new</span> <span class="keyword">int</span>[]&#123;nums[i+k-<span class="number">1</span>], i+k-<span class="number">1</span>&#125;);</span><br><span class="line">           <span class="keyword">while</span>(queue.peek()[<span class="number">1</span>]&lt;i)&#123;</span><br><span class="line">               queue.poll();</span><br><span class="line">           &#125;</span><br><span class="line">           result[i] = queue.peek()[<span class="number">0</span>];</span><br><span class="line">       &#125;</span><br><span class="line">       </span><br><span class="line">       <span class="keyword">return</span> result;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><p>左神的方法：利用双端队列中的单调性：</p><figure class="highlight java"><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="keyword">public</span> <span class="keyword">int</span>[] maxSlidingWindow(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> k) &#123;</span><br><span class="line">       <span class="keyword">if</span>(nums == <span class="keyword">null</span> || nums.length&lt;k || k&lt;<span class="number">1</span>)&#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       LinkedList&lt;Integer&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">       <span class="keyword">int</span>[] result = <span class="keyword">new</span> <span class="keyword">int</span>[nums.length - k + <span class="number">1</span>];</span><br><span class="line">       <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;nums.length; i++)&#123;</span><br><span class="line">           <span class="keyword">while</span>(!queue.isEmpty() &amp;&amp; nums[i]&gt;=nums[queue.peekLast()])&#123;</span><br><span class="line">               queue.pollLast();</span><br><span class="line">           &#125;</span><br><span class="line">           queue.addLast(i);</span><br><span class="line">           <span class="keyword">if</span>(queue.peekFirst()&lt;=(i-k))&#123;<span class="comment">//如果被窗口抛下了（在窗口左边界的左侧）</span></span><br><span class="line">               queue.pollFirst();</span><br><span class="line">           &#125;</span><br><span class="line">           <span class="keyword">if</span>(i&gt;=k-<span class="number">1</span>)&#123;</span><br><span class="line">               result[index++] = nums[queue.peekFirst()];</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> result;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="旋转数组">189 旋转数组</h3><figure class="highlight plaintext"><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">给定一个数组，将数组中的元素向右移动 k 个位置，其中 k 是非负数。</span><br><span class="line"></span><br><span class="line">进阶：</span><br><span class="line">尽可能想出更多的解决方案，至少有三种不同的方法可以解决这个问题。</span><br><span class="line">你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗？</span><br><span class="line"></span><br><span class="line">示例 1:</span><br><span class="line">输入: nums = [1,2,3,4,5,6,7], k = 3</span><br><span class="line">输出: [5,6,7,1,2,3,4]</span><br><span class="line">解释:</span><br><span class="line">向右旋转 1 步: [7,1,2,3,4,5,6]</span><br><span class="line">向右旋转 2 步: [6,7,1,2,3,4,5]</span><br><span class="line">向右旋转 3 步: [5,6,7,1,2,3,4]</span><br></pre></td></tr></table></figure><p>算法：旋转数组：</p><table><thead><tr class="header"><th>步骤</th><th>旋转后的效果</th></tr></thead><tbody><tr class="odd"><td>旋转整个数组（镜像）</td><td>[7,6,5,4,3,2,1]</td></tr><tr class="even"><td>旋转前k个数</td><td>[5,6,7, 4,3,2,1]</td></tr><tr class="odd"><td>旋转剩下的数</td><td>[5,6,7, 1,2,3,4]</td></tr></tbody></table><figure class="highlight java"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">rotate</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> k)</span> </span>&#123;</span><br><span class="line">        reverse(nums, <span class="number">0</span>, nums.length-<span class="number">1</span>);</span><br><span class="line">        reverse(nums, <span class="number">0</span>, k%(nums.length)-<span class="number">1</span>);</span><br><span class="line">        reverse(nums, k%(nums.length), nums.length-<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">reverse</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> left, <span class="keyword">int</span> right)</span></span>&#123;</span><br><span class="line">        <span class="keyword">while</span>(left&lt;=right)&#123;</span><br><span class="line">            <span class="keyword">int</span> temp = nums[left];</span><br><span class="line">            nums[left] = nums[right];</span><br><span class="line">            nums[right] = temp;</span><br><span class="line">            left++;</span><br><span class="line">            right--;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="剑指offer-03">剑指offer 03</h3><p>https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/solution/yuan-di-zhi-huan-shi-jian-kong-jian-100-by-derrick/705525</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">找出数组中重复的数字。</span><br><span class="line"></span><br><span class="line">在一个长度为 n 的数组 nums 里的所有数字都在 0～n-1 的范围内。数组中某些数字是重复的，但不知道有几个数字重复了，也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。</span><br><span class="line"></span><br><span class="line">示例 1：</span><br><span class="line">输入：</span><br><span class="line">[2, 3, 1, 0, 2, 5, 3]</span><br><span class="line">输出：2 或 3 </span><br></pre></td></tr></table></figure><p>算法：利用一个萝卜一个坑的方式去想，因为一共有0个数，所有数字的范围都在0～n-1之间，所以在没有重复的情况下，排序完成之后的数组将是0位置对应的数字为0，1位置对应的数字为1……每个位置的数字即为其下标的数字。</p><p>我们从第一个下标<code>i</code>和元素<code>m</code>不对应的位置<code>i</code>开始，将元素换到下标和元素相同的位置<code>m</code>，直到当前下标<code>i</code>的元素值为<code>i</code>.如果发现<code>m</code>位置的元素已经为<code>m</code>，说明m为重复元素，直接返回即可。</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">findRepeatNumber</span><span class="params">(<span class="keyword">int</span>[] nums)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;nums.length; i++)&#123;</span><br><span class="line">            <span class="keyword">while</span>(nums[i] != i)&#123;</span><br><span class="line">                <span class="keyword">if</span>(nums[nums[i]] != nums[i])&#123;</span><br><span class="line">                    swap(nums, i, nums[i]);</span><br><span class="line">                &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">                    <span class="keyword">return</span> nums[i];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</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="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> temp = nums[i];</span><br><span class="line">        nums[i] = nums[j];</span><br><span class="line">        nums[j] = temp;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="栈和队列">栈和队列</h2><h3 id="最小栈剑指offer-30">最小栈（剑指offer 30）</h3><h3 id="最大队列剑指offer59">最大队列（剑指offer59）</h3><h3 id="单调栈">单调栈：</h3><h4 id="每日温度">739 每日温度</h4><figure class="highlight plaintext"><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">请根据每日 气温 列表，重新生成一个列表。对应位置的输出为：要想观测到更高的气温，至少需要等待的天数。如果气温在这之后都不会升高，请在该位置用 0 来代替。</span><br><span class="line"></span><br><span class="line">例如，给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]，你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。</span><br><span class="line"></span><br><span class="line">提示：气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度，都是在 [30, 100] 范围内的整数。</span><br></pre></td></tr></table></figure><p><strong>算法：</strong></p><ul><li>准备一个栈，一个结果数组<code>res[]</code></li><li>从头开始遍历参数-温度数组</li><li>如果栈为空，加入当前温度下标</li><li>如果栈不为空，且当前栈顶元素<code>peek</code>小于当前遍历到的元素<code>cur</code>（<font color = red>注意，当前存入的是温度数组的下标，比较的却是下标对应的温度值</font>），弹出栈顶元素，且在结果数组中，栈顶元素<code>peek</code>的位置，存入栈顶元素<code>peek</code>和当前遍历到的元素<code>cur</code>差（表示：栈顶元素找到了第一个比自己大的温度）</li><li>如果栈为空，或者栈顶元素<code>peek</code>不小于当前遍历到的元素<code>cur</code>，将当前遍历到的元素<code>cur</code>压栈</li><li>循环完毕</li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span>[] dailyTemperatures(<span class="keyword">int</span>[] T) &#123;</span><br><span class="line">        Stack&lt;Integer&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">        <span class="keyword">int</span> n = T.length;</span><br><span class="line">        <span class="keyword">int</span>[] res = <span class="keyword">new</span> <span class="keyword">int</span>[n];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;n; i++)&#123;</span><br><span class="line">            <span class="keyword">while</span>(!stack.isEmpty() &amp;&amp; T[i]&gt;T[stack.peek()])&#123;</span><br><span class="line">                res[stack.peek()] = i-stack.pop();<span class="comment">//出栈，且将两个下标差存入出栈的下标的位置</span></span><br><span class="line">            &#125;</span><br><span class="line">            stack.push(i);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="单调双端队列">单调双端队列</h3><h4 id="滑动窗口最大值-1"><a href="#jump">滑动窗口最大值</a></h4><h2 id="进制问题">进制问题</h2><h3 id="excel列表的名称">168 Excel列表的名称</h3><figure class="highlight plaintext"><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">给定一个正整数，返回它在 Excel 表中相对应的列名称。</span><br><span class="line">例如，</span><br><span class="line">    1 -&gt; A</span><br><span class="line">    2 -&gt; B</span><br><span class="line">    3 -&gt; C</span><br><span class="line">    ...</span><br><span class="line">    26 -&gt; Z</span><br><span class="line">    27 -&gt; AA</span><br><span class="line">    28 -&gt; AB </span><br><span class="line">    ...</span><br></pre></td></tr></table></figure><p><strong>将n看作是一个26进制的数字，而且每一位的最小值为A，通过不断尝试得到以下结果：</strong></p><figure class="highlight java"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">convertToTitle</span><span class="params">(<span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line">        StringBuilder result = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">        <span class="keyword">while</span>(n&gt;<span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">int</span> rem = (n-=<span class="number">1</span>) % <span class="number">26</span>;<span class="comment">//注意在这里：关键点在于要对n减1，这样可以保证当n==26的时候，余数不会为0，导致插入的字母为A</span></span><br><span class="line">            result.insert(<span class="number">0</span>, (<span class="keyword">char</span>)(<span class="string">&#x27;A&#x27;</span>+rem));</span><br><span class="line">            n/=<span class="number">26</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result.toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="listnode">ListNode</h2><h3 id="分隔链表">86 分隔链表</h3><p>利用哨兵节点，将内容分成两个链表，然后再按照要求将两个链表合并起来</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">给你一个链表和一个特定值 x ，请你对链表进行分隔，使得所有小于 x 的节点都出现在大于或等于 x 的节点之前。</span><br><span class="line">你应当保留两个分区中每个节点的初始相对位置。</span><br><span class="line"></span><br><span class="line">示例：</span><br><span class="line">输入：head = 1-&gt;4-&gt;3-&gt;2-&gt;5-&gt;2, x = 3</span><br><span class="line">输出：1-&gt;2-&gt;2-&gt;4-&gt;3-&gt;5</span><br></pre></td></tr></table></figure><figure class="highlight java"><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">public</span> ListNode <span class="title">partition</span><span class="params">(ListNode head, <span class="keyword">int</span> x)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">if</span>(head == <span class="keyword">null</span>)&#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">       &#125;</span><br><span class="line">       ListNode less = <span class="keyword">new</span> ListNode(<span class="number">0</span>);<span class="comment">//哑节点，用来防止nullPointer</span></span><br><span class="line">       ListNode more = <span class="keyword">new</span> ListNode(<span class="number">0</span>);</span><br><span class="line">       ListNode lessPtr = less;</span><br><span class="line">       ListNode morePtr = more;</span><br><span class="line">       <span class="keyword">while</span>(head != <span class="keyword">null</span>)&#123;</span><br><span class="line">           <span class="keyword">if</span>(head.val&gt;=x)&#123;</span><br><span class="line">               morePtr.next = <span class="keyword">new</span> ListNode(head.val);</span><br><span class="line">               morePtr = morePtr.next;</span><br><span class="line">           &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">               lessPtr.next = <span class="keyword">new</span> ListNode(head.val);</span><br><span class="line">               lessPtr = lessPtr.next;</span><br><span class="line">           &#125;</span><br><span class="line">           head = head.next;</span><br><span class="line">       &#125;</span><br><span class="line">       lessPtr.next = more.next;</span><br><span class="line">       <span class="keyword">return</span> less.next;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="相交链表">160 相交链表</h3><figure><img src="https://i.loli.net/2021/01/06/uoMdVEDfX58bFnP.png" alt="img" /><figcaption aria-hidden="true">img</figcaption></figure><p>算法：</p><ul><li>对于两个链表，A+C和B+C，C是两个链表公有的部分。同时遍历两个链表的时候可以发现A+C+B = B+C+A。</li><li>准备两个指针指向链表开头，分别同时向下遍历，如果ptrA指向了null（链表结尾），就跳转到headB；如果ptrB指向了null，就跳转到headA，（这是为了应对在两个链表长度不等的情况下，指针可以在重合部分之前走过相同的节点，这样就可以同时达到公共节点了）</li><li>当两个指针指向的节点相同的时候（公共节点或者null），将这个节点返回</li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> ListNode <span class="title">getIntersectionNode</span><span class="params">(ListNode headA, ListNode headB)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(headA == <span class="keyword">null</span> || headB == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        ListNode lA = headA;</span><br><span class="line">        ListNode lB = headB;</span><br><span class="line">        <span class="keyword">while</span>(lA!=lB)&#123;</span><br><span class="line">            lA = lA == <span class="keyword">null</span> ? headB : lA.next;</span><br><span class="line">            lB = lB == <span class="keyword">null</span> ? headA : lB.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> lA;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="两两交换链表中的节点">24 两两交换链表中的节点</h3><figure><img src="https://i.loli.net/2021/01/12/3d1LhJDXiwNgUrk.png" alt="image-20210112180423432" /><figcaption aria-hidden="true">image-20210112180423432</figcaption></figure><p><strong>算法：</strong></p><ol type="1"><li><p>首先创建一个<code>dummyNode</code>哑节点，其<code>next</code>指向<code>head</code></p></li><li><p>准备一个<code>temp</code>指针指向当前要处理的节点</p></li><li><p>对<code>temp</code>后面的两个节点，做如下交换：</p><figure><img src="https://i.loli.net/2021/01/12/lSNqTGroQXeOsbR.png" alt="image-20210112180701161" /><figcaption aria-hidden="true">image-20210112180701161</figcaption></figure></li><li><p><code>temp.next = node2; node1.next = node2.next; node2.next = node1;</code></p></li><li><p>将<code>temp</code>节点向后移动，移动两个位置，如果当前位置后面还有两个节点，继续调换，如果没有节点了或者只有一个节点，停止</p><figure><img src="https://i.loli.net/2021/01/12/M9rTjehwq5saQUc.png" alt="image-20210112181007003" /><figcaption aria-hidden="true">image-20210112181007003</figcaption></figure><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> ListNode <span class="title">swapPairs</span><span class="params">(ListNode head)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(head == <span class="keyword">null</span> || head.next == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> head;</span><br><span class="line">        &#125;</span><br><span class="line">        ListNode dummyHead = <span class="keyword">new</span> ListNode(-<span class="number">1</span>);<span class="comment">//哑节点</span></span><br><span class="line">        dummyHead.next = head;</span><br><span class="line">        ListNode temp = dummyHead;</span><br><span class="line">        <span class="keyword">while</span>(temp.next != <span class="keyword">null</span> &amp;&amp; temp.next.next != <span class="keyword">null</span>)&#123;<span class="comment">//两步一交换</span></span><br><span class="line">            ListNode node1 = temp.next;</span><br><span class="line">            ListNode node2 = temp.next.next;</span><br><span class="line">            temp.next = node2;</span><br><span class="line">            node1.next = node2.next;</span><br><span class="line">            node2.next = node1;</span><br><span class="line">            temp = node1;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dummyHead.next;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="两数相加">445 两数相加</h3><figure class="highlight plaintext"><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><br><span class="line">你可以假设除了数字 0 之外，这两个数字都不会以零开头。</span><br><span class="line"></span><br><span class="line">输入：(7 -&gt; 2 -&gt; 4 -&gt; 3) + (5 -&gt; 6 -&gt; 4)</span><br><span class="line">输出：7 -&gt; 8 -&gt; 0 -&gt; 7</span><br></pre></td></tr></table></figure><p><strong>算法：</strong></p><p>利用两个栈来逆序链表，计算好结果后通过头插法插入到新的链表中</p></li></ol><h2 id="贪心算法">贪心算法</h2><h3 id="不重叠的区间的个数">435 不重叠的区间的个数</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">给定一个区间的集合，找到需要移除区间的最小数量，使剩余区间互不重叠。</span><br><span class="line"></span><br><span class="line">注意:</span><br><span class="line">可以认为区间的终点总是大于它的起点。</span><br><span class="line">区间 [1,2] 和 [2,3] 的边界相互“接触”，但没有相互重叠。</span><br><span class="line">示例 1:</span><br><span class="line">输入: [ [1,2], [2,3], [3,4], [1,3] ]</span><br><span class="line">输出: 1</span><br><span class="line">解释: 移除 [1,3] 后，剩下的区间没有重叠。</span><br><span class="line"></span><br><span class="line">示例 2:</span><br><span class="line">输入: [ [1,2], [1,2], [1,2] ]</span><br><span class="line">输出: 2</span><br><span class="line">解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。</span><br><span class="line"></span><br><span class="line">示例 3:</span><br><span class="line">输入: [ [1,2], [2,3] ]</span><br><span class="line">输出: 0</span><br><span class="line">解释: 你不需要移除任何区间，因为它们已经是无重叠的了。</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>算法：</p><ul><li>将数组中的区间按照右边界的大小进行排序（从小到大）</li><li>因为右边界小的区间会给其他区间更多的可能，贪心策略就是尽可能的寻找右边界小的区间，而且左边界没有小于上一个有效区间的右边界</li><li>如果找到一个满足条件的区间，计数加一，当前区间变为有效区间</li><li>最后用总的区间数减去不发生重叠的区间数就可以了</li></ul><figure class="highlight java"><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">public</span> <span class="keyword">int</span> <span class="title">eraseOverlapIntervals</span><span class="params">(<span class="keyword">int</span>[][] intervals)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">if</span>(intervals == <span class="keyword">null</span> || intervals.length &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">       <span class="comment">//排序，自己重写比较器</span></span><br><span class="line">       Arrays.sort(intervals, <span class="keyword">new</span> Comparator&lt;<span class="keyword">int</span>[]&gt;()&#123;</span><br><span class="line">           <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(<span class="keyword">int</span>[] arr1, <span class="keyword">int</span>[] arr2)</span></span>&#123;</span><br><span class="line">               <span class="keyword">return</span> arr1[<span class="number">1</span>] - arr2[<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">int</span> count = <span class="number">1</span>;</span><br><span class="line">       <span class="keyword">int</span> index = <span class="number">0</span>;<span class="comment">//指向（左边界）&gt;=前者（有边界的区间）的</span></span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;intervals.length; i++)&#123;</span><br><span class="line">           <span class="keyword">if</span>(intervals[i][<span class="number">0</span>]&gt;=intervals[index][<span class="number">1</span>])&#123;</span><br><span class="line">               count++;</span><br><span class="line">               index = i;<span class="comment">//因为当前区间满足要求，index就指向了当前区间</span></span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> intervals.length - count;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="根据身高和序号重组队列">406 根据身高和序号重组队列</h3><p>算法：</p><ul><li>根据身高h从大到小排序</li><li>相同身高则根据k的大小排序</li><li>将排好序的数组按照顺序添加到链表中，这样可以保证先将身高较高的同学排好，再去排身高较低的几个同学，可以保证身高较低的同学的位置是正确的（不会被推到后面）</li></ul><p>ps：其中h表示当前同学的身高，k表示在当前同学之前有k个同学的身高&gt;=当前同学</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">int</span>[][] reconstructQueue(<span class="keyword">int</span>[][] people) &#123;</span><br><span class="line">       <span class="comment">//按照身高从大到小排序，相同身高按照前面的人数从小到大排序</span></span><br><span class="line">       Arrays.sort(people, <span class="keyword">new</span> Comparator&lt;<span class="keyword">int</span>[]&gt;()&#123;</span><br><span class="line">           <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(<span class="keyword">int</span>[] arr1, <span class="keyword">int</span>[] arr2)</span></span>&#123;</span><br><span class="line">               <span class="keyword">return</span> arr1[<span class="number">0</span>] == arr2[<span class="number">0</span>] ? arr1[<span class="number">1</span>] - arr2[<span class="number">1</span>] : arr2[<span class="number">0</span>] - arr1[<span class="number">0</span>];</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;);</span><br><span class="line"></span><br><span class="line">       LinkedList&lt;<span class="keyword">int</span>[]&gt; list = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span>[] p:people)&#123;</span><br><span class="line">           list.add(p[<span class="number">1</span>],p);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> list.toArray(<span class="keyword">new</span> <span class="keyword">int</span>[list.size()][]);</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="买卖股票的最大收益">122 买卖股票的最大收益</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">题目描述：可以进行多次交易，多次交易之间不能交叉进行，可以进行多次交易。</span><br><span class="line">举例：</span><br><span class="line">输入: [7,1,5,3,6,4]</span><br><span class="line">输出: 7</span><br><span class="line">解释: 在第 2 天（股票价格 = 1）的时候买入，在第 3 天（股票价格 = 5）的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。</span><br><span class="line">     随后，在第 4 天（股票价格 = 3）的时候买入，在第 5 天（股票价格 = 6）的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。</span><br><span class="line"></span><br><span class="line">对于 [a, b, c, d]，如果有 a &lt;= b &lt;= c &lt;= d ，那么最大收益为 d - a。而 d - a = (d - c) + (c - b) + (b - a) ，因此当访问到一个 prices[i] 且 prices[i] - prices[i-1] &gt; 0，那么就把 prices[i] - prices[i-1] 添加到收益中。</span><br></pre></td></tr></table></figure><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">maxProfit</span><span class="params">(<span class="keyword">int</span>[] prices)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">if</span>(prices.length &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 class="keyword">int</span> result = <span class="number">0</span>;</span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;prices.length; i++)&#123;</span><br><span class="line">           <span class="keyword">if</span>(prices[i]&gt;prices[i-<span class="number">1</span>])&#123;</span><br><span class="line">               result+=prices[i]-prices[i-<span class="number">1</span>];</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> result;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h3 id="判断是否为子序列">392 判断是否为子序列</h3><figure class="highlight plaintext"><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">s = &quot;abc&quot;, t = &quot;ahbgdc&quot;</span><br><span class="line">Return true.</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>很骚的方法：用时0ms</p><figure class="highlight java"><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">public</span> <span class="keyword">boolean</span> <span class="title">isSubsequence</span><span class="params">(String s, String t)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">int</span> index = -<span class="number">1</span>;</span><br><span class="line">       <span class="keyword">char</span>[] letters = s.toCharArray();</span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">char</span> c:letters)&#123;</span><br><span class="line">           index = t.indexOf(c, index+<span class="number">1</span>);<span class="comment">//从index+1开始查找当前字符所在的位置，如果没有当前字符，返回-1</span></span><br><span class="line">           <span class="keyword">if</span>(index == -<span class="number">1</span>)&#123;</span><br><span class="line">               <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h2 id="string">String</h2><p>最长回文字串</p><figure class="highlight java"><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">//方法2，利用数组，桶计数</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">longestPalindrome2</span><span class="params">(String s)</span></span>&#123;</span><br><span class="line">        <span class="comment">//将所有的字符按照ASCII码装到对应的bucket中</span></span><br><span class="line">        <span class="keyword">int</span>[] letters = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">128</span>];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; s.length(); i++) &#123;</span><br><span class="line">            letters[s.charAt(i)]++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> count = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> n:letters</span><br><span class="line">             ) &#123;</span><br><span class="line">            <span class="keyword">if</span> (n&gt;<span class="number">1</span>)&#123;</span><br><span class="line">                count+=(n/<span class="number">2</span>*<span class="number">2</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (n%<span class="number">2</span>==<span class="number">1</span>&amp;&amp;count%<span class="number">2</span>==<span class="number">0</span>)&#123;</span><br><span class="line">                count++;</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> count;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="验证回文字串">验证回文字串</h3><p>算法：双指针</p><ul><li><p>指针p1指向字符串头，指针p2指向字符串尾</p></li><li><p>两个指针相向而行，循环跳出条件：p1==p2</p></li><li><p>对于每个指针，如果当前指向的元素不是字母或者数字，向下移动一位，直到是字母或者数字为止</p></li><li><p>两个指针静止后，比较两个指针指向的元素</p></li><li><p>如果相等，p1++， p2- -，下一次循环</p></li><li><p>如果不相等，return false</p></li><li><p>最后return true</p></li></ul><figure class="highlight java"><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">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isPalindrome</span><span class="params">(String s)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (s.length()==<span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> p1 = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> p2 = s.length()-<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span>(p1&lt;p2)&#123;</span><br><span class="line">            <span class="keyword">while</span>(p1&lt;p2&amp;&amp;!Character.isLetterOrDigit(s.charAt(p1)))&#123;</span><br><span class="line">                p1++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">while</span>(p1&lt;p2&amp;&amp;!Character.isLetterOrDigit(s.charAt(p2)))&#123;</span><br><span class="line">                p2--;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (p1&lt;p2) &#123;</span><br><span class="line">                <span class="keyword">if</span> (Character.toLowerCase(s.charAt(p1)) == Character.toLowerCase(s.charAt(p2))) &#123;</span><br><span class="line">                    p1++;</span><br><span class="line">                    p2--;</span><br><span class="line">                &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h2 id="广度优先搜索">广度优先搜索</h2><h3 id="模板1">模板1</h3><figure class="highlight java"><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="comment">/**</span></span><br><span class="line"><span class="comment"> * Return the length of the shortest path between root and target node.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">BFS</span><span class="params">(Node root, Node target)</span> </span>&#123;</span><br><span class="line">    Queue&lt;Node&gt; queue;  <span class="comment">// store all nodes which are waiting to be processed</span></span><br><span class="line">    <span class="keyword">int</span> step = <span class="number">0</span>;       <span class="comment">// number of steps neeeded from root to current node</span></span><br><span class="line">    <span class="comment">// initialize</span></span><br><span class="line">    add root to queue;</span><br><span class="line">    <span class="comment">// BFS</span></span><br><span class="line">    <span class="keyword">while</span> (queue is not empty) &#123;</span><br><span class="line">        step = step + <span class="number">1</span>;</span><br><span class="line">        <span class="comment">// iterate the nodes which are already in the queue</span></span><br><span class="line">        <span class="keyword">int</span> size = queue.size();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; size; ++i) &#123;</span><br><span class="line">            Node cur = the first node in queue;</span><br><span class="line">            <span class="keyword">return</span> step <span class="keyword">if</span> cur is target;</span><br><span class="line">            <span class="keyword">for</span> (Node next : the neighbors of cur) &#123;</span><br><span class="line">                add next to queue;</span><br><span class="line">            &#125;</span><br><span class="line">            remove the first node from queue;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> -<span class="number">1</span>;          <span class="comment">// there is no path from root to target</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>queue中添加的节点都是待处理的节点</li><li>每进行一次while循环，都距离根节点远一些，step+1</li><li>每次处理的都是queue中剩余的节点</li><li>将每一个node的邻居都加进来，之后再将被处理的节点弹出</li><li>缺点：如果出现环状链表，可能会导致无限循环</li></ul><h3 id="模板2">模板2</h3><p>为了防止环状链表导致的无限循环，利用set来存储已经处理过的节点，保证下一次不会再被遍历到</p><figure class="highlight java"><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="comment">/**</span></span><br><span class="line"><span class="comment"> * Return the length of the shortest path between root and target node.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">BFS</span><span class="params">(Node root, Node target)</span> </span>&#123;</span><br><span class="line">    Queue&lt;Node&gt; queue;  <span class="comment">// store all nodes which are waiting to be processed</span></span><br><span class="line">    Set&lt;Node&gt; used;     <span class="comment">// store all the used nodes</span></span><br><span class="line">    <span class="keyword">int</span> step = <span class="number">0</span>;       <span class="comment">// number of steps neeeded from root to current node</span></span><br><span class="line">    <span class="comment">// initialize</span></span><br><span class="line">    add root to queue;</span><br><span class="line">    add root to used;</span><br><span class="line">    <span class="comment">// BFS</span></span><br><span class="line">    <span class="keyword">while</span> (queue is not empty) &#123;</span><br><span class="line">        step = step + <span class="number">1</span>;</span><br><span class="line">        <span class="comment">// iterate the nodes which are already in the queue</span></span><br><span class="line">        <span class="keyword">int</span> size = queue.size();</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; size; ++i) &#123;</span><br><span class="line">            Node cur = the first node in queue;</span><br><span class="line">            <span class="keyword">return</span> step <span class="keyword">if</span> cur is target;</span><br><span class="line">            <span class="keyword">for</span> (Node next : the neighbors of cur) &#123;</span><br><span class="line">                <span class="keyword">if</span> (next is not in used) &#123;</span><br><span class="line">                    add next to queue;</span><br><span class="line">                    add next to used;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            remove the first node from queue;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> -<span class="number">1</span>;          <span class="comment">// there is no path from root to target</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="动态规划">动态规划</h2><h3 id="打家劫舍">198 打家劫舍</h3><blockquote><p>一道入门的动态规划题，通过尝试法，尝试使用暴力递归完成题目，然后优化为动态规划算法</p></blockquote><figure class="highlight plaintext"><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><br><span class="line">给定一个代表每个房屋存放金额的非负整数数组，计算你 不触动警报装置的情况下 ，一夜之内能够偷窃到的最高金额。</span><br><span class="line"></span><br><span class="line">示例 1：</span><br><span class="line"></span><br><span class="line">输入：[1,2,3,1]</span><br><span class="line">输出：4</span><br><span class="line">解释：偷窃 1 号房屋 (金额 = 1) ，然后偷窃 3 号房屋 (金额 = 3)。</span><br><span class="line">     偷窃到的最高金额 = 1 + 3 = 4 。</span><br><span class="line">示例 2：</span><br><span class="line"></span><br><span class="line">输入：[2,7,9,3,1]</span><br><span class="line">输出：12</span><br><span class="line">解释：偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9)，接着偷窃 5 号房屋 (金额 = 1)。</span><br><span class="line">     偷窃到的最高金额 = 2 + 9 + 1 = 12 。</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>对于数组中的每一个位置（每一间房），我们都有两种选择：进入这间房/不进入这间房。</p><p><strong>如果进入这间房：</strong>则和这间房相邻的房间必然不能进入</p><p><strong>如果没有进入这间房：</strong> 则这间房相邻的房间可以随意进入</p><p>当我们遍历完整个数组的时候，我们才能知道所有房间的情况，包括我们该选择哪个房间，所以我们要从数组末尾开始进入递归。</p><p>当确认了最后一个房间的选择情况，我们就可以向前确认其他房间的情况，即从数组的末端向前方递归。</p><p><strong>递归出口：</strong></p><ol type="1"><li>如果只有一个房间让小偷去偷，小偷的最大收获只能是这个房间的内容</li><li>如果有两个房间给小偷，小偷的最大收获是这两个房间中价值最高的那一个</li></ol><p><strong>设计递归函数：</strong></p><p>在递归函数中我们需要传入数组（所有房间的选择），和一个变量 i（表示当前我们在考虑的是哪一间房子）</p><p>假设我们要传入的房子数组是 int[ ] houses = {2,7,9,3,1} ，则对于递归函数：process( int[ ] houses, int i )，</p><p>当i == 0的时候，应该返回==houses[0]==，</p><p>当i == 1的时候，应该返回==houses[0] 和hosues[1]中最大的那个==</p><p>当i为其他值的时候，我们要考虑当前i表示的房子要不要去偷，如果偷，那么上一间房子就不能去偷了：==返回 process(houses, i-2) + houses[i]==</p><p>如果不去偷，那么上一间房子就可以去偷：返回==process(houses, i-1)==</p><p>递归函数如下：</p><figure class="highlight java"><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">public</span> <span class="keyword">int</span> <span class="title">process</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> i)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(i == <span class="number">0</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> nums[<span class="number">0</span>];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(i == <span class="number">1</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> Math.max(nums[<span class="number">0</span>], nums[<span class="number">1</span>]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> A = process(nums, i-<span class="number">1</span>); <span class="comment">//不偷当前房子</span></span><br><span class="line">    <span class="keyword">int</span> B = process(nums, i-<span class="number">2</span>)+nums[i]; <span class="comment">//偷当前房子</span></span><br><span class="line">    <span class="keyword">return</span> Math.max(A, B); <span class="comment">//选择两者中最大的值</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>递归的复杂度为O(2<sup>n</sup>)，递归的弊端</strong></p><p>当我们来到第5间房间的时候，如果偷第5间房：需要计算==第3间房==的情况；如果不偷第5间房：需要计算第4间房的情况</p><p>当我们来到第4间房的时候，如果去偷第4间房：需要计算第2间房的情况；如果不偷第4间房：需要计算==第3间房==的情况</p><p>综上可见：在数组的遍历过程中，第3间房的情况被计算了两次，如果用一种方法将第3间房的值保存起来，就可以加速递归的过程</p><p><strong>动态规划的解法：</strong></p><ul><li>准备一个dp数组dp[ ]，数组的长度即为房间的数量（因为我们不存在一个都不偷的情况）</li><li>我们要求的最后的结果即为dp[dp.length-1]，即走完所有的房子之后，我们才能知道最大收益可以是多少</li><li>当我们关注最后一个房间的情况（即dp[dp.length-1]）的时候，我们还需要考虑它的前一位和前两位的值</li><li>最终的迭代出口在数组的第0位和第1位</li><li>dp[0] = houses[0]，dp[1] = Math.max(houses[0], houses[1]）</li><li>从第二位开始，每一位的值 dp[ i ] 都是：Math.max ( dp[ i - 1] , dp[ i - 2 ] + houses[ i ] )</li><li>从第2位开始向后迭代，我们便可以将这个数组填满，取最后一位的值返回即可</li></ul><figure class="highlight java"><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">public</span> <span class="keyword">int</span> <span class="title">rob</span><span class="params">(<span class="keyword">int</span>[] nums)</span> </span>&#123;</span><br><span class="line">       <span class="keyword">if</span>(nums == <span class="keyword">null</span> || nums.length == <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>(nums.length == <span class="number">1</span>)&#123;</span><br><span class="line">           <span class="keyword">return</span> nums[<span class="number">0</span>];</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">int</span>[] dp = <span class="keyword">new</span> <span class="keyword">int</span>[nums.length]; <span class="comment">//动态规划迭代法需要的数组</span></span><br><span class="line">       dp[<span class="number">0</span>] = nums[<span class="number">0</span>]; <span class="comment">//先将第0位和第1位填好</span></span><br><span class="line">       dp[<span class="number">1</span>] = Math.max(nums[<span class="number">0</span>], nums[<span class="number">1</span>]);</span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">2</span>; i&lt;nums.length; i++)&#123;</span><br><span class="line">           <span class="keyword">int</span> A = dp[i-<span class="number">1</span>];</span><br><span class="line">           <span class="keyword">int</span> B = dp[i-<span class="number">2</span>]+nums[i];</span><br><span class="line">           dp[i] = Math.max(A,B);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> dp[nums.length-<span class="number">1</span>];</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h1 id="排序">排序</h1><h2 id="堆排序">堆排序</h2><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HeapSort</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[] nums = &#123;<span class="number">3</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">9</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="number">4</span>&#125;;</span><br><span class="line">        sort(nums);</span><br><span class="line">        System.out.println(Arrays.toString(nums));</span><br><span class="line"></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">    1. 让数组整体形成大根堆</span></span><br><span class="line"><span class="comment">    2. 最后一个位置和堆顶位置交换， size-1</span></span><br><span class="line"><span class="comment">    3. 重新调整为大根堆</span></span><br><span class="line"><span class="comment">    4. 重复2-3步骤</span></span><br><span class="line"><span class="comment">    5. 直到 size == 0</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(<span class="keyword">int</span>[] nums)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (nums == <span class="keyword">null</span> || nums.length&lt;<span class="number">2</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="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nums.length; i++) &#123;</span><br><span class="line">            insert(nums, i);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> size = nums.length;</span><br><span class="line">        <span class="keyword">while</span> (size&gt;<span class="number">0</span>)&#123;</span><br><span class="line">            swap(nums, <span class="number">0</span>, size-<span class="number">1</span>);</span><br><span class="line">            heapify(nums, <span class="number">0</span>, --size);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</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 class="doctag">@param</span> nums</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> size</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">heapify</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> index, <span class="keyword">int</span> size)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> left;</span><br><span class="line">        <span class="keyword">while</span>((left = index*<span class="number">2</span>+<span class="number">1</span>)&lt;size)&#123;</span><br><span class="line">            <span class="keyword">int</span> largestPos = (left+<span class="number">1</span>)&lt;size&amp;&amp;nums[left+<span class="number">1</span>]&gt;nums[left]?left+<span class="number">1</span>:left;</span><br><span class="line">            largestPos = nums[largestPos]&gt;nums[index]?largestPos:index;</span><br><span class="line">            <span class="keyword">if</span> (largestPos == index)&#123;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            swap(nums, largestPos, index);</span><br><span class="line">            index = largestPos;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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 class="doctag">@param</span> nums</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> index</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> index)</span></span>&#123;</span><br><span class="line">        <span class="keyword">while</span>(nums[index]&gt;nums[(index-<span class="number">1</span>)/<span class="number">2</span>])&#123;</span><br><span class="line">            swap(nums, index, (index-<span class="number">1</span>)/<span class="number">2</span>);</span><br><span class="line">            index = (index-<span class="number">1</span>)/<span class="number">2</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> temp = nums[i];</span><br><span class="line">        nums[i] = nums[j];</span><br><span class="line">        nums[j] = temp;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="归并排序">归并排序</h2><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MergeSort</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[] nums = &#123;<span class="number">3</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">7</span>, <span class="number">9</span>, <span class="number">8</span>, <span class="number">0</span>, <span class="number">4</span>&#125;;</span><br><span class="line">        sort(nums, <span class="number">0</span>, nums.length-<span class="number">1</span>);</span><br><span class="line">        System.out.println(Arrays.toString(nums));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">sort</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> L, <span class="keyword">int</span> R)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (R == L)&#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">int</span> mid = (R+L)/<span class="number">2</span>;</span><br><span class="line">        sort(nums, L, mid);</span><br><span class="line">        sort(nums, mid+<span class="number">1</span>, R);</span><br><span class="line">        merge(nums, L, R, mid);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">merge</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> L, <span class="keyword">int</span> R, <span class="keyword">int</span> mid)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[] temp = <span class="keyword">new</span> <span class="keyword">int</span>[R-L+<span class="number">1</span>];</span><br><span class="line">        <span class="keyword">int</span> p = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> p1 = L;</span><br><span class="line">        <span class="keyword">int</span> p2 = mid + <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span>(p1&lt;=mid&amp;&amp;p2&lt;=R)&#123;</span><br><span class="line">            temp[p++] = nums[p1]&lt;nums[p2]?nums[p1++]:nums[p2++];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//如果p2遍历完了</span></span><br><span class="line">        <span class="keyword">while</span>(p1&lt;=mid)&#123;</span><br><span class="line">            temp[p++] = nums[p1++];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//如果p1遍历完了</span></span><br><span class="line">        <span class="keyword">while</span>(p2&lt;=R)&#123;</span><br><span class="line">            temp[p++] = nums[p2++];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//将temp拷贝回nums中</span></span><br><span class="line">        System.arraycopy(temp, <span class="number">0</span>, nums, L, temp.length);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="快速排序">快速排序</h2><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">QuickSort</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[] nums = &#123;<span class="number">3</span>,<span class="number">5</span>,<span class="number">6</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">7</span>,<span class="number">9</span>,<span class="number">8</span>,<span class="number">0</span>,<span class="number">4</span>&#125;;</span><br><span class="line">        quickSort(nums, <span class="number">0</span>, nums.length-<span class="number">1</span>);</span><br><span class="line">        System.out.println(Arrays.toString(nums));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">quickSort</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> leftBound, <span class="keyword">int</span> rightBound)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (leftBound&gt;=rightBound)&#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">int</span> partition = partition(nums, leftBound, rightBound);</span><br><span class="line">        quickSort(nums, leftBound, partition-<span class="number">1</span>);</span><br><span class="line">        quickSort(nums, partition+<span class="number">1</span>, rightBound);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">partition</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> leftBound, <span class="keyword">int</span> rightBound)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> pivot = rightBound;</span><br><span class="line">        <span class="keyword">int</span> p1 = leftBound;</span><br><span class="line">        <span class="keyword">int</span> p2 = rightBound-<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">while</span> (p1&lt;=p2)&#123;</span><br><span class="line">            <span class="keyword">while</span>(p1&lt;=p2&amp;&amp;nums[p1]&lt;=nums[pivot]) p1++;</span><br><span class="line">            <span class="keyword">while</span>(p1&lt;=p2&amp;&amp;nums[p2]&gt;nums[pivot]) p2--;</span><br><span class="line">            <span class="keyword">if</span> (p1&lt;p2)&#123;</span><br><span class="line">                swap(nums, p1, p2);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        swap(nums, p1, pivot);</span><br><span class="line">        <span class="keyword">return</span> p1;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> temp = nums[i];</span><br><span class="line">        nums[i] = nums[j];</span><br><span class="line">        nums[j] = temp;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="桶排序">桶排序</h2><h3 id="补充问题">补充问题</h3><ol type="1"><li><p>给定一个数组，求如果排序之后，相邻两数的最大差值，要求时间复杂度位O(N)，且要求不能用非基于比较的排序</p><p><strong>题解：</strong></p><p>总体：利用桶排序的思想，将数据分类，但是核心的排序方法仍是基于比较的排序</p><p>步骤：</p><ul><li><p>面对n个元素的数组，创建辅助数组，长度为n+1，主要是为了用于记录每个桶中的最大值，最小值，是否加入了新的元素。</p></li><li><p>为什么桶的数量为n+1:</p><p>为了保证最大gap不会出现在桶内（max-min），而是相邻两个有数据的桶之间的gap（下一个桶的最小值-上一个桶的最大值）</p></li><li><p>求出整个数组中的最大值和最小值，通过入桶算法，求出每一个元素应该进的桶号</p></li><li><p>将每个元素入桶</p></li><li><p>创建一个全局变量gap</p></li><li><p>遍历所有的桶，计算下一个桶最小值和当前桶的最大值的差值，根据大小情况更新gap</p></li><li><p>最后返回的gap即是全局最大的gap</p></li></ul><p>源代码：</p><figure class="highlight java"><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><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MaxGap</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[] nums = RandomArrayGenerator.generate(<span class="number">100</span>,<span class="number">100</span>);</span><br><span class="line">        System.out.println(truthValue(nums));</span><br><span class="line">        System.out.println(solution(nums));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">solution</span><span class="params">(<span class="keyword">int</span>[] nums)</span></span>&#123;</span><br><span class="line">        <span class="comment">//n个数，创建n+1个桶</span></span><br><span class="line">        <span class="keyword">int</span> min = Integer.MAX_VALUE;</span><br><span class="line">        <span class="keyword">int</span> max = Integer.MIN_VALUE;</span><br><span class="line">        <span class="comment">//取出了数组的最大最小值</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nums.length; i++) &#123;</span><br><span class="line">            min = Math.min(min, nums[i]);</span><br><span class="line">            max = Math.max(max, nums[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (min == max)&#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="comment">//创建3个辅助数组</span></span><br><span class="line">        <span class="keyword">boolean</span>[] hasNum = <span class="keyword">new</span> <span class="keyword">boolean</span>[nums.length+<span class="number">1</span>];</span><br><span class="line">        <span class="keyword">int</span>[] maxValue = <span class="keyword">new</span> <span class="keyword">int</span>[nums.length+<span class="number">1</span>];</span><br><span class="line">        <span class="keyword">int</span>[] minValue = <span class="keyword">new</span> <span class="keyword">int</span>[nums.length+<span class="number">1</span>];</span><br><span class="line">        <span class="comment">//重新遍历数组，将数值填入辅助数组的桶中</span></span><br><span class="line">        <span class="keyword">int</span> bucket = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nums.length ; i++) &#123;</span><br><span class="line">            <span class="comment">//用算法求出当前数应该在哪个桶中</span></span><br><span class="line">            bucket = bucket(nums[i], nums.length, min, max);</span><br><span class="line">            <span class="comment">//如果桶中还没有值，就将最小值置为nums[i],如果有了，就取两者之间的最小值</span></span><br><span class="line">            minValue[bucket] = hasNum[bucket]?Math.min(minValue[bucket],nums[i]):nums[i];</span><br><span class="line">            maxValue[bucket] = hasNum[bucket]?Math.max(maxValue[bucket],nums[i]):nums[i];</span><br><span class="line">            <span class="comment">//此时肯定已经有值了，将boolean置为true</span></span><br><span class="line">            hasNum[bucket] = <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//桶装好后，开始找最大值,遍历所有的桶。最大值发生在相邻两个数组之间，后一个数组的min-前一个数组的max</span></span><br><span class="line">        <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> lastMax = maxValue[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; nums.length+<span class="number">1</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (hasNum[i])&#123;</span><br><span class="line">                res = Math.max(res, minValue[i]-lastMax);</span><br><span class="line">                lastMax = maxValue[i];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</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="comment">/**</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> num 当前数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> len 一共有几个数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> min 数组中最小值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> max 数组中最大值</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 当前数应该在第几个桶</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">bucket</span><span class="params">(<span class="keyword">long</span> num, <span class="keyword">long</span> len, <span class="keyword">long</span> min, <span class="keyword">long</span> max)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> (<span class="keyword">int</span>)((num-min)*len/(max-min));</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">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">truthValue</span><span class="params">(<span class="keyword">int</span>[] nums)</span></span>&#123;</span><br><span class="line">        Arrays.sort(nums);</span><br><span class="line">        <span class="keyword">int</span> gap = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; nums.length; i++) &#123;</span><br><span class="line">            gap = Math.max(gap, nums[i]-nums[i-<span class="number">1</span>]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> gap;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="出现频率最多的k个元素">347 出现频率最多的k个元素</h3><figure class="highlight plaintext"><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">给定一个非空的整数数组，返回其中出现频率前 k 高的元素。</span><br><span class="line"></span><br><span class="line">示例 1:</span><br><span class="line"></span><br><span class="line">输入: nums = [1,1,1,2,2,3], k = 2</span><br><span class="line">输出: [1,2]</span><br><span class="line">示例 2:</span><br><span class="line"></span><br><span class="line">输入: nums = [1], k = 1</span><br><span class="line">输出: [1]</span><br></pre></td></tr></table></figure><p>算法1：</p><ul><li>通过HashMap将数组中的元素和其出现的次数对应起来</li><li>通过优先级队列（堆）根据出现次数从大到小排序</li><li>通过k次迭代从堆顶拿出k个数</li></ul><p>算法2：</p><ul><li>第一步同上</li><li>准备一个桶数组（数组由nums.length()+1个List组成，目的是为了使得下标和频次对应）</li><li>遍历Map中的Entry，将桶数组填好，天然的，桶数组右侧的元素频次大于左侧</li><li>从桶数组的右侧开始遍历，如果当前桶不为空，就遍历桶中的元素，加入到结果中，直到满足数量为k</li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span>[] topKFrequent(<span class="keyword">int</span>[] nums, <span class="keyword">int</span> k)&#123;</span><br><span class="line">       <span class="comment">//用来存储每个不同的数字和它出现的次数</span></span><br><span class="line">       HashMap&lt;Integer, Integer&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">       <span class="keyword">for</span>(<span class="keyword">int</span> n : nums)&#123;</span><br><span class="line">           map.put(n, map.getOrDefault(n, <span class="number">0</span>)+<span class="number">1</span>);</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">//准备一个桶数组List[]，下标表示频率，每个桶中的列表存储当前频率下的数值</span></span><br><span class="line">       ArrayList&lt;Integer&gt;[] buckets = <span class="keyword">new</span> ArrayList[nums.length+<span class="number">1</span>];</span><br><span class="line">       <span class="keyword">for</span> (Map.Entry&lt;Integer, Integer&gt; en:map.entrySet()</span><br><span class="line">            ) &#123;</span><br><span class="line">           <span class="keyword">int</span> num = en.getKey();</span><br><span class="line">           <span class="keyword">int</span> times = en.getValue();</span><br><span class="line">           <span class="keyword">if</span>(buckets[times] == <span class="keyword">null</span>)&#123;</span><br><span class="line">               <span class="comment">//如果当前频率下的元素不存在，就初始化这个列表</span></span><br><span class="line">               buckets[times] = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">           &#125;</span><br><span class="line">           buckets[times].add(num);<span class="comment">//在当前频率的桶中加入符合该频率的数值</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">int</span>[] res = <span class="keyword">new</span> <span class="keyword">int</span>[k];</span><br><span class="line">       <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line">       a:<span class="keyword">for</span>(<span class="keyword">int</span> i = buckets.length-<span class="number">1</span>; i&gt;=<span class="number">0</span>; i--)&#123;<span class="comment">//遍历整个桶数组</span></span><br><span class="line">           <span class="keyword">if</span>(buckets[i] == <span class="keyword">null</span>)&#123;<span class="comment">//如果当前桶为空，说明当前频率下没有元素在其中</span></span><br><span class="line">               <span class="keyword">continue</span>;</span><br><span class="line">           &#125;</span><br><span class="line">           b:<span class="keyword">for</span> (<span class="keyword">int</span> num:buckets[i]<span class="comment">//如果当前桶非空，就将桶中的元素一个一个加入到结果数组中</span></span><br><span class="line">                ) &#123;</span><br><span class="line">               res[index++] = num;<span class="comment">//随着元素的加入，结果数组的指针在不断增加</span></span><br><span class="line">               <span class="keyword">if</span> (index == res.length)&#123;<span class="comment">//如果结果数组的指针越界了，说明结果数组已满，直接终止外层循环</span></span><br><span class="line">                   <span class="keyword">break</span> a;</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="keyword">return</span> res;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><h1 id="数据结构">数据结构</h1><h2 id="栈">栈</h2></li></ol><h3 id="用数组实现创建栈">1.1 用数组实现创建栈</h3><h3 id="补充问题-1">1.2 补充问题</h3><ol type="1"><li><p>设计一个栈，在实现栈的基础功能的前提下，实现返回栈中最小元素的操作</p><p>要求：</p><p>（1）pop， push， getMin的复杂度都是O(1)</p><p>（2）设计的栈类型可以使用现成的栈结构</p><p><strong>题解：</strong></p><ul><li>准备两个栈：一个普通栈，一个只存储最小值的栈（minStack）</li><li>压栈的时候，同时压入第一个元素</li><li>压入第二个及以上元素：普通栈正常压，如果此时的元素&lt;minStack的栈顶，将此元素压入，否则重复压入minStack的栈顶</li><li>弹出元素：同时弹出两个栈的栈顶</li></ul><figure class="highlight java"><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><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">NewStack</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Stack&lt;Integer&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">    <span class="keyword">private</span> Stack&lt;Integer&gt; minStack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">push</span><span class="params">(<span class="keyword">int</span> num)</span></span>&#123;</span><br><span class="line">        stack.push(num);</span><br><span class="line">        <span class="keyword">if</span> (minStack.size() == <span class="number">0</span>)&#123;</span><br><span class="line">            minStack.push(num);</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            minStack.push(Math.min(num, <span class="keyword">this</span>.getMin()));</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">public</span> <span class="keyword">int</span> <span class="title">getMin</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (stack.size() == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> ArrayIndexOutOfBoundsException(<span class="string">&quot;栈已空&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> minStack.peek();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">pop</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (stack.size() == <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> ArrayIndexOutOfBoundsException(<span class="string">&quot;栈已空&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        minStack.pop();</span><br><span class="line">        <span class="keyword">return</span> stack.pop();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        NewStack newStack = <span class="keyword">new</span> NewStack();</span><br><span class="line">        newStack.push(<span class="number">1</span>);</span><br><span class="line">        newStack.push(<span class="number">2</span>);</span><br><span class="line">        newStack.push(<span class="number">3</span>);</span><br><span class="line">        newStack.push(<span class="number">4</span>);</span><br><span class="line">        newStack.push(<span class="number">5</span>);</span><br><span class="line">        newStack.push(<span class="number">0</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;Before pop:----------&quot;</span>);</span><br><span class="line">        System.out.println(newStack.getMin());</span><br><span class="line">        newStack.pop();</span><br><span class="line">        System.out.println(<span class="string">&quot;After pop:-----------&quot;</span>);</span><br><span class="line">        System.out.println(newStack.getMin());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol><h3 id="用队列实现栈">1.3 用队列实现栈</h3><p>要求：只用队列结构实现栈</p><p><strong>题解：</strong></p><ul><li><p>准备两个队列，一个是data，一个是help</p></li><li><p>添加元素的时候总是向data队列中添加元素</p></li><li><p>要取出元素的时候：（先进后出，后进先出），将data队列中的所有元素除了最后一个元素都添加到help队列中，返回data中的最后一个元素</p></li><li><p>交换两个队列，即help队列变成了新的data队列</p></li><li><p>如果只是访问栈顶元素，则同上，但是将data的最后一个元素也push进help中，交换两个队列</p></li></ul><p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.LinkedList;</span><br><span class="line"><span class="keyword">import</span> java.util.Queue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TwoQueueStack</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Queue&lt;Integer&gt; data;</span><br><span class="line">    <span class="keyword">private</span> Queue&lt;Integer&gt; help;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">TwoQueueStack</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.data = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">        <span class="keyword">this</span>.help = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">push</span><span class="params">(<span class="keyword">int</span> num)</span></span>&#123;</span><br><span class="line">        data.add(num);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">peek</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (data.isEmpty())&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;Stack is empty&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(data.size()&gt;<span class="number">1</span>)&#123;</span><br><span class="line">            help.add(data.poll());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> res = data.poll();</span><br><span class="line">        help.add(res);</span><br><span class="line">        swap();</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">pop</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (data.isEmpty())&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;Stack is empty&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span> (data.size()&gt;<span class="number">1</span>)&#123;</span><br><span class="line">            help.add(data.poll());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> res = data.poll();</span><br><span class="line">        swap();</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">public</span> <span class="keyword">void</span> <span class="title">swap</span><span class="params">()</span></span>&#123;</span><br><span class="line">        Queue&lt;Integer&gt; temp = data;</span><br><span class="line">        data = help;</span><br><span class="line">        help = temp;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> data.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        TwoQueueStack stack = <span class="keyword">new</span> TwoQueueStack();</span><br><span class="line">        stack.push(<span class="number">1</span>);</span><br><span class="line">        stack.push(<span class="number">2</span>);</span><br><span class="line">        stack.push(<span class="number">3</span>);</span><br><span class="line">        stack.push(<span class="number">4</span>);</span><br><span class="line">        stack.push(<span class="number">5</span>);</span><br><span class="line">        stack.push(<span class="number">6</span>);</span><br><span class="line">        <span class="comment">//按顺序弹出栈顶</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">6</span>; i++) &#123;</span><br><span class="line">            System.out.println(stack.pop());</span><br><span class="line">            System.out.println(stack);</span><br><span class="line">            System.out.println(<span class="string">&quot;--------------&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;   </span><br></pre></td></tr></table></figure></p><h3 id="用栈实现队列">1.4 用栈实现队列</h3><p>要求：只用栈实现队列</p><p>算法：</p><ul><li><p>准备两个栈：push栈，pop栈</p><p>push栈用于加入元素，pop栈用于弹出元素</p></li><li><p>加入元素的时候直接将元素加入push栈中</p></li><li><p>在取出元素之前，先调用pour方法：</p><p><strong>pour方法：</strong></p><p>将push栈中的元素都弹进pop栈中，目的是为了颠倒取出元素的顺序</p><p><strong>注意：</strong></p><p>pour的条件：</p><ol type="1"><li>如果pop栈中还有元素，就不能将push中的元素加入pop中</li><li>如果决定要将push栈中的元素倒入pop栈中，则一次性倒完</li></ol></li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Stack;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TwoStackQueue</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Stack&lt;Integer&gt; pushStack;</span><br><span class="line">    <span class="keyword">private</span> Stack&lt;Integer&gt; popStack;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">TwoStackQueue</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.pushStack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">        <span class="keyword">this</span>.popStack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> num)</span></span>&#123;</span><br><span class="line">        pushStack.push(num);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">pull</span><span class="params">()</span></span>&#123;</span><br><span class="line">        pour();</span><br><span class="line">        <span class="keyword">if</span> (popStack.isEmpty())&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;The queue is empty&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> popStack.pop();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">peek</span><span class="params">()</span></span>&#123;</span><br><span class="line">        pour();</span><br><span class="line">        <span class="keyword">if</span> (popStack.isEmpty())&#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;The queue is empty&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> popStack.peek();</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">     * 将push栈中的元素加入pop栈中</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">pour</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//如果pop栈不为空，则一定不能将push栈中的元素加进来</span></span><br><span class="line">        <span class="keyword">if</span> (!popStack.isEmpty())&#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">while</span>(!pushStack.isEmpty())&#123;</span><br><span class="line">            popStack.push(pushStack.pop());</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">public</span> String <span class="title">toString</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> popStack.toString();</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        TwoStackQueue queue = <span class="keyword">new</span> TwoStackQueue();</span><br><span class="line">        queue.add(<span class="number">1</span>);</span><br><span class="line">        queue.add(<span class="number">2</span>);</span><br><span class="line">        queue.add(<span class="number">3</span>);</span><br><span class="line">        queue.add(<span class="number">4</span>);</span><br><span class="line">        queue.add(<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            System.out.println(queue.pull());</span><br><span class="line">            System.out.println(queue);</span><br><span class="line">            System.out.println(<span class="string">&quot;-------------&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    1</span></span><br><span class="line"><span class="comment">    [5, 4, 3, 2]</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">    [5, 4, 3]</span></span><br><span class="line"><span class="comment">    -------------</span></span><br><span class="line"><span class="comment">    3</span></span><br><span class="line"><span class="comment">    [5, 4]</span></span><br><span class="line"><span class="comment">    -------------</span></span><br><span class="line"><span class="comment">    4</span></span><br><span class="line"><span class="comment">    [5]</span></span><br><span class="line"><span class="comment">    -------------</span></span><br><span class="line"><span class="comment">    5</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">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="猫狗队列">1.5 猫狗队列</h3><p><img src="/Users/lichaofan/Library/Application%20Support/typora-user-images/image-20201201145418902.png" alt="image-20201201145418902" style="zoom:50%;" /></p><p><strong>题解：</strong></p><ul><li><p>构建两个队列：猫队列和狗队列，这样可以方便的分别按照顺序弹出相应的宠物</p></li><li><p>如何在pollAll方法中做到两种宠物按照共同的时间进行排列呢？</p><p>给每一个加入队列中的宠物添加时间戳：</p><p>注意：不能修改宠物类，不能给宠物类添加新的属性</p><p><strong>解决方案</strong>：添加一个新的包装类，将Pet对象和一个计数变量包装起来</p></li><li><p>pollAll方法：比较两个队列顶部元素的时间戳大小，将时间戳小的弹出，当其中一个队列为空的时候，直接弹出另一个队列的元素即可</p></li><li><p>继续完成pollCat和pollDog和其他简单方法</p></li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 练习.队列.猫狗队列;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.LinkedList;</span><br><span class="line"><span class="keyword">import</span> java.util.Queue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CatDogQueue</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Pet</span> </span>&#123;</span><br><span class="line">        <span class="keyword">private</span> String type;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Pet</span><span class="params">(String type)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.type = type;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">getType</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> type;</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">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Dog</span> <span class="keyword">extends</span> <span class="title">Pet</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Dog</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(<span class="string">&quot;Dog&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="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Pet</span> </span>&#123;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Cat</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(<span class="string">&quot;Cat&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><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">PetEnter</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> Pet pet;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">PetEnter</span><span class="params">(Pet pet, <span class="keyword">int</span> count)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.pet = pet;</span><br><span class="line">            <span class="keyword">this</span>.count = count;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Pet <span class="title">getPet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> pet;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getCount</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> count;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">getEnterPetType</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">return</span> pet.getType();</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">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">PetQueue</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> Queue&lt;PetEnter&gt; catQueue;</span><br><span class="line">        <span class="keyword">private</span> Queue&lt;PetEnter&gt; dogQueue;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> count;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">PetQueue</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.catQueue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">            <span class="keyword">this</span>.dogQueue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">            <span class="keyword">this</span>.count = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(Pet pet)</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (pet.getType() .equals(<span class="string">&quot;Dog&quot;</span>))&#123;</span><br><span class="line">                dogQueue.add(<span class="keyword">new</span> PetEnter(<span class="keyword">new</span> Dog(), count++));</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span> (pet.getType().equals(<span class="string">&quot;Cat&quot;</span>))&#123;</span><br><span class="line">                catQueue.add(<span class="keyword">new</span> PetEnter(<span class="keyword">new</span> Cat(), count++));</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;Not dog or cat!&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">public</span> Pet <span class="title">pollAll</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (!dogQueue.isEmpty()&amp;&amp;!catQueue.isEmpty())&#123;</span><br><span class="line">                <span class="keyword">return</span> dogQueue.peek().count&lt;catQueue.peek().count?dogQueue.poll().getPet():catQueue.poll().getPet();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (!dogQueue.isEmpty())&#123;</span><br><span class="line">                <span class="keyword">return</span> dogQueue.poll().getPet();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (!catQueue.isEmpty())&#123;</span><br><span class="line">                <span class="keyword">return</span> catQueue.poll().getPet();</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;The queue is empty!&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">public</span> Pet <span class="title">pollCat</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (catQueue.isEmpty())&#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;CatQueue is empty!&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> catQueue.poll().getPet();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Pet <span class="title">pollDog</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (dogQueue.isEmpty())&#123;</span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;DogQueue is empty&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> dogQueue.poll().getPet();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">return</span> dogQueue.isEmpty()&amp;&amp;catQueue.isEmpty();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isCatEmpty</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">return</span> catQueue.isEmpty();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isDogEmpty</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="keyword">return</span> dogQueue.isEmpty();</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></pre></td></tr></table></figure><h3 id="宏观调度问题">1.6 宏观调度问题</h3><h4 id="矩阵旋转">1.6.1 矩阵旋转</h4><p>要求：在空间复杂度为O(1)的前提下，将矩阵旋转90度</p><p><strong>算法：</strong></p><p><img src="/Users/lichaofan/Library/Application%20Support/typora-user-images/image-20201201164019250.png" alt="image-20201201164019250" style="zoom:50%;" /></p><p>从外向内逐层旋转</p><p>旋转的方法：</p><p><img src="/Users/lichaofan/Library/Application%20Support/typora-user-images/image-20201201164238387.png" alt="image-20201201164238387" style="zoom:50%;" /></p><p>代码：</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RotateMatrix</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">rotate</span><span class="params">(<span class="keyword">int</span>[][] m)</span></span>&#123;</span><br><span class="line">        <span class="comment">//左上角</span></span><br><span class="line">        <span class="keyword">int</span> a = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> b = <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//右下角</span></span><br><span class="line">        <span class="keyword">int</span> c = m.length-<span class="number">1</span>;</span><br><span class="line">        <span class="keyword">int</span> d = m[<span class="number">0</span>].length-<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span>(a&lt;c)&#123;</span><br><span class="line">            rotateEdge(m, a++,b++,c--,d--);</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">rotateEdge</span><span class="params">(<span class="keyword">int</span>[][] m, <span class="keyword">int</span> a, <span class="keyword">int</span> b, <span class="keyword">int</span> c, <span class="keyword">int</span> d)</span></span>&#123;</span><br><span class="line">        <span class="comment">//循环次数</span></span><br><span class="line">        <span class="keyword">int</span> times = d - b;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; times; i++) &#123;</span><br><span class="line">            <span class="keyword">int</span> temp = m[a][b+i];</span><br><span class="line">            m[a][b+i] = m[c-i][b];</span><br><span class="line">            m[c-i][b] = m[c][d-i];</span><br><span class="line">            m[c][d-i] = m[a+i][d];</span><br><span class="line">            m[a+i][d] = temp;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">matrixPrint</span><span class="params">(<span class="keyword">int</span>[][] m)</span></span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; m.length; i++) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; m[<span class="number">0</span>].length; j++) &#123;</span><br><span class="line">                System.out.print(m[i][j]+<span class="string">&quot;\t&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println();</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[][] matrix = &#123;</span><br><span class="line">                &#123;<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>&#125;,</span><br><span class="line">                &#123;<span class="number">5</span>,<span class="number">6</span>,<span class="number">7</span>,<span class="number">8</span>&#125;,</span><br><span class="line">                &#123;<span class="number">9</span>,<span class="number">10</span>,<span class="number">11</span>,<span class="number">12</span>&#125;,</span><br><span class="line">                &#123;<span class="number">13</span>,<span class="number">14</span>,<span class="number">15</span>,<span class="number">16</span>&#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        System.out.println(<span class="string">&quot;旋转之前---------&quot;</span>);</span><br><span class="line">        matrixPrint(matrix);</span><br><span class="line">        rotate(matrix);</span><br><span class="line">        System.out.println(<span class="string">&quot;旋转之后---------&quot;</span>);</span><br><span class="line">        matrixPrint(matrix);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</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">1  2  3  4</span></span><br><span class="line"><span class="comment">5  6  7  8</span></span><br><span class="line"><span class="comment">9  101112</span></span><br><span class="line"><span class="comment">13141516</span></span><br><span class="line"><span class="comment">旋转之后---------</span></span><br><span class="line"><span class="comment">139 5  1</span></span><br><span class="line"><span class="comment">14106  2</span></span><br><span class="line"><span class="comment">15117  3</span></span><br><span class="line"><span class="comment">16128  4</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h4 id="之字形打印矩阵">1.6.2 之字形打印矩阵</h4><p>要求：之字形打印数组中的元素</p><p><strong>算法：</strong></p><ul><li>从左上角开始，准备两个点A和B</li><li>A向右跑，B向下跑</li><li>A到达最右端后，向下移动，B到达最下端后向右移动</li><li>用一个算法打印出A和B之间的数字（以AB为端点的对角线）</li></ul><p><img src="https://i.bmp.ovh/imgs/2020/12/01685feb5d52fee3.png" /></p><p>在算法中：</p><ul><li>先更新A的row，再更新A的col</li><li>先更新B的col，再更新B的row</li></ul><p>代码</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line">在算法中：</span><br><span class="line"></span><br><span class="line">* 先更新A的row，再更新A的col</span><br><span class="line">* 先更新B的col，再更新B的row</span><br><span class="line"></span><br><span class="line">代码</span><br></pre></td></tr></table></figure><h4 id="在行和列都排好序的矩阵中找数">1.6.3 在行和列都排好序的矩阵中找数</h4><p>要求：给定的M*N矩阵已经有序，现在给一个K，判断K是否在矩阵中</p><p>时间复杂度为O(M+N), 空间复杂度为O(1)</p><p><strong>算法：</strong></p><ul><li>从矩阵的右上角开始，如果当前值大于K，则向左移动；如果当前值小于K，向下移动；否则当前值就是K，返回true</li><li>终止条件，指针移动到了左下角都没有找到K，返回false</li><li>边界条件：移动到右下角后，当前数&lt;K，直接返回false；移动到左上角后，当前数&gt;K，直接返回false（<font color = red>最大值都比K小，说明K肯定不在矩阵的范围内，同理最小值也是如此</font>）</li></ul><p><strong>代码：</strong></p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 练习.从有序矩阵中寻找K;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@program</span>: leetcode</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: ClarkLevis</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span>: 2020-12-02 08:45</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FindK</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[][] matrix = &#123;</span><br><span class="line">                &#123;<span class="number">1</span>,<span class="number">3</span>,<span class="number">5</span>,<span class="number">6</span>&#125;,</span><br><span class="line">                &#123;<span class="number">2</span>,<span class="number">5</span>,<span class="number">7</span>,<span class="number">9</span>&#125;,</span><br><span class="line">                &#123;<span class="number">4</span>,<span class="number">6</span>,<span class="number">8</span>,<span class="number">10</span>&#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        System.out.println(findK(matrix,<span class="number">12</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">findK</span><span class="params">(<span class="keyword">int</span>[][] matrix, <span class="keyword">int</span> k)</span></span>&#123;</span><br><span class="line">        <span class="comment">//从右上角开始寻找，如果当前数大于K，则该列中的数都会比K大，切换到前一列</span></span><br><span class="line">        <span class="keyword">int</span> row = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> col = matrix[<span class="number">0</span>].length-<span class="number">1</span>;</span><br><span class="line">        <span class="comment">//边界条件：如果k不在当前矩阵范围内，返回false</span></span><br><span class="line">        <span class="keyword">if</span> (k&lt;matrix[<span class="number">0</span>][<span class="number">0</span>] || k&gt;matrix[matrix.length-<span class="number">1</span>][matrix[<span class="number">0</span>].length-<span class="number">1</span>])&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//终止条件：到达左下角</span></span><br><span class="line">        <span class="keyword">while</span>(!(row == matrix.length-<span class="number">1</span>&amp;&amp; col == <span class="number">0</span>))&#123;</span><br><span class="line">            <span class="keyword">if</span> (matrix[row][col] &gt; k)&#123;</span><br><span class="line">                col--; <span class="comment">// 因为已经确定了边界条件，这里不会出现越界问题了</span></span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span> (matrix[row][col] == k)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">while</span>(row&lt;matrix.length)&#123;</span><br><span class="line">                    <span class="keyword">if</span> (matrix[row][col] == k)&#123;</span><br><span class="line">                        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">                    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(matrix[row][col] &lt; k)&#123;</span><br><span class="line">                        row++;<span class="comment">// 因为已经确定了边界条件，这里不会出现越界问题了</span></span><br><span class="line">                    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                        col--;</span><br><span class="line">                        <span class="keyword">break</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">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="链表题目">1.7 链表题目</h3><h4 id="链表生成器">1.7.0 链表生成器</h4><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//可以根据一个数组生成对应数值的链表，并且可以根据链表的样子打印出来</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> val;</span><br><span class="line">        Node next;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Node</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.val = val;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            StringBuilder result = <span class="keyword">new</span> StringBuilder();</span><br><span class="line">            Node temp = <span class="keyword">this</span>;</span><br><span class="line">            <span class="keyword">while</span>(temp!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                result.append(temp.next==<span class="keyword">null</span>?temp.val:temp.val+<span class="string">&quot; -&gt; &quot;</span>);</span><br><span class="line">                temp = temp.next;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> result.toString();</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">public</span> <span class="keyword">static</span> Node <span class="title">linkGenerator</span><span class="params">(<span class="keyword">int</span>[] nums)</span></span>&#123;</span><br><span class="line">        Node head = <span class="keyword">new</span> Node(nums[<span class="number">0</span>]);</span><br><span class="line">        Node temp = head;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i &lt; nums.length; i++) &#123;</span><br><span class="line">            temp.next = <span class="keyword">new</span> Node(nums[i]);</span><br><span class="line">            temp = temp.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> head;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h4 id="找到链表中的相同节点">1.7.1 找到链表中的相同节点</h4><p>题目：给定两个有序链表头指针head1和head2，打印两个链表的公共部分</p><p>算法：外部排序（Merge过程）</p><h4 id="判断一个链表是不是回文结构">1.7.2 判断一个链表是不是回文结构</h4><p>题目：</p><p><img src="Leetcode.assets/f4d9679efde0a501.png" /></p><p><strong>算法1：</strong></p><p>遍历链表，将node加入栈中，再遍历栈，和原始链表比对，如果相等，说明是回文链表</p><p><strong>算法1增强版：</strong></p><ul><li>快慢指针：当快指针走到结尾的时候，慢指针走到中点的下一个位置</li><li>将慢指针和之后的节点压栈</li><li>弹栈，和链表的前半部分比较</li></ul><p><strong>算法2：</strong></p><ul><li>快慢指针：当快指针走到结尾的时候，慢指针走到中点</li><li>逆序从慢指针开始的后半部分</li><li>新建两个指针从头和尾遍历，到终点node为止</li><li>如果都相等，返回true，否则返回false</li><li>最后再将后半部分恢复回来</li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 练习.回文链表;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Stack;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@program</span>: leetcode</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span>: ClarkLevis</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span>: 2020-12-02 10:34</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Palindrome</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Node head = linkGenerator(<span class="keyword">new</span> <span class="keyword">int</span>[]&#123;<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">5</span>,<span class="number">4</span>,<span class="number">3</span>,<span class="number">2</span>,<span class="number">1</span>&#125;);</span><br><span class="line">        System.out.println(head);</span><br><span class="line">        System.out.println(isPalindrome3(head));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//空间复杂度为n</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isPalindrome1</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        Stack&lt;Integer&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">        Node pointer = head;</span><br><span class="line">        <span class="keyword">while</span> (pointer!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            stack.push(pointer.val);</span><br><span class="line">            pointer = pointer.next;</span><br><span class="line">        &#125;</span><br><span class="line">        pointer = head;</span><br><span class="line">        <span class="keyword">while</span> (!stack.isEmpty())&#123;</span><br><span class="line">            <span class="keyword">if</span> (stack.pop()!=pointer.val)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            pointer = pointer.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//空间复杂度为n/2</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isPalindrome2</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head == <span class="keyword">null</span> || head.next == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        Node slow = head.next;<span class="comment">//注意这里慢指针的初始位置</span></span><br><span class="line">        Node fast = head;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//当循环终止时，fast在最后一位（奇数），或者在倒数第二位（偶数）</span></span><br><span class="line">        <span class="comment">//slow在中间位置的下一位（奇数）1-&gt;2-&gt;3-&gt;(2)-&gt;1，或者在中间相等两数的第二个数（偶数）1-&gt;2-&gt;3-&gt;(3)-&gt;2-&gt;1</span></span><br><span class="line">        <span class="keyword">while</span>(fast.next!=<span class="keyword">null</span>&amp;&amp;fast.next.next!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            slow = slow.next;</span><br><span class="line">            fast = fast.next.next;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//将此时从slow开始的链表压栈</span></span><br><span class="line">        Stack&lt;Integer&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">        <span class="keyword">while</span> (slow!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            stack.push(slow.val);</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">while</span>(!stack.isEmpty())&#123;</span><br><span class="line">            <span class="keyword">if</span> (head.val != stack.pop())&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            head = head.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//空间复杂度为O(1)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isPalindrome3</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head == <span class="keyword">null</span> || head.next == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Node n1 = head;<span class="comment">//慢指针</span></span><br><span class="line">        Node n2 = head;<span class="comment">//快指针</span></span><br><span class="line">        <span class="comment">//慢指针移动到中点，或者中间偏左的位置（偶数）</span></span><br><span class="line">        <span class="keyword">while</span>(n2.next!=<span class="keyword">null</span>&amp;&amp;n2.next.next!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            n1 = n1.next;</span><br><span class="line">            n2 = n2.next.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//开始反转后半部分的链表</span></span><br><span class="line">        n2 = n1.next;</span><br><span class="line">        n1.next = <span class="keyword">null</span>;<span class="comment">//mid.next = null</span></span><br><span class="line">        Node n3 = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">while</span>(n2!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            n3 = n2.next;</span><br><span class="line">            n2.next = n1;</span><br><span class="line">            n1 = n2;</span><br><span class="line">            n2 = n3;</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">        n3 = n1;</span><br><span class="line">        n2 = head;</span><br><span class="line">        <span class="keyword">boolean</span> res = <span class="keyword">true</span>;</span><br><span class="line">        <span class="keyword">while</span> (n1!=<span class="keyword">null</span>&amp;&amp;n2!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span> (n1.val!=n2.val)&#123;</span><br><span class="line">                res = <span class="keyword">false</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            n1 = n1.next;</span><br><span class="line">            n2 = n2.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">        n1 = n3.next;</span><br><span class="line">        n3.next = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">while</span>(n1!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            n2 = n1.next;</span><br><span class="line">            n1.next = n3;</span><br><span class="line">            n3 = n1;</span><br><span class="line">            n1 = n2;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="链表的荷兰国旗问题">1.7.2 链表的荷兰国旗问题</h4><p>要求：给定一个链表和一个数字，将比这个数字小的节点放在左边，比这个数字大的节点放在右边，和这个数字相等的节点放在中间</p><p>时间复杂度为O(N)，空间复杂度为O(1)</p><h4 id="复制含有随机指针节点的链表">1.7.3 复制含有随机指针节点的链表</h4><p>题目：在链表的结点中，除了val，next之外，还有一个类型为Node的随机指针，它可能指向链表中的任何一个节点，也可能指向null</p><p><img src="https://i.loli.net/2021/01/19/rq4lAMFmO8EZ6kG.png" /></p><p><strong>算法1：</strong></p><p>使用HashMap ：</p><ul><li>将原链表中的节点作为key，将copy后的节点作为value，放入HashMap中。</li><li>重建新的链表</li><li>通过映射关系，重建rand关系：1’和 2’之间的关系可以通过1和2之间的关系得到</li></ul><p>需要额外空间</p><p><strong>代码：</strong></p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeepCopy</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Node head = <span class="keyword">new</span> Node(<span class="number">1</span>);</span><br><span class="line">        head.next = <span class="keyword">new</span> Node(<span class="number">2</span>);</span><br><span class="line">        head.next.next = <span class="keyword">new</span> Node(<span class="number">3</span>);</span><br><span class="line">        head.next.rand = head;</span><br><span class="line">        head.next.next.rand = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"></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">public</span> <span class="keyword">static</span> Node <span class="title">copyListWithRand1</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        HashMap&lt;Node, Node&gt; map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">        Node cur = head;</span><br><span class="line">        <span class="keyword">while</span>(cur!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            map.put(cur, <span class="keyword">new</span> Node(cur.val));</span><br><span class="line">            cur = cur.next;</span><br><span class="line">        &#125;</span><br><span class="line">        cur = head;</span><br><span class="line">        <span class="keyword">while</span>(cur!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            map.get(cur).next = map.get(cur.next);</span><br><span class="line">            map.get(cur).rand = map.get(cur.rand);</span><br><span class="line">            cur = cur.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> map.get(head);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Node</span></span>&#123;</span><br><span class="line">    <span class="keyword">int</span> val;</span><br><span class="line">    Node next;</span><br><span class="line">    Node rand;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Node</span><span class="params">(<span class="keyword">int</span> val)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.val = val;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>算法2：不用HashMap</strong></p><p>空间复杂度为O(1)</p><ul><li>通过第一次遍历，将原来的链表：</li></ul><p><img src="https://i.loli.net/2021/01/19/ygELMDZ1nJox3Ft.png" /></p><p>​ 每个copy节点都连接在原节点的后面</p><ul><li>当确定rand或者next关系的时候，首先通过原来链表的rand关系找到（1找到2），因为2’就在2的下一位，所以1’可以直接找到2’（通过这种结构关系，巧妙地避免了HashMap的使用）</li><li>最后，分离混合的链表（在这里面重新确定next关系）</li></ul><p><strong>代码：</strong></p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">static</span> Node <span class="title">copyListWithRand2</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        Node cur = head;</span><br><span class="line">        Node next = <span class="keyword">null</span>;</span><br><span class="line">        <span class="comment">//构造出 1 -&gt; 1 -&gt; 2 -&gt; 2 -&gt; 3 -&gt; 3 这种结构</span></span><br><span class="line">        <span class="keyword">while</span>(cur!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            next = cur.next;</span><br><span class="line">            cur.next = <span class="keyword">new</span> Node(cur.val);</span><br><span class="line">            cur.next.next = next;</span><br><span class="line">            cur = next;</span><br><span class="line">        &#125;</span><br><span class="line">        cur = head;</span><br><span class="line">        Node curCopy = <span class="keyword">null</span>;</span><br><span class="line">        <span class="comment">//设置 “复制Node”的rand指针</span></span><br><span class="line">        <span class="keyword">while</span>(cur!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            next = cur.next.next;</span><br><span class="line">            curCopy = cur.next;</span><br><span class="line">            curCopy.rand = cur.rand == <span class="keyword">null</span>? <span class="keyword">null</span>:cur.rand.next;</span><br><span class="line">            cur = next;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Node res = head.next;</span><br><span class="line">        cur = head;</span><br><span class="line">        <span class="comment">//分离混合在一起的链表</span></span><br><span class="line">        <span class="keyword">while</span>(cur!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            next = cur.next.next;</span><br><span class="line">            curCopy = cur.next;</span><br><span class="line">            cur.next = next;</span><br><span class="line">            curCopy.next = next==<span class="keyword">null</span>?<span class="keyword">null</span>:next.next;</span><br><span class="line">            cur = next;</span><br><span class="line">        &#125;</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="两个链表相交的一系列问题">1.7.4 两个链表相交的一系列问题</h4><p>题目：</p><p><img src="https://i.loli.net/2021/01/19/q5BTujQ3EXRslFZ.png" /></p><p>算法：</p><p>因为是单链表，所以右图的情况是不可能的</p><p><img src="https://i.loli.net/2021/01/19/E1oe8XkhbIlOQyu.png" /></p><ul><li><p>首先判断两个链表是否有环（用下面问题的方法）</p></li><li><p>则分别求出他们的入环节点loop1和loop2</p></li><li><p>如果没有环（loop1 == null ，loop2 == null），通过遍历每个节点，维护两个变量：len和endNode</p><ul><li>如果endNode1!=endNode2，两个链表不相交；否则相交</li><li>如果相交，则比较len<ul><li>如果len1-len2 = 10，则先让链表1遍历10个node，然后两个链表一起遍历，相遇的节点就是交叉的第一个节点</li></ul></li></ul></li><li><p>如果两个一个链表有环一个链表无环，不可能相交（loop1 ，loop2中有一个为null）</p></li><li><p>如果两个链表都有环（loop!=null loop2!=null）：</p><ol type="1"><li>各自成环，不相交</li><li>先相交，再共享一个环（loop1 == loop2）</li><li>从环上两个地方切入</li></ol><p><img src="https://i.loli.net/2021/01/19/UfRtF7GLcnxgmAu.png" /></p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Node <span class="title">getIntersectNode</span><span class="params">(Node head1, Node head2)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head1 == <span class="keyword">null</span> || head2 == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (head1 == head2)&#123;</span><br><span class="line">            <span class="keyword">return</span> head1;</span><br><span class="line">        &#125;</span><br><span class="line">        Node loop1 = getLoopNode(head1);</span><br><span class="line">        Node loop2 = getLoopNode(head2);</span><br><span class="line">        <span class="keyword">if</span> (loop1 == <span class="keyword">null</span> &amp;&amp; loop2 == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> noLoop(head1, head2);</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>(loop1 != <span class="keyword">null</span>&amp;&amp;loop2 != <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> bothLoop(head1, head2, loop1, loop2);</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</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">public</span> <span class="keyword">static</span> Node <span class="title">getLoopNode</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head == <span class="keyword">null</span> || head.next == <span class="keyword">null</span> || head.next.next == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//两个只针的位置要错开</span></span><br><span class="line">        Node fast = head.next.next;</span><br><span class="line">        Node slow = head.next;</span><br><span class="line">        <span class="comment">//第一次重合</span></span><br><span class="line">        <span class="keyword">while</span>(fast != slow)&#123;</span><br><span class="line">            <span class="keyword">if</span> (fast.next == <span class="keyword">null</span>||fast.next.next==<span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">            &#125;</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 class="comment">//重合后，快指针放回head</span></span><br><span class="line">        fast = head;</span><br><span class="line">        <span class="comment">//寻找第二次重合</span></span><br><span class="line">        <span class="keyword">while</span> (fast!=slow)&#123;</span><br><span class="line">            fast = fast.next;</span><br><span class="line">            slow = slow.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//返回当前重合节点</span></span><br><span class="line">        <span class="keyword">return</span> fast;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Node <span class="title">noLoop</span><span class="params">(Node head1, Node head2)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head1 == <span class="keyword">null</span> || head2 == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//遍历head1</span></span><br><span class="line">        <span class="keyword">int</span> len1 = <span class="number">0</span>;</span><br><span class="line">        Node endNode1 = <span class="keyword">null</span>;</span><br><span class="line">        Node cur = head1;</span><br><span class="line">        <span class="keyword">while</span>(cur != <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span> (cur.next == <span class="keyword">null</span>)&#123;</span><br><span class="line">                endNode1 = cur;</span><br><span class="line">            &#125;</span><br><span class="line">            len1++;</span><br><span class="line">            cur = cur.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//遍历head2</span></span><br><span class="line">        <span class="keyword">int</span> len2 = <span class="number">0</span>;</span><br><span class="line">        Node endNode2 = <span class="keyword">null</span>;</span><br><span class="line">        cur = head2;</span><br><span class="line">        <span class="keyword">while</span>(cur != <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span> (cur.next == <span class="keyword">null</span>)&#123;</span><br><span class="line">                endNode2 = cur;</span><br><span class="line">            &#125;</span><br><span class="line">            len2++;</span><br><span class="line">            cur = cur.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> (endNode1!=endNode2)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//结尾节点相等</span></span><br><span class="line">        <span class="comment">//长的链表先遍历sub步</span></span><br><span class="line">        Node longerHead = len1&gt;len2?head1:head2;</span><br><span class="line">        Node shorterHead = len1&gt;len2?head2:head1;</span><br><span class="line">        <span class="keyword">int</span> sub = len1&gt;len2?len1-len2:len2-len1;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; sub; i++) &#123;</span><br><span class="line">            longerHead = longerHead.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(longerHead!=shorterHead)&#123;</span><br><span class="line"></span><br><span class="line">            longerHead = longerHead.next;</span><br><span class="line">            shorterHead = shorterHead.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> longerHead;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Node <span class="title">bothLoop</span><span class="params">(Node head1, Node head2, Node loop1, Node loop2)</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (loop1 == loop2)&#123;</span><br><span class="line">            <span class="keyword">int</span> len1 = <span class="number">0</span>;</span><br><span class="line">            Node cur1 = head1;</span><br><span class="line">            <span class="keyword">while</span>(cur1 != loop1)&#123;</span><br><span class="line">                len1++;</span><br><span class="line">                cur1 = cur1.next;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//遍历head2</span></span><br><span class="line">            <span class="keyword">int</span> len2 = <span class="number">0</span>;</span><br><span class="line">            Node cur2 = head2;</span><br><span class="line">            <span class="keyword">while</span>(cur2 != loop1)&#123;</span><br><span class="line">                len2++;</span><br><span class="line">                cur2 = cur2.next;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//结尾节点相等</span></span><br><span class="line">            <span class="comment">//长的链表先遍历sub步</span></span><br><span class="line">            Node longerHead = len1&gt;len2?head1:head2;</span><br><span class="line">            Node shorterHead = len1&gt;len2?head2:head1;</span><br><span class="line">            <span class="keyword">int</span> sub = len1&gt;len2?len1-len2:len2-len1;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; sub; i++) &#123;</span><br><span class="line">                longerHead = longerHead.next;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">while</span>(longerHead!=shorterHead)&#123;</span><br><span class="line"></span><br><span class="line">                longerHead = longerHead.next;</span><br><span class="line">                shorterHead = shorterHead.next;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> longerHead;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Node cur = loop1.next;</span><br><span class="line">        <span class="keyword">while</span> (cur!=loop1)&#123;</span><br><span class="line">            <span class="keyword">if</span> (cur == loop2)&#123;</span><br><span class="line">                <span class="keyword">return</span> loop2;</span><br><span class="line">            &#125;</span><br><span class="line">            cur = cur.next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">int</span> value;</span><br><span class="line">        <span class="keyword">public</span> Node next;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Node</span><span class="params">(<span class="keyword">int</span> data)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.value = data;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></li></ul><h4 id="判断一个单链表是否有环若有环将环的起点返回">1.7.5 判断一个单链表是否有环（若有环，将环的起点返回）</h4><p><strong>算法1：快慢指针</strong>：</p><ul><li><p>如果两个指针重合，说明这个链表有环；如果其中一个指针遇到了null，则必然无环。</p></li><li><p><font color = red>当两个指针重合后，快指针回到起点，速度变为1步每次，则两个指针一定会在环的起点相遇</font></p></li><li><p>注意：快慢指针的起点：</p><ol type="1"><li><p>要么都在起点（推荐）</p><figure class="highlight java"><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">Node fast = head;</span><br><span class="line">     Node slow = head;</span><br><span class="line">     <span class="keyword">while</span>(<span class="keyword">true</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 class="keyword">if</span> (fast == slow)&#123;</span><br><span class="line">             <span class="keyword">break</span>;</span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure></li><li><p>要么在起点的下两个位置</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line">Node fast = head.next.next;</span><br><span class="line">      Node slow = head.next;</span><br><span class="line">      <span class="keyword">while</span>(fast != slow)&#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></pre></td></tr></table></figure></li><li><p>否则：<font color = red>在寻找环入口的时候可能会陷入死循环</font></p></li></ol></li></ul><p><strong>算法2：HashMap</strong>：遍历链表，每次将node存进表中，如果第一次出现了重复的node，就返回这个node</p><h2 id="二叉树相关问题">二叉树相关问题</h2><h3 id="二叉树的遍历">1 二叉树的遍历</h3><h4 id="二叉树的递归遍历">1.7.1 二叉树的递归遍历</h4><figure><img src="https://i.loli.net/2021/01/19/jkaPp3lw7KIc6W4.jpg" alt="img" /><figcaption aria-hidden="true">img</figcaption></figure><h4 id="二叉树的非递归遍历">1.7.2 二叉树的非递归遍历</h4><p><strong>栈：</strong>为什么用栈：</p><p>栈是一个可以反向输出的结构，因为二叉树的遍历一定是从上往下遍历每一个节点，是单向的，但是在递归中，子节点遍历完后可以返回父节点，形成了反向的遍历，这时候选择栈结构比较合适。而且递归本身就是一个方法栈。</p><p><strong>先序遍历：</strong></p><p>算法：</p><ul><li>准备一个栈</li><li>将头节点压进去</li><li>弹出头节点，打印，如果有的话，将右节点压入，再将左节点压入</li><li>如果最后一个元素弹出，且没有新的节点加入，说明遍历完成，栈已空</li></ul><figure class="highlight java"><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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">preOrderNoRecur</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head != <span class="keyword">null</span>)&#123;</span><br><span class="line">            Stack&lt;Node&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">            Node cur = head;</span><br><span class="line">            stack.push(cur);</span><br><span class="line">            <span class="keyword">while</span>(!stack.isEmpty())&#123;</span><br><span class="line">                cur = stack.pop();</span><br><span class="line">                System.out.print(cur.value+<span class="string">&quot; &quot;</span>);</span><br><span class="line">                <span class="keyword">if</span> (cur.right!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                    stack.push(cur.right);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (cur.left!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                    stack.push(cur.left);</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></pre></td></tr></table></figure><hr /><p><strong>中序遍历：</strong></p><p>算法：</p><ul><li><p>如果<font color = orange>栈不为空</font>或者<font color = yellow>当前节点不为null</font>，开始执行</p></li><li><p>如果当前节点不为null：不停的将该节点的left 节点压栈，直到当前节点为null</p><figure><img src="https://i.loli.net/2021/01/19/CAmcz1kGqebr6wh.png" alt="img" /><figcaption aria-hidden="true">img</figcaption></figure></li><li><p>如果当前节点为null，但是stack不为空，开始弹栈，当前节点为弹出的节点，打印</p><figure><img src="https://i.loli.net/2021/01/19/5zFWEGfY7oIvy38.png" alt="img" /><figcaption aria-hidden="true">img</figcaption></figure></li><li><p>当前（如果当前节点有right子节点）节点变为right子节点</p></li><li><p>直到<font color = green>栈为空且当前节点为空</font>，终止</p></li></ul><figure class="highlight java"><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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">inOrderNoRecur</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head!=<span class="keyword">null</span>)&#123;</span><br><span class="line">            Stack&lt;Node&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">            Node cur = head;</span><br><span class="line">            <span class="keyword">while</span>(!stack.isEmpty() || cur != <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="comment">//如果当前节点不为空，一直将当前节点和左子节点压入栈中</span></span><br><span class="line">                <span class="keyword">if</span> (cur!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                    stack.push(cur);</span><br><span class="line">                    cur = cur.left;</span><br><span class="line">                &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                    cur = stack.pop();</span><br><span class="line">                    System.out.print(cur.value+<span class="string">&quot; &quot;</span>);</span><br><span class="line">                    cur = cur.right;</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></pre></td></tr></table></figure><p><strong>直观逻辑：</strong></p><ol type="1"><li><p>将包括当前节点在内的左边树全部压入栈中--&gt;压入完成</p></li><li><p>弹出栈顶元素，如果这个元素有右子节点，将包括右子节点在内的，以右子节点为首的左边树压入栈中--&gt;压入完成</p></li><li><p>继续弹出栈顶元素</p><figure><img src="https://i.loli.net/2021/01/19/1W8vmKfSAzMU9rw.png" alt="img" /><figcaption aria-hidden="true">img</figcaption></figure></li></ol><hr /><p><strong>后序遍历</strong></p><p>算法：</p><p>用两个栈，实现相反的先序遍历</p><ol type="1"><li>考虑到：在先序遍历中，首先会pop头节点，然后将右节点和左节点压栈（因为栈会反向输出，所以输出顺序为左-右）</li><li>如果将输出变为压入另一个栈，pop头节点后，将先将左节点压栈，再压右节点，之后弹出的时候顺序就为右-左</li><li>所以会以中-右-左的顺序压入第二个栈</li><li>遍历第二个栈，就会以左-右-中的方式弹出</li></ol><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">posOrderNoRecur</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head != <span class="keyword">null</span>)&#123;</span><br><span class="line">            Stack&lt;Node&gt; stack1 = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">            Stack&lt;Node&gt; stack2 = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">            Node cur = head;</span><br><span class="line">            stack1.push(cur);</span><br><span class="line">            <span class="keyword">while</span>(!stack1.isEmpty())&#123;</span><br><span class="line">                cur = stack1.pop();</span><br><span class="line">                stack2.push(cur);</span><br><span class="line">                <span class="keyword">if</span> (cur.left!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                    stack1.push(cur.left);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (cur.right!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                    stack1.push(cur.right);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">while</span>(!stack2.isEmpty())&#123;</span><br><span class="line">                System.out.print(stack2  .pop().value+<span class="string">&quot; &quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="打印一棵二叉树">2.0 打印一棵二叉树</h3><h3 id="寻找二叉树的后继节点和前驱节点">2.1 寻找二叉树的后继节点和前驱节点</h3><h3 id="二叉树的序列化和反序列化">2.2 二叉树的序列化和反序列化</h3><p>序列化即是将二叉树的节点变成字符串，而且后期可以恢复回来</p><h4 id="通过先中后序遍历将节点都序列化">2.2.1 通过先中后序遍历将节点都序列化</h4><p>用相同的方式来反序列化</p><h4 id="通过层序遍历将节点序列化">2.2.2 通过层序遍历将节点序列化</h4><h3 id="判断一棵树是平衡二叉树">2.3 判断一棵树是平衡二叉树</h3><blockquote><p>对于任何一个节点，如果左子树的高度和右子树的高度差不超过1，就是平衡的</p></blockquote><p><strong>套路</strong>：因为递归可以经过一个节点三次（第一次；左子树返回（第二次）；右子树返回（第三次）），所以我们可以收集到两个子节点的信息再返回到父节点</p><p><strong>算法：</strong></p><p><font color = red>如果以每一个节点为头节点的子树都是平衡的，那么整棵树就是平衡的</font></p><ol type="1"><li>左树是否平衡</li><li>右树是否平衡</li><li>左树高度h1，和右树高度h2比较，看是否平衡</li><li>设计递归返回结构（1. 当前子树的高度 2. 当前子树是否平衡），这两个信息需要返回给父节点（<font color = orange>可以构建一个返回类</font>）</li></ol><figure class="highlight java"><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="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ReturnValue</span></span>&#123;</span><br><span class="line">        <span class="keyword">boolean</span> isBalance;</span><br><span class="line">        <span class="keyword">int</span> height;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">ReturnValue</span><span class="params">(<span class="keyword">boolean</span> isBalance, <span class="keyword">int</span> height)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.isBalance = isBalance;</span><br><span class="line">            <span class="keyword">this</span>.height = height;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>用递归列出所有的可能性：</p><figure class="highlight java"><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">public</span> <span class="keyword">static</span> ReturnValue <span class="title">process</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">    <span class="comment">//如果根节点是null，则这个子树是平衡的</span></span><br><span class="line">        <span class="keyword">if</span> (head == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> ReturnValue(<span class="keyword">true</span>, <span class="number">0</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        ReturnValue leftValue = process(head.left);</span><br><span class="line">        ReturnValue rightValue = process(head.right);</span><br><span class="line"><span class="comment">//如果左子树不平衡，这棵树就不平衡</span></span><br><span class="line">        <span class="keyword">if</span> (!leftValue.isBalance)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> ReturnValue(<span class="keyword">false</span>,<span class="number">0</span>);</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> (!rightValue.isBalance)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> ReturnValue(<span class="keyword">false</span>,<span class="number">0</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    <span class="comment">//如果左右高度差大于1，这棵树就不平衡</span></span><br><span class="line">        <span class="keyword">if</span> (Math.abs(rightValue.height-leftValue.height)&gt;<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> ReturnValue(<span class="keyword">false</span>,<span class="number">0</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    <span class="comment">//则目前子树平衡，返回这个子树的相关信息</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> ReturnValue(<span class="keyword">true</span>, Math.max(rightValue.height, leftValue.height)+<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>图解：</p><p><img src="Leetcode.assets/268220e800dfeb7b.jpg" /></p><h3 id="如何判断一棵树是搜索二叉树">2.4 如何判断一棵树是搜索二叉树</h3><blockquote><p>右子树比当前节点都大，左子树比当前节点都小，而且通常是没有重复节点的</p></blockquote><p>判断标准：<font color = red>一棵树的中序遍历结果是依次升序的，就是搜索二叉树</font></p><h3 id="如何判断一棵树是完全二叉树">2.5 如何判断一棵树是完全二叉树</h3><p>判断逻辑：</p><p><font color = red>二叉树的按层遍历</font></p><ol type="1"><li>如果一个Node只有右节点没有左节点，返回false，一定不是完全二叉树</li><li>如果一个Node只有左节点，或者没有子节点，那么后面遇到的所有节点都必须是叶子节点（层序遍历），否则一定不是完全二叉树</li><li>以上都可以保证，就是完全二叉树</li></ol><figure class="highlight java"><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">public</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">isCBT</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        Queue&lt;Node&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">        queue.offer(head);</span><br><span class="line">        <span class="keyword">boolean</span> beginLeaf = <span class="keyword">false</span>;<span class="comment">//是否进入之后的节点都是叶子节点模式？</span></span><br><span class="line">        <span class="keyword">while</span>(!queue.isEmpty())&#123;</span><br><span class="line">            Node cur = queue.poll();</span><br><span class="line">            Node left = cur.left;</span><br><span class="line">            Node right = cur.right;</span><br><span class="line">            <span class="comment">//这一条判断语句将两个条件都进行了判断</span></span><br><span class="line">            <span class="keyword">if</span> (beginLeaf&amp;&amp;(left!=<span class="keyword">null</span> || right!=<span class="keyword">null</span>) || left==<span class="keyword">null</span>&amp;&amp;right!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">false</span>;</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> (left!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                queue.offer(left);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (right!=<span class="keyword">null</span>)&#123;</span><br><span class="line">                queue.offer(right);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//如果出现左√右x的情况，开启叶子节点模式</span></span><br><span class="line">            <span class="keyword">if</span> (left!=<span class="keyword">null</span>&amp;&amp;right==<span class="keyword">null</span>)&#123;</span><br><span class="line">                beginLeaf = <span class="keyword">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="求完全二叉树节点的个数">2.5.1 求完全二叉树节点的个数</h3><p><strong>要求</strong>：如果二叉树的节点个数为n，时间复杂度应该低于O(n)</p><p><strong>已知情况：</strong>如果满二叉树的层数为 L， 那么这棵二叉树的节点数量为 2^L-1；如果一棵二叉树有n个节点，那么它的层数为log（n）</p><p><strong>算法：</strong></p><ol type="1"><li>先遍历head的左边界，可以得到二叉树的层数L</li><li>遍历head右子树的左边界：<ol type="1"><li>如果右子树的左边界到了最后一层，那么这个head节点的左子树是满的：左树的高度就为L-<font color = red>1</font>，可以求得左树的节点数：2<sup>(L-1)</sup> -1，加上头节点为 2<sup>(L-1)</sup> 。递归去求右子树的节点个数（其中这个L-1中的1是变化的，表示的是当前head节点所在的层数）</li><li>如果右子树左边界没有到最后一层，那么右子树一定是满的，只是高度为L-<font color = red>1</font>-1。可以求得右子树的节点个数为2<sup>(L-1-1)</sup> -1，加上头节点为2<sup>(L-1-1)</sup> ，递归左子树的节点个数</li></ol></li></ol><p><img src="Leetcode.assets/1be4d0df4584b638.jpg" /></p><p><strong>代码：</strong></p><figure class="highlight java"><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></pre></td><td class="code"><pre><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">     * <span class="doctag">@param</span> head 当前节点</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> level 当前节点所在的层数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 返回当前节点最深层的左节点的层数（相对于整棵树的层数）</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">mostLeftLevel</span><span class="params">(Node node, <span class="keyword">int</span> level)</span></span>&#123;</span><br><span class="line">    <span class="keyword">while</span>(node!=<span class="keyword">null</span>)&#123;</span><br><span class="line">        level++;</span><br><span class="line">        node = node.left;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> level;</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"><span class="comment">     * <span class="doctag">@param</span> node 当前被处理的节点</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> level 当前节点所在的层数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> h 整棵树的最大层数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 当前节点为头节点的子树的节点数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">process</span><span class="params">(Node node, <span class="keyword">int</span> level, <span class="keyword">int</span> h)</span></span>&#123;</span><br><span class="line">    <span class="comment">//如果当前节点到达了最大深度，肯定没有子节点了</span></span><br><span class="line">    <span class="keyword">if</span>(level == h)&#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">//右子树的深度到达了最大深度,则左子树一定是满二叉树</span></span><br><span class="line">    <span class="keyword">if</span>(mostLeftLevel(node.right, level+<span class="number">1</span>) == h)&#123;</span><br><span class="line">        <span class="keyword">return</span> (<span class="number">1</span>&lt;&lt;(h-level))+process(node.right, level+<span class="number">1</span>, h);</span><br><span class="line">    &#125;<span class="keyword">else</span>&#123;<span class="comment">//右子树的深度没有到达最大深度，右子树一定是满二叉树</span></span><br><span class="line">        <span class="keyword">return</span> (<span class="number">1</span>&lt;&lt;(h-level-<span class="number">1</span>))+peocess(node.left, level+<span class="number">1</span>, h);</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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">nodeCount</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(head == <span class="keyword">null</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> process(head, <span class="number">1</span>, mostLeftLevel(head, <span class="number">1</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>时间复杂度分析：</p><ul><li>每一层遍历一个节点（只遍历那个具有满二叉树的节点）一共有n个节点，logn层，复杂度为logn</li><li>判断深度的时候，只遍历右子树的左边界，依旧是logn</li><li>所以一共是log<sup>2</sup>n的复杂度</li></ul><h1 id="哈希函数和哈希表">哈希函数和哈希表</h1><h2 id="哈希函数">1 哈希函数</h2><p>性质：</p><ol type="1"><li>输入域：无穷大</li><li>输出域：固定大小</li><li>相同的输入必定会有相同的hashcode</li><li>存在不同输入对应相同hashcode的情况</li><li>hashcode具有离散型（而且和输入没有关系，可以打乱输入规律）</li><li>如果hashcode是均匀分布的，那么对hashcode取余之后，结果也是均匀分布的</li><li>hashcode中每一位和其他位都是相互独立的</li></ol><p>默认：哈希表的增删改查是O(1)的</p><h3 id="大数据类型问题">1.1 大数据类型问题</h3><p>利用hash函数来对大文件进行分流</p><h3 id="设计randompool结构">1.2 设计RandomPool结构</h3><p><img src="https://i.loli.net/2020/12/20/wMRhvj9JfXZIbUl.png" /></p><p><strong>算法：</strong></p><p>注意：要求是等概率，而且时间复杂度还要是O(1)，等概率考虑到使用随机数生成，但是需要index，所以想到Map结构；在删除操作中可能会在0~size-1之间产生一个洞，所以需要用最后一位来填</p><ol type="1"><li>准备两个Map，一个全局变量size。<font color=orange>第一个map用于存放key和index，其中index是我们自己用来构建索引的；第二个map用于存放index和key，其中index是用来通过随机数获取key的</font></li><li>add操作：map1中，加入&lt;String1， index1&gt;， map2中加入&lt;index1， String1&gt;， size++</li><li>当需要getRandom的时候，用Math.Random()*size获得 [0, size) 区间内的随机一个数，从map2中查找</li><li>当进行remove(key)操作的时候，将map1的最后一位覆盖key对应的一位，将map2的最后一位覆盖key对应的一位，然后将最后一条数据删除， size- -</li></ol><h2 id="布隆过滤器">2 布隆过滤器</h2><p>应用场景：爬虫去重问题，黑名单问题</p><p>布隆过滤器存在的问题：宁可错杀3000，也不放过1人（会存在比较低的失误率）</p><p>底层为一个bit数组</p><h3 id="在一个32000bit长的数组中如何将第30000个位置的bit置1">2.1 在一个32000bit长的数组中，如何将第30000个位置的bit置1？</h3><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span>[] arr = <span class="keyword">new</span> <span class="keyword">int</span>[<span class="number">1000</span>];</span><br><span class="line"><span class="keyword">int</span> index = <span class="number">30000</span>;</span><br><span class="line"><span class="keyword">int</span> intIndex = index/<span class="number">32</span>;</span><br><span class="line"><span class="keyword">int</span> bitIndex = index%<span class="number">32</span>;</span><br><span class="line"></span><br><span class="line">arr[intIndex] = (arr[intIndex] | (<span class="number">1</span>&lt;&lt;bitIndex));</span><br></pre></td></tr></table></figure><p><img src="https://i.loli.net/2020/12/20/yfJ1te32TrCzcAu.png" /></p><h3 id="实际的布隆过滤器判断url是否在黑名单里">2.2 实际的布隆过滤器（判断Url是否在黑名单里）</h3><p>详细了解：<a href="https://www.cnblogs.com/liyulong1982/p/6013002.html">布隆过滤器(Bloom Filter)详解 - 李玉龙 - 博客园 (cnblogs.com)</a></p><ol type="1"><li>准备一个足够大的数组</li><li>准备黑名单：将url经过hash函数之后，生成一个code，对数组长度取模（类似上面的方法），将相应桶中相应位置描黑</li><li>用k个hash函数做同样的操作，数组中最多将有k个位置被描黑（置1）</li><li>当要检查一个url是否在黑名单中时，对这个url取k次hashcode，看对应的k位置是否被描黑</li><li>如果k个位置全部被描黑，那么这个url可能就属于这个黑名单中</li><li>只要有一个位置不是被描黑的，就能够判断这个url没有在黑名单中</li></ol><p><strong>如何决定n的大小（bit数组的大小）：</strong></p><p><span class="math inline">\(n = -\frac{m\times\ln(p)}{(\ln2)^2}\)</span></p><p>n是数组的长度，m是样本量，p预期失误率</p><p><strong>如何确定hash函数的个数：</strong></p><p><span class="math inline">\(k = \ln2\times\frac{n}{m}\)</span> 向上取整</p><p><strong>真实失误率：</strong></p><p><span class="math inline">\((1-e^-\frac{m\times k}{n})^k\)</span></p><h2 id="一致性哈希">3 一致性哈希</h2><blockquote><p>降低数据迁移的代价，仍能保证负载均衡</p></blockquote><p>在负载均衡的时候，面对服务器设备增加的情况，需要进行全部的数据迁移，重新进行哈希。</p><p>而在一致性哈希的结构下，可以避免对hashcode取模，高效的应对设备数量变化的情况</p><p><img src="https://i.loli.net/2020/12/20/3KH7FyzqmwhiWke.png" /></p><p><strong>如何实现在环形结构中找到顺时针最近的服务器？</strong></p><p><img src="https://ftp.bmp.ovh/imgs/2020/12/f883604ec26e60e9.jpg" /></p><p>面临的问题：</p><ol type="1"><li>当服务器数量很少的时候很难做到均匀负载，即便做到了均匀负载，加入新的服务器的时候，负载又会被破坏</li></ol><p><strong>解决方案：<font color = red>虚拟节点技术</font></strong></p><blockquote><p>一致性哈希算法引入了虚拟节点机制，即对每一个服务节点计算多个哈希，每个计算结果位置都放置一个此服务节点，称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况，可以为每台服务器计算三个虚拟节点，于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值，于是形成六个虚拟节点：同时数据定位算法不变，只是多了一步虚拟节点到实际节点的映射，例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到Node A上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中，通常将虚拟节点数设置为32甚至更大，因此即使很少的服务节点也能做到相对均匀的数据分布</p></blockquote><h2 id="并查集">4 并查集</h2><blockquote><ol type="1"><li>非常快的检查两个元素是否属于一个集合isSameSet(A, B)</li><li>两个元素各自所在的集合合并在一起 union(A, B) ，A所在的集合和B所在的集合合并在一起</li></ol></blockquote><p><img src="Leetcode.assets/e5653f1d096aa6e4.png" /></p><ul><li>初始状态下，每个节点都是自己集合的代表节点</li><li>和其他集合合并的时候，元素数量少的集合将挂载到元素集合多的代表节点下面</li><li>如果要判断两个元素是否在同一个集合：就向上找他们各自的代表节点，如果是同一个代表节点，则判断是同一个集合</li></ul><p>优化：</p><p>因为向上寻找代表节点的时候会存在链表的遍历，为了降低复杂度，在一次遍历中可以将结构扁平化：链表上的所有节点都直接连接在代表节点后面</p><p><img src="Leetcode.assets/de0b747cf6240e8b.jpg" /></p><p>代码：</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">unionFindSet</span></span>&#123;</span><br><span class="line">        <span class="keyword">public</span> HashMap&lt;Node, Node&gt; fatherMap;<span class="comment">//key: child, value: father</span></span><br><span class="line">        <span class="keyword">public</span> HashMap&lt;Node, Integer&gt; sizeMap;<span class="comment">//key: 当前节点， value：当前节点所在集合的size</span></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">unionFindSet</span><span class="params">(List&lt;Node&gt; nodes)</span> </span>&#123;</span><br><span class="line">            makeSets(nodes);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">makeSets</span><span class="params">(List&lt;Node&gt; nodes)</span></span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.fatherMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">            <span class="keyword">this</span>.sizeMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">            <span class="comment">//集合初始化的时候，每个元素自成一个集合</span></span><br><span class="line">            <span class="keyword">for</span> (Node node:nodes) &#123;</span><br><span class="line">                fatherMap.put(node, node);</span><br><span class="line">                sizeMap.put(node, <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="comment">/**</span></span><br><span class="line"><span class="comment">         * 递归版本</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> node</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Node <span class="title">findHead</span><span class="params">(Node node)</span></span>&#123;</span><br><span class="line">            Node father = fatherMap.get(node);</span><br><span class="line">            <span class="comment">//通过递归找到整个集合的代表节点</span></span><br><span class="line">            <span class="keyword">if</span> (father != node)&#123;</span><br><span class="line">                father = findHead(father);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//将所有节点连到那个代表节点上去</span></span><br><span class="line">            fatherMap.put(node, father);</span><br><span class="line">            <span class="keyword">return</span> father;</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"><span class="comment">         * 非递归版本</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> node</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Node <span class="title">findHead2</span><span class="params">(Node node)</span></span>&#123;</span><br><span class="line">            Stack&lt;Node&gt; nodeStack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">            Node father = fatherMap.get(node);</span><br><span class="line">            <span class="keyword">while</span>(father!=node)&#123;</span><br><span class="line">                nodeStack.push(node);</span><br><span class="line">                node = father;</span><br><span class="line">                father = fatherMap.get(node);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">while</span>(!nodeStack.isEmpty())&#123;</span><br><span class="line">                fatherMap.put(nodeStack.pop(),father);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> father;</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"><span class="comment">         * <span class="doctag">@param</span> a</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> b</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isSameSet</span><span class="params">(Node a, Node b)</span></span>&#123;</span><br><span class="line">            <span class="keyword">return</span> findHead(a) == findHead(b);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">union</span><span class="params">(Node a, Node b)</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (a == <span class="keyword">null</span> || b == <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            Node aHead = findHead(a);</span><br><span class="line">            Node bHead = findHead(b);</span><br><span class="line">            <span class="comment">//只有两个代表节点不相等才需要合并</span></span><br><span class="line">            <span class="keyword">if</span> (aHead!=bHead)&#123;</span><br><span class="line">                <span class="keyword">int</span> aSetSize = sizeMap.get(aHead);</span><br><span class="line">                <span class="keyword">int</span> bSetSize = sizeMap.get(bHead);</span><br><span class="line">                <span class="keyword">if</span> (aSetSize&gt;bSetSize)&#123;</span><br><span class="line">                    <span class="comment">//将bSet挂载到aSet下面</span></span><br><span class="line">                    fatherMap.put(bHead, aHead);</span><br><span class="line">                    <span class="comment">//更新aSet的size（两个set size的和）</span></span><br><span class="line">                    sizeMap.put(aHead, aSetSize+bSetSize);</span><br><span class="line">                &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                    fatherMap.put(aHead, bHead);</span><br><span class="line">                    sizeMap.put(bHead, aSetSize+bSetSize);</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></pre></td></tr></table></figure><p><strong>复杂度分析：</strong></p><p>查询次数+合并次数 的数量级逼近O(n)及以上，单次查询的效率为O(1)</p><h3 id="岛问题">4.2 岛问题</h3><p><img src="Leetcode.assets/2844c962d417c083.png" /></p><p>算法：</p><ol type="1"><li>遍历整个数组，如果遇到1，开始进行感染函数；如果遇到0，跳过</li><li>感染函数：以当前位置开始，在不越界的前提下，将上下左右的位置全部感染，1变成2</li><li>继续遍历，如果遇到2，继续向下进行</li></ol><p>代码：</p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">IslandCount</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">countIsland</span><span class="params">(<span class="keyword">int</span>[][] m)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (m == <span class="keyword">null</span> || m[<span class="number">0</span>] == <span class="keyword">null</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">int</span> N = m.length;</span><br><span class="line">        <span class="keyword">int</span> M = m[<span class="number">0</span>].length;</span><br><span class="line">        <span class="keyword">int</span> res = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; N ; i++) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; M; j++) &#123;</span><br><span class="line">                <span class="keyword">if</span> (m[i][j] == <span class="number">1</span>)&#123;</span><br><span class="line">                    res++;</span><br><span class="line">                    infect(m,i,j,N,M);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</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="comment">/**</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> m 包含岛的矩阵</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> i 当前点所在的位置x</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> j 当前点所在的位置y</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> N 行数</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> M 列数</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">infect</span><span class="params">(<span class="keyword">int</span>[][] m, <span class="keyword">int</span> i, <span class="keyword">int</span> j, <span class="keyword">int</span> N, <span class="keyword">int</span> M)</span></span>&#123;</span><br><span class="line">        <span class="comment">//如果坐标越界，或者当前位置的值不为1，不做任何操作</span></span><br><span class="line">        <span class="keyword">if</span>(i&lt;<span class="number">0</span> || i&gt;=N || j&lt;<span class="number">0</span> || j&gt;=M || m[i][j] != <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">        m[i][j] = <span class="number">2</span>;</span><br><span class="line">        infect(m, i+<span class="number">1</span>, j, N, M);</span><br><span class="line">        infect(m, i-<span class="number">1</span>, j, N, M);</span><br><span class="line">        infect(m, i, j+<span class="number">1</span>, N, M);</span><br><span class="line">        infect(m, i, j-<span class="number">1</span>, N, M);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[][] island = <span class="keyword">new</span> <span class="keyword">int</span>[][]&#123;</span><br><span class="line">                &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>&#125;,</span><br><span class="line">                &#123;<span class="number">1</span>,<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>&#125;,</span><br><span class="line">                &#123;<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>&#125;,</span><br><span class="line">                &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>&#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        System.out.println(countIsland(island));</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>如果岛的数组很大很大，可以将数组分块来分别求数量。可能遇到分块中岛的数量之和不等于总数量的情况。可以用并查集去处理边界条件。</p><h2 id="前缀树">5 前缀树</h2><blockquote><p>新建一个头节点，对于每一个字符串，从头节点看，有没有可以到达每一个字符的路径，如果没有就新建一个路径。每一个字符表示一个路径而不是节点</p></blockquote><p><img src="Leetcode.assets/7f039fb1b7870f61.jpg" /></p><p>功能：</p><ol type="1"><li>可以查找是否有以“be”为前缀的字符串在树中</li><li>查找具体的字符串“be”是否被加入到了树中（需要添加一个属性：给每个节点添加一个计数，即以当前节点为结尾的字符串的数量。<font color = orange>如：如果树中加过“be”，那么e后的节点中的计数就变为1</font>）</li></ol><p><img src="Leetcode.assets/84e4226c3afd90b0.jpg" /></p><ol start="3" type="1"><li>以“be”为前缀的字符串有几个？（需要再添加一个属性：<font color = red>这个节点被扫过的次数</font>，每有一个以“be”为前缀的字符串生成，e后面的节点中次数就增加1次）</li></ol><p><strong>代码：</strong></p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">TrieNode</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> path;<span class="comment">//经过该节点的次数</span></span><br><span class="line">        <span class="keyword">int</span> end;<span class="comment">//以当前node为节点的次数</span></span><br><span class="line">        TrieNode[] nexts;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">TrieNode</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.path = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">this</span>.end = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">this</span>.nexts = <span class="keyword">new</span> TrieNode[<span class="number">26</span>];<span class="comment">//规定当前String中的字符都是26个英文字母（小写）</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">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Trie</span></span>&#123;</span><br><span class="line">        TrieNode root;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Trie</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.root = <span class="keyword">new</span> TrieNode();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 插入word</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> s 要插入的word</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">insert</span><span class="params">(String s)</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (s == <span class="keyword">null</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="keyword">char</span>[] chars = s.toCharArray();</span><br><span class="line">            TrieNode node = root;</span><br><span class="line">            <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;chars.length; i++) &#123;</span><br><span class="line">                index = chars[i] - <span class="string">&#x27;a&#x27;</span>;<span class="comment">//确定是nexts中的哪一条支路</span></span><br><span class="line">                <span class="keyword">if</span> (node.nexts[index] == <span class="keyword">null</span>)&#123;</span><br><span class="line">                    node.nexts[index] = <span class="keyword">new</span> TrieNode();</span><br><span class="line">                &#125;</span><br><span class="line">                node = node.nexts[index];<span class="comment">//node变为下一个节点</span></span><br><span class="line">                node.path++;<span class="comment">//这个节点被经过，path++</span></span><br><span class="line">            &#125;</span><br><span class="line">            node.end++;<span class="comment">//循环结束，此时停到的节点就是String末尾，end++</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"><span class="comment">         * <span class="doctag">@param</span> word</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">search</span><span class="params">(String word)</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (word == <span class="keyword">null</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">            TrieNode node = root;</span><br><span class="line">            <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">char</span>[] chars = word.toCharArray();</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; chars.length; i++) &#123;</span><br><span class="line">                index = chars[i]-<span class="string">&#x27;a&#x27;</span>;</span><br><span class="line">                <span class="keyword">if</span> (node.nexts[index] == <span class="keyword">null</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">                node = node.nexts[index];</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> node.end;</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">         * 删除提供的word</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> word</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">delete</span><span class="params">(String word)</span></span>&#123;</span><br><span class="line">            <span class="comment">//只有这个word存在才能删除</span></span><br><span class="line">            <span class="keyword">if</span> (search(word)!=<span class="number">0</span>)&#123;</span><br><span class="line">                TrieNode node = root;</span><br><span class="line">                <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line">                <span class="keyword">char</span>[] chars = word.toCharArray();</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; chars.length; i++) &#123;</span><br><span class="line">                    index = chars[i] - <span class="string">&#x27;a&#x27;</span>;</span><br><span class="line">                    node = node.nexts[index];</span><br><span class="line">                    <span class="comment">//将经过node的次数-1</span></span><br><span class="line">                    node.path--;</span><br><span class="line">                    <span class="comment">//如果删除之后，经过当前节点的次数==0，说明没有word会经过此节点了，直接指向null</span></span><br><span class="line">                    <span class="keyword">if</span> (node.path == <span class="number">0</span>)&#123;</span><br><span class="line">                        node = <span class="keyword">null</span>;</span><br><span class="line">                        <span class="keyword">return</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                node.end--;</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="comment">         * 给定前缀的出现次数</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@param</span> prefix 提供的前缀</span></span><br><span class="line"><span class="comment">         * <span class="doctag">@return</span> 前缀在树中的出现次数</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">prefixNum</span><span class="params">(String prefix)</span></span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (prefix == <span class="keyword">null</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">            TrieNode node = root;</span><br><span class="line">            <span class="keyword">int</span> index = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">char</span>[] chars = prefix.toCharArray();</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; chars.length; i++) &#123;</span><br><span class="line">                index = chars[i] - <span class="string">&#x27;a&#x27;</span>;</span><br><span class="line">                <span class="keyword">if</span> (node.nexts[index] == <span class="keyword">null</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">                node = node.nexts[index];</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> node.path;</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">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Trie tree = <span class="keyword">new</span> Trie();</span><br><span class="line">        tree.insert(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        tree.insert(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        tree.insert(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        tree.insert(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        tree.insert(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        tree.insert(<span class="string">&quot;root&quot;</span>);</span><br><span class="line"></span><br><span class="line">        tree.delete(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        tree.delete(<span class="string">&quot;root&quot;</span>);</span><br><span class="line">        tree.delete(<span class="string">&quot;root&quot;</span>);</span><br><span class="line"></span><br><span class="line">        tree.insert(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">        tree.insert(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line">        tree.insert(<span class="string">&quot;hello&quot;</span>);</span><br><span class="line"></span><br><span class="line">        tree.insert(<span class="string">&quot;this&quot;</span>);</span><br><span class="line">        System.out.println(tree.search(<span class="string">&quot;root&quot;</span>)); <span class="comment">//3</span></span><br><span class="line">        System.out.println(tree.search(<span class="string">&quot;hello&quot;</span>));<span class="comment">//3</span></span><br><span class="line">        System.out.println(tree.search(<span class="string">&quot;this&quot;</span>));<span class="comment">//1</span></span><br><span class="line">        System.out.println(tree.prefixNum(<span class="string">&quot;ro&quot;</span>));<span class="comment">//6</span></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>算法中的结构：</p><p><img src="Leetcode.assets/dacccc71763ff591.jpg" /></p><ul><li>每个节点中包含变量 path 和变量 end，一个节点数组，数组的每一个位置代表一个字符</li><li>每个节点选择数组中的某一个节点作为next（如上图中，选择的路径为 a -&gt; c ），没有被选择的节点即为 null</li><li>每经过一个节点的时候，path++， 遍历完整个word，当前节点即为word结尾的节点，end++， path++</li><li>删除的时候，将path - -， 对于最后一个节点，end - -，如果当前节点的path已经被减为0，当前节点直接指向null</li></ul><h2 id="贪心策略">6 贪心策略</h2><blockquote><p>字典序：当长度相等的时候，按顺序比较每一位的ascii值；当长度不相等的时候，将短的补齐（用最小的字面值），在按照每一位的ascii码比较</p><p>贪心策略：</p><ul><li>将问题分为一些子问题</li><li>对每个子问题求出局部最优解</li><li>将局部最优解整合，得到全局最优解</li></ul></blockquote><p><strong>题目</strong>：有一个字符串数组，将其中的每一项拼接在一起形成一个大的字符串，要求形成的字符串字典序最小。例如 {"ab","cd","ef"}，拼成的最小字典序的字符串是“abcdef”</p><p><strong>错误的解法：</strong></p><p>将所有的字符串排好序（按照字典序），再按照顺序拼接起来。<font color = red>错误的原因："b"和"ba"，按照字典序为"b, ba"，但是拼接后的结果为"bba"，其字典序是小于"bab"的</font></p><p><strong>正确的解法：利用贪心</strong></p><p>String1和String2拼接：如果（String1+String2）&lt;（String2+String1），则String1放前面，否则String2放前面</p><p>（在每两个String排序的时候，就可以实现局部最优的顺序）</p><p>贪心策略的正确性：</p><ol type="1"><li>需要用数学方法证明两两比较具有可传递性（排序策略具有可传递性）</li><li>证明拼接之后的字符串的字典序是最小的（任意子串的位置交换之后都会得到更大的字典序）</li><li>3，3交换，4，4交换类比于两两交换</li></ol><blockquote><p>贪心策略的问题，要把重点放在贪心的策略上，而不是寻找方法去证明贪心策略的正确性，可以用对数器去证明结果的正确性，因为贪心策略的证明非常之难</p></blockquote><h3 id="金条题目哈夫曼编码问题">6.1 金条题目（哈夫曼编码问题）</h3><p><img src="Leetcode.assets/f2c51427939e1bcc.png" /></p><p><strong>算法：</strong></p><ol type="1"><li>先将数组所有内容构建出一个小根堆</li><li>取出小根堆中最小的两个元素，堆中的两个元素删除</li><li>将两个元素相加，将结果加回小根堆（记录此结果为一个代价）</li><li>继续重复2-4步操作</li><li>直到小根堆中只有一个元素，将所有代价相加即是整个方法的总代价</li></ol><blockquote><p>哈夫曼算法就是将数组中的元素按照完美二叉树的要求构建，（代价小的距离根节点较远，代价大的距离根节点近），将其中所有的非叶节点的代价相加即是整个方法的代价<font color = red>当总共的代价等于局部代价之和的时候（本题），就首先考虑使用哈夫曼编码</font></p></blockquote><p><strong>代码：</strong></p><figure class="highlight java"><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="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MinCostComparator</span> <span class="keyword">implements</span> <span class="title">Comparator</span>&lt;<span class="title">Integer</span>&gt;</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Integer o1, Integer o2)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> o1 - o2;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">//如果不添加比较器，那么默认的排序就是大根堆</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">lessMoney</span><span class="params">(<span class="keyword">int</span>[] nums)</span></span>&#123;</span><br><span class="line">        <span class="comment">//构造小根堆</span></span><br><span class="line">        PriorityQueue&lt;Integer&gt; queue = <span class="keyword">new</span> PriorityQueue&lt;&gt;(<span class="keyword">new</span> MinCostComparator());</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; nums.length; i++) &#123;</span><br><span class="line">            queue.add(nums[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">int</span> result = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(queue.size()&gt;<span class="number">1</span>)&#123;</span><br><span class="line">            result = result + queue.poll()+queue.poll();</span><br><span class="line">            queue.add(result);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="利润最大">6.2 利润最大</h3><blockquote><p>你要完成K个项目：所有项目的花费和利润都存储在两个数组中：</p><p>cost[x, x, x, x, x, x]</p><p>profit[x, x, x, x, x, x]</p><p>i = 0,1,2,3,4,5,6</p><p>现在又启动资金W，每一次只能选择一个项目，比如，如果我第一次选择了i=0项目，</p><p>cost = 40， profit = 30， W = 100；那么第一次完成项目之后，我手中的资金变成了130，我就可以接下来去选择cost&lt;=130的项目了</p><p>在只能进行K次项目的情况下，求该如何选择项目，使得利润最大</p></blockquote><p><strong>算法：</strong></p><ol type="1"><li>准备一个小根堆，按照项目的cost为依据进行构建，小根堆的顶部就是cost最小的项目</li><li>将堆顶满足低于启动资金的项目都弹出，构建一个大根堆，大根堆的顶部就是在满足要求的前提下收益最大的项目</li><li>弹出大根堆的顶点，这个顶点即是当下要做的项目。之后启动资金W被更新（因为当前项目的收益）</li><li>向小根堆中加入新的项目（因为W的的变化，新的项目会被解锁）</li></ol><p><img src="Leetcode.assets/9d410f3fb053be6b.jpg" /></p><p><font color = red >当更新过的启动资金不能再解锁新的项目了，这时候就不会有新的项目加入到大根堆中，算法就只能结束</font></p><p>代码：</p><figure class="highlight java"><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></pre></td><td class="code"><pre><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="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> cost;</span><br><span class="line">        <span class="keyword">int</span> profit;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Node</span><span class="params">(<span class="keyword">int</span> cost, <span class="keyword">int</span> profit)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.cost = cost;</span><br><span class="line">            <span class="keyword">this</span>.profit = profit;</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">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MinCostComparator</span> <span class="keyword">implements</span> <span class="title">Comparator</span>&lt;<span class="title">Node</span>&gt;</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Node o1, Node o2)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> o1.cost-o2.cost;<span class="comment">//小的放前面</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">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MaxProfitComparator</span> <span class="keyword">implements</span> <span class="title">Comparator</span>&lt;<span class="title">Node</span>&gt;</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Node o1, Node o2)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> o2.profit-o1.profit;<span class="comment">//大的放前面</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">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">findMaxCapital</span><span class="params">(<span class="keyword">int</span> k, <span class="keyword">int</span> W, <span class="keyword">int</span>[] profit, <span class="keyword">int</span>[] cost)</span></span>&#123;</span><br><span class="line">        Node[] projects = <span class="keyword">new</span> Node[profit.length];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; profit.length; i++) &#123;</span><br><span class="line">            projects[i] = <span class="keyword">new</span> Node(cost[i],profit[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//构建小顶堆</span></span><br><span class="line">        PriorityQueue&lt;Node&gt; minCostHeap = <span class="keyword">new</span> PriorityQueue&lt;&gt;(<span class="keyword">new</span> MinCostComparator());</span><br><span class="line">        <span class="comment">//构建大顶堆</span></span><br><span class="line">        PriorityQueue&lt;Node&gt; maxProfitHeap = <span class="keyword">new</span> PriorityQueue&lt;&gt;(<span class="keyword">new</span> MaxProfitComparator());</span><br><span class="line">        <span class="comment">//将所有项目添加到小顶堆中</span></span><br><span class="line">        minCostHeap.addAll(Arrays.asList(projects));</span><br><span class="line">        <span class="comment">//保证总项目数不超过k</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; k; i++) &#123;</span><br><span class="line">            <span class="comment">//一旦小顶堆不空，且小根堆顶的cost不大于W，就将这个项目添加到大根堆</span></span><br><span class="line">            <span class="keyword">while</span>(!minCostHeap.isEmpty()&amp;&amp;minCostHeap.peek().cost&lt;=W)&#123;</span><br><span class="line">                maxProfitHeap.add(minCostHeap.poll());</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//如果此时大根堆空掉了，返回当前的W</span></span><br><span class="line">            <span class="keyword">if</span> (maxProfitHeap.isEmpty())&#123;</span><br><span class="line">                <span class="keyword">return</span> W;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//如果没有空，就取出大根堆的顶（利润最高的项目），收益加给W</span></span><br><span class="line">            W += maxProfitHeap.poll().profit;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> W;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="会议室的日程">6.3 会议室的日程</h3><p><img src="Leetcode.assets/7332cdd33cd22813.png" /></p><p><strong>算法：</strong></p><ul><li>贪心策略：哪个项目早结束就先安排哪个项目，然后淘汰掉因为这个项目而不能进行的项目</li></ul><figure class="highlight java"><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 class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Program</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> start;</span><br><span class="line">        <span class="keyword">int</span> end;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Program</span><span class="params">(<span class="keyword">int</span> start, <span class="keyword">int</span> end)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.start = start;</span><br><span class="line">            <span class="keyword">this</span>.end = end;</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="comment">     * 按照项目的终止时间来设定比较器</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ProgramComparator</span> <span class="keyword">implements</span> <span class="title">Comparator</span>&lt;<span class="title">Program</span>&gt;</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Program o1, Program o2)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> o1.end - o2.end;</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="comment">     * 求出在一天之内会议室可以安排的宣讲会的最大数量</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> programs 包含所有宣讲会的数组</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> current 当前时刻</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 返回可以安排的宣讲会的数量</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">bestArrange</span><span class="params">(Program[] programs, <span class="keyword">int</span> current)</span></span>&#123;</span><br><span class="line">        Arrays.sort(programs, <span class="keyword">new</span> ProgramComparator());</span><br><span class="line">        <span class="keyword">int</span> result = <span class="number">0</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; programs.length; i++) &#123;</span><br><span class="line">            <span class="comment">//只有满足在当前时间之后开始的项目才可以被安排</span></span><br><span class="line">            <span class="keyword">if</span> (current&lt;=programs[i].start)&#123;</span><br><span class="line">                result++;</span><br><span class="line">                current = programs[i].end;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h2 id="递归和动态规划">7 递归和动态规划</h2><p>递归：（<font color = red>递归代表尝试</font>）</p><ol type="1"><li>把问题转化为规模缩小了的同类子问题</li><li>有明确的不需要继续进行递归的条件（base case）</li><li>有当得到了子问题的结果之后的决策过程</li><li>不记录每一个子问题的解</li></ol><p>动态规划：（<font color = red>用于优化暴力递归</font>）</p><ol type="1"><li>从暴力递归中来</li><li>将每一个子问题的解记录下来，避免重复计算</li><li>把暴力递归过程抽象成状态表达</li><li>并且存在化简状态表达，使其更加简洁的可能</li></ol><p>递归代表的问题就是，不知道具体怎么算，但是知道怎么尝试</p><p><strong>P = NP问题：</strong></p><blockquote><p>P代表：有具体的计算方法（多项式时间内可以解决的问题）；</p><p>NP代表：可以进行尝试的问题（非确定性多项式时间可以解决的问题），不知道怎么算，但是知道怎么尝试</p><p>P问题举例：</p><p><strong>计算1-1000的连续整数之和</strong>：这个问题就比较简单，无论是编程还是使用高斯求和公式都可以在有限可接受的时间内完成，这种算是P类问题。</p><p>NP问题举例：</p><p><strong>计算地球上所有原子个数之和</strong>：这个问题就很困难甚至无解，但是现在有个答案是300个，显然是错的，所以很容易验证但不容易求解，这种算NP类问题。</p></blockquote><h3 id="暴力递归">7.1 暴力递归</h3><h4 id="n问题">7.1.1 n！问题</h4><h4 id="汉诺塔问题">7.1.2 汉诺塔问题</h4><p><strong>算法：</strong></p><ol type="1"><li>准备三个杆：from， to， help（from上有n个圆盘，要全部移动到to上，借助help实现）</li><li>步骤：<ol type="1"><li>将1~n-1移动到help上</li><li>将n移动到to上</li><li>再将1~n-1移动到to上</li></ol></li></ol><p><strong>代码：</strong></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HanoiTower</span> </span>&#123;</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"><span class="comment">     * <span class="doctag">@param</span> N 问题的规模（一共N个圆片）</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> from 最开始所有圆片都在的柱子</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> to 最后所有圆片要前往的柱子</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> help 用于辅助操作的柱子</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">process</span><span class="params">(<span class="keyword">int</span> N, String from, String to, String help)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (N == <span class="number">1</span>)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;move 1 from &quot;</span>+from+<span class="string">&quot; to&quot;</span>+to);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        process(N-<span class="number">1</span>, from, help, to);</span><br><span class="line">        System.out.println(<span class="string">&quot;move &quot;</span>+N+<span class="string">&quot; from &quot;</span>+from+<span class="string">&quot; to&quot;</span>+to);</span><br><span class="line">        process(N-<span class="number">1</span>, help, to, from);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        process(<span class="number">3</span>, <span class="string">&quot;柱子1&quot;</span>, <span class="string">&quot;柱子3&quot;</span>, <span class="string">&quot;柱子2&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="打印字符串所有的子序列包括空字符串">7.1.2 打印字符串所有的子序列，包括空字符串</h4><p><strong>代码：</strong></p><figure class="highlight java"><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="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SubStrings</span> </span>&#123;</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 class="doctag">@param</span> strs 字符串转成的字符数组</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> i 当前指针的位置</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> result 返回的字符串结果</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printAllSub</span><span class="params">(<span class="keyword">char</span>[] strs, <span class="keyword">int</span> i, String result)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(i == strs.length)&#123;</span><br><span class="line">            System.out.println(result);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        printAllSub(strs, i+<span class="number">1</span>, result);</span><br><span class="line">        printAllSub(strs, i+<span class="number">1</span>, result+strs[i]);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        String s = <span class="string">&quot;abcde&quot;</span>;</span><br><span class="line">        <span class="keyword">char</span>[] chars = s.toCharArray();</span><br><span class="line">        printAllSub(chars, <span class="number">0</span>, <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></pre></td></tr></table></figure><p><strong>算法：</strong></p><ol type="1"><li>如果字符串指针指到了最后一位的下一位，说明已经遍历完毕，直接返回当前的结果</li><li>每个位置上有两种情况：打印当前位置的字符 / 不打印当前位置的字符</li></ol><p><img src="Leetcode.assets/ad45e4b4d8030b06.jpg" /></p><h4 id="字符串的全排列">7.1.4 字符串的全排列</h4><h4 id="母牛问题">7.1.5 母牛问题</h4><p><img src="Leetcode.assets/6f4be909c94c4393.png" /></p><p><strong>尝试：</strong></p><p><img src="Leetcode.assets/603e2e379f2326e5.jpg" /></p><p><strong>证明递归逻辑的正确性：</strong></p><p>今年的牛 = 去年的牛的数量（因为牛不会死，会被完整地保留下来）+ 三年前的牛的数量（因为三年前的牛在今年会全部成熟，每一头都会贡献一只小牛）</p><p>将O(2<sup>N</sup>)复杂度转化为O(log<sub>2</sub>n)的方法：</p><p><img src="https://i.loli.net/2020/12/30/dAfmbSH5YchkTvg.png" alt="2020-12-30_12-29-18" style="zoom:50%;" /></p><p>问题从此被转化为O(log<sub>2</sub>N)的规模：</p><p>如何进行矩阵的==快速==幂运算：</p><p><img src="https://i.loli.net/2020/12/30/jMixX3oQVNZvFq5.png" alt="2020-12-30_12-49-15" style="zoom:50%;" /></p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">long</span> <span class="title">countCows</span><span class="params">(<span class="keyword">long</span> n)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(n&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 class="keyword">if</span>(n == <span class="number">1</span> || n==<span class="number">2</span> || n==<span class="number">3</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> n;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">long</span>[][] base = &#123;&#123;<span class="number">1</span>,<span class="number">1</span>,<span class="number">0</span>&#125;,&#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">1</span>&#125;,&#123;<span class="number">1</span>,<span class="number">0</span>,<span class="number">0</span>&#125;&#125;;</span><br><span class="line">        <span class="keyword">long</span>[][] res = matrixPow(base, n-<span class="number">3</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">3</span>*res[<span class="number">0</span>][<span class="number">0</span>]+<span class="number">2</span>*res[<span class="number">1</span>][<span class="number">0</span>]+res[<span class="number">2</span>][<span class="number">0</span>];</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//求矩阵m的n次方</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">long</span>[][] matrixPow(<span class="keyword">long</span>[][] m, <span class="keyword">long</span> n)&#123;</span><br><span class="line">        <span class="keyword">long</span>[][] res = <span class="keyword">new</span> <span class="keyword">long</span>[m.length][m[<span class="number">0</span>].length];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;res.length; i++)&#123;</span><br><span class="line">            res[i][i] = <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">long</span>[][] temp = m;</span><br><span class="line">        <span class="keyword">while</span>(n!=<span class="number">0</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span>((n&amp;<span class="number">1</span>)==<span class="number">1</span>)&#123;</span><br><span class="line">                res = dotProduct(res, temp);<span class="comment">//只有当前位上为1的时候，才将自乘后的m乘到res上</span></span><br><span class="line">            &#125;</span><br><span class="line">            temp = dotProduct(temp, temp);<span class="comment">//m自乘</span></span><br><span class="line">            n&gt;&gt;=<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">        </span><br><span class="line">        </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">public</span> <span class="keyword">static</span> <span class="keyword">long</span>[][] dotProduct(<span class="keyword">long</span>[][] m1, <span class="keyword">long</span>[][] m2)&#123;</span><br><span class="line">        <span class="keyword">long</span>[][] res = <span class="keyword">new</span> <span class="keyword">long</span>[m1.length][m2[<span class="number">0</span>].length];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;m1.length; i++)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j&lt;m2[<span class="number">0</span>].length; j++)&#123;</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> k = <span class="number">0</span>; k&lt;m2.length; k++)&#123;</span><br><span class="line">                    res[i][j] += m1[i][k]*m2[k][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 class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p><font color = red>这种题就是先试几个情况，然后找规律</font></p><h4 id="路径和问题">7.1.5 路径和问题</h4><blockquote><p>所有没做过的动态规划问题都可以先写出暴力递归的尝试版本，再优化成为动态规划</p></blockquote><p><img src="https://ftp.bmp.ovh/imgs/2020/12/112242b9527de50b.png" /></p><p>暴力递归：其中包含了重复的状态，造成了计算上的不必要的浪费</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 从当前位置i，j到右下角的最短路径和</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> matrix 要行走的矩阵</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> i 行位置</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> j 列位置</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 最短路径和</span></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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">walk</span><span class="params">(<span class="keyword">int</span>[][] matrix, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">        <span class="comment">//如果已经到达了右下角位置</span></span><br><span class="line">        <span class="keyword">if</span>(i == matrix.length-<span class="number">1</span> &amp;&amp; j == matrix[<span class="number">0</span>].length-<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> matrix[i][j];</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>(i == matrix.length-<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> matrix[i][j]+walk(matrix, i, j+<span class="number">1</span>);</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>(j == matrix[<span class="number">0</span>].length-<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> matrix[i][j]+walk(matrix, i+<span class="number">1</span>, j);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//向右寻找最短路径和</span></span><br><span class="line">        <span class="keyword">int</span> right = walk(matrix, i, j+<span class="number">1</span>);</span><br><span class="line">        <span class="comment">//向左寻找最短路径和</span></span><br><span class="line">        <span class="keyword">int</span> down = walk(matrix, i+<span class="number">1</span>, j);</span><br><span class="line">        <span class="keyword">return</span> matrix[i][j]+Math.min(right, down);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span>[][] matrix = &#123;</span><br><span class="line">                &#123;<span class="number">1</span>,<span class="number">3</span>,<span class="number">5</span>,<span class="number">9</span>&#125;,</span><br><span class="line">                &#123;<span class="number">8</span>,<span class="number">1</span>,<span class="number">3</span>,<span class="number">4</span>&#125;,</span><br><span class="line">                &#123;<span class="number">5</span>,<span class="number">0</span>,<span class="number">6</span>,<span class="number">1</span>&#125;,</span><br><span class="line">                &#123;<span class="number">8</span>,<span class="number">8</span>,<span class="number">4</span>,<span class="number">0</span>&#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        System.out.println(walk(matrix, <span class="number">0</span>,<span class="number">0</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">方法二：使用dp数组：</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        Scanner in = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">        <span class="keyword">int</span> row = in.nextInt();</span><br><span class="line">        <span class="keyword">int</span> col = in.nextInt();</span><br><span class="line">        <span class="keyword">int</span>[][] m = <span class="keyword">new</span> <span class="keyword">int</span>[row][col];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i&lt;row; i++)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">0</span>; j&lt;col; j++)&#123;</span><br><span class="line">                m[i][j] = in.nextInt();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(getMinPath2(m));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line"><span class="comment">//使用二维dp数组，占用空间较大，但是适用于需要求解出具体路径的dp问题</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">getMinPath</span><span class="params">(<span class="keyword">int</span>[][] m)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(m == <span class="keyword">null</span> || m.length == <span class="number">0</span> || m[<span class="number">0</span>] == <span class="keyword">null</span> || m[<span class="number">0</span>].length == <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">int</span> row = m.length;</span><br><span class="line">        <span class="keyword">int</span> col = m[<span class="number">0</span>].length;</span><br><span class="line">        <span class="keyword">int</span>[][] dp = <span class="keyword">new</span> <span class="keyword">int</span>[row][col];</span><br><span class="line">        dp[<span class="number">0</span>][<span class="number">0</span>] = m[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;row; i++)&#123;</span><br><span class="line">            dp[i][<span class="number">0</span>] = dp[i-<span class="number">1</span>][<span class="number">0</span>]+m[i][<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>(<span class="keyword">int</span> j = <span class="number">1</span>; j&lt;col; j++)&#123;</span><br><span class="line">            dp[<span class="number">0</span>][j] = dp[<span class="number">0</span>][j-<span class="number">1</span>]+m[<span class="number">0</span>][j];</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;row; i++)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j&lt;col; j++)&#123;</span><br><span class="line">                dp[i][j] = Math.min(dp[i-<span class="number">1</span>][j], dp[i][j-<span class="number">1</span>])+m[i][j];</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> dp[row-<span class="number">1</span>][col-<span class="number">1</span>];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line"><span class="comment">//使用一维dp数组，可以重复使用，占用空间较小，不适用于求解具体路径的dp问题，但是可以适用于求出最短路径数值的问题</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">getMinPath2</span><span class="params">(<span class="keyword">int</span>[][] m)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(m == <span class="keyword">null</span> || m.length == <span class="number">0</span> || m[<span class="number">0</span>] == <span class="keyword">null</span> || m[<span class="number">0</span>].length == <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">int</span> less = Math.min(m.length, m[<span class="number">0</span>].length);</span><br><span class="line">        <span class="keyword">int</span> more = Math.max(m.length, m[<span class="number">0</span>].length);</span><br><span class="line">        <span class="comment">//判断较大的数据是行还是列</span></span><br><span class="line">        <span class="keyword">boolean</span> moreIsRow = more == m.length;</span><br><span class="line">        <span class="keyword">int</span>[] dp = <span class="keyword">new</span> <span class="keyword">int</span>[less];<span class="comment">//dp数组只需要和短边一样长就好了</span></span><br><span class="line">        dp[<span class="number">0</span>] = m[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;less; i++)&#123;</span><br><span class="line">            dp[i] = dp[i-<span class="number">1</span>] + (moreIsRow?m[<span class="number">0</span>][i]:m[i][<span class="number">0</span>]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">1</span>; i&lt;more; i++)&#123;</span><br><span class="line">            dp[<span class="number">0</span>] = dp[<span class="number">0</span>] + (moreIsRow?m[i][<span class="number">0</span>]:m[<span class="number">0</span>][i]);</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> j = <span class="number">1</span>; j&lt;less; j++)&#123;</span><br><span class="line">                dp[j] = Math.min(dp[j-<span class="number">1</span>], dp[j])+(moreIsRow?m[i][j]:m[j][i]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dp[less-<span class="number">1</span>];</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p><img src="https://ftp.bmp.ovh/imgs/2020/12/01f2622785d0a1ef.jpg" /></p><blockquote><p>无后效性问题可以改成动态规划（在本题中，每一个位置的返回值都是确定的，不论该位置是怎么被达到的）</p></blockquote><p><strong>算法（暴力递归改成动态规划）：</strong></p><ol type="1"><li>设置好边界位置（base case）：右下角；右边界； 下边界</li><li>绘制dp图</li><li>对于普遍位置：当前位置可以由下一个右侧位置和下一个下侧位置求出，看看当前的普遍位置需要依赖什么位置，逆回去就是动态规划的路径</li></ol><h4 id="累加问题">7.1.6 累加问题</h4><p><img src="https://ftp.bmp.ovh/imgs/2020/12/32db4930222cca14.png" /></p><p><strong>算法：</strong></p><ol type="1"><li>尝试版本</li><li>列出可变参数的变化范围</li><li>终止位置是什么</li><li>base case提前填好</li><li>由普遍位置推出它所依赖的位置</li></ol><h1 id="字符串问题">字符串问题</h1><h2 id="kmp算法">1 KMP算法</h2><p>区分子序列和子串：子序列不一定连续，子串一定连续</p><ol type="1"><li>求每一个位置上的字符：其前面字符串的最长前缀和最长后缀（前缀不包含最后一位，后缀不包含第一位）的最长匹配位数</li></ol><p><img src="%E5%9B%BE%E7%89%87/2020-12-29_08-59-52.jpg" alt="2020-12-29_08-59-52" style="zoom: 50%;" /></p><ol start="2" type="1"><li><p>找到String1中和String2中不匹配的第一个字符，计算String2中最长匹配的前后缀：</p><p><img src="https://i.loli.net/2020/12/29/waPgIklxp8oAO6G.png" alt="2020-12-29_09-16-10" style="zoom:50%;" /></p></li><li><p>从String1中找到对应String2中后缀开端的位置，将String2推过去，起点重合，再从后缀结束的下一个位置开始匹配：</p><p><img src="https://i.loli.net/2020/12/29/qderZzHYlGcLaAI.png" alt="image-20201229092738531" style="zoom: 33%;" /></p></li></ol><blockquote><p>本质：我们在继续尝试从J位置开始的匹配情况，==并且已经可以保证 J之前的位置全部没有匹配上==</p></blockquote><p><strong>寻找next数组</strong>：假设最长相等前后缀长度为LPP</p><ol type="1"><li><p>设当前位置是 i 位置，目前已知 i-1位置的==LPP==为n，比较==i-1位置的前缀的下一位==是否和==i-1位置==的字符相等</p></li><li><p>如果相等：当前位置的==LPP== = cn++ （如果跳到了cn位置，那么cn位置之前回有cn个字符，也就是i-1位置的==LPP==）</p><p><img src="https://i.loli.net/2020/12/29/n17Q9fMIYdOWE6c.png" alt="2020-12-29_11-37-52" style="zoom: 50%;" /></p></li><li><p>如果不相等，cn继续跳到next[cn]的位置，进行上述操作</p><p><img src="https://i.loli.net/2020/12/29/pyIlcHn7XvjLOR6.png" alt="2020-12-29_11-24-44" style="zoom:50%;" /></p></li><li><p>如果cn已经等于0都不能达到步骤2的相等，则 i 位置的值为0</p><p><img src="https://i.loli.net/2020/12/29/eBCuxFov82qzIYs.png" alt="2020-12-29_11-30-41" style="zoom:50%;" /></p></li></ol><p>代码：</p><figure class="highlight java"><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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">KMP</span><span class="params">(String str1, String str2)</span></span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (str1 == <span class="keyword">null</span> || str2 == <span class="keyword">null</span> || str1.length()&lt;<span class="number">1</span> || str1.length()&lt;str2.length() || str2.length()&lt;<span class="number">1</span>)&#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="keyword">char</span>[] s1 = str1.toCharArray();</span><br><span class="line">        <span class="keyword">char</span>[] s2 = str2.toCharArray();</span><br><span class="line">        <span class="comment">//得到str2的next数组</span></span><br><span class="line">        <span class="keyword">int</span>[] next = getNextArray(s2);</span><br><span class="line">        <span class="comment">//两个指针，分别指向str1和str2当前比较的位置</span></span><br><span class="line">        <span class="keyword">int</span> p1 = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> p2 = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span>(p1&lt;str1.length() &amp;&amp; p2&lt;str2.length())&#123;</span><br><span class="line">            <span class="keyword">if</span> (s1[p1] == s2[p2])&#123;</span><br><span class="line">                p1++;</span><br><span class="line">                p2++;</span><br><span class="line">            &#125;<span class="keyword">else</span> &#123;<span class="comment">//当前位置不匹配了</span></span><br><span class="line">                <span class="keyword">if</span> (next[p2] == -<span class="number">1</span>)&#123;<span class="comment">//如果已经到了str2的第一个字符还没有匹配</span></span><br><span class="line">                    p1++;<span class="comment">//就继续尝试str1的下一个字符</span></span><br><span class="line">                &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">                    p2 = next[p2];<span class="comment">//指针指向str2前缀的下一个位置</span></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> p2 == str2.length()?p1-p2:-<span class="number">1</span>;<span class="comment">//如果，p2跑完了整个str2，说明匹配完毕，此时p1肯定也停在str2的末尾，则开始位置就是p1-p2</span></span><br><span class="line">        <span class="comment">//否则说明两个字符串没有匹配上，返回-1</span></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span>[] getNextArray(<span class="keyword">char</span>[] str2)&#123;</span><br><span class="line">        <span class="keyword">if</span> (str2.length == <span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="keyword">int</span>[]&#123;-<span class="number">1</span>&#125;;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//要返回的next数组</span></span><br><span class="line">        <span class="keyword">int</span>[] next = <span class="keyword">new</span> <span class="keyword">int</span>[str2.length];</span><br><span class="line">        next[<span class="number">0</span>] = -<span class="number">1</span>;<span class="comment">//认为规定：0位置上的值为-1</span></span><br><span class="line">        next[<span class="number">1</span>] = <span class="number">0</span>;<span class="comment">//因为前后缀不包括前缀的最后一个数和后缀的第一个数，所以这里唯一的一个数不属于前缀和后缀，值为0；</span></span><br><span class="line">        <span class="keyword">int</span> i = <span class="number">2</span>;<span class="comment">//从第二个位置开始遍历</span></span><br><span class="line">        <span class="keyword">int</span> cn = <span class="number">0</span>;<span class="comment">//跳跃到的位置：</span></span><br><span class="line">        <span class="keyword">while</span> (i&lt;str2.length) &#123;</span><br><span class="line">            <span class="keyword">if</span> (str2[i - <span class="number">1</span>] == str2[cn]) &#123;<span class="comment">//如果当前位置的上一个位置和cn指向的位置相等，cn++， 且当前位置值=cn</span></span><br><span class="line">                next[i++] = ++cn;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (cn &gt; <span class="number">0</span>) &#123;<span class="comment">//如果当前位置的上一个位置和cn指向的位置不相等，cn跳到next[cn]</span></span><br><span class="line">                cn = next[cn];</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;<span class="comment">//如果不相等且cn==0，则i位置的值也为0</span></span><br><span class="line">                next[i++] = <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> next;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>应用：</p><p><strong>1. 一道京东面试题：</strong></p><figure class="highlight plaintext"><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><br><span class="line">比如：</span><br><span class="line">String1 = &quot;abcabc&quot;    得到的大字符串为：&quot;abcabcabc&quot;</span><br><span class="line">String1 = &quot;abcbab&quot;    得到的大字符串为：&quot;abcbabcbab&quot;</span><br><span class="line"></span><br><span class="line">算法：利用KMP中求next数组的方法：</span><br><span class="line">求出每一位的LPP值，最后再求出终止位（string1的末尾的下一位的LPP值），这个值就在说明整个字符串的前后缀重复的长度，</span><br><span class="line">只要如下操作：</span><br><span class="line">abcb|ab|</span><br><span class="line">    |ab|cbab</span><br><span class="line">这样错位对上，补足后面的cbab就可以了===&gt;abcbabcbab</span><br></pre></td></tr></table></figure><p><strong>2. 判断子树问题</strong></p><figure class="highlight plaintext"><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">判断Tree1是不是Tree2的子树：</span><br><span class="line">算法：</span><br><span class="line">1. 先将两棵树序列化，</span><br><span class="line">2. 如果Tree1的序列化字符串是Tree2序列化字符串的子串，则Tree2中必定包含Tree1</span><br></pre></td></tr></table></figure><p><strong>3. 判断一个String是不是由某一个子串重复得到的</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">abcabcabcabc</span><br></pre></td></tr></table></figure><h2 id="manahcer-算法">2. Manahcer 算法</h2><blockquote><p>从一个字符串中找到最长的回文子串</p></blockquote><p><strong>暴力解法：</strong></p><figure class="highlight plaintext"><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">比如：11311这个字符串：</span><br><span class="line">向其中加入特殊字符将他们分开：#1#1#3#1#1#</span><br><span class="line">遍历整个字符串，以每一个字符为中心向两边扩展（直到某一边扩展到边缘），</span><br><span class="line"># 1 # 1 # 3  # 1 # 1 #</span><br><span class="line">1 3 5 3 1 11 1 3 5 3 1</span><br><span class="line">得到的最长长度除以二就是最大回文串的长度</span><br><span class="line">（时间复杂度为O(n^2)）</span><br></pre></td></tr></table></figure><p><strong>Manacher算法：</strong></p><p>概念：</p><blockquote><ol type="1"><li>回文直径</li><li>回文半径</li><li>回文半径数组：将每个位置的回文半径存在数组中</li><li>最右回文右边界</li><li>当前回文右边界对应的中心（记录第一次到达该右边界的中心）</li></ol></blockquote><p>情况讨论：</p><figure class="highlight plaintext"><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">1. i在最右边界的外面，最右边界向右扩张O(n)</span><br><span class="line">2. i在最右边界的内部，三种情况：</span><br><span class="line">（1）i的对称i&#x27;的左边界（小L）在L的内部：[ (...^...) C ...^... ]    则i所在位置的半径就是i&#x27;的半径O(1)</span><br><span class="line">                                     L l   i&#x27;  r      i    R</span><br><span class="line">（2）i的对称i&#x27;的左边界（小L）在L的外面：(...[ ^...) C ...^ ]       则i所在位置的半径就是R-i  O(1)</span><br><span class="line">                                     l   L i&#x27;  r      i R</span><br><span class="line">（3）i的对称i&#x27;的左边界（小L）在L的上面（重合）： [...^...) C ...^... ]  则从i到R可以不用验证了，R后面的需要继续验证（验证i的回文半径需不需要扩张）O(n)</span><br><span class="line">                                             Ll  i&#x27;  r      i    R                                    </span><br><span class="line">                                             </span><br></pre></td></tr></table></figure><p>总的时间复杂度是O(n)</p><p><strong>应用：</strong></p><ol type="1"><li>只向字符串末尾添加字符串，怎么让字符串成为回文串，要求添加的字符最少</li></ol><figure class="highlight plaintext"><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">比如：abc12321-----&gt;abc12321cba</span><br><span class="line"></span><br><span class="line">算法：</span><br><span class="line">1. 求出在必须包含最后一位的前提下，最长回文串（12321）</span><br><span class="line">2. 再将不属于回文串内部的部分（abc）逆序加上去（cba）</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;leetcode&quot;&gt;Leetcode&lt;/h1&gt;
&lt;h2 id=&quot;array&quot;&gt;Array&lt;/h2&gt;
&lt;h3 id=&quot;摩尔投票&quot;&gt;摩尔投票&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;题目背景：从一个数组中找到关键元素（关键元素的数量大于数组中元素总数的一半）&lt;/p&gt;</summary>
      
    
    
    
    
    <category term="LeetCode" scheme="http://example.com/tags/LeetCode/"/>
    
  </entry>
  
  <entry>
    <title>【LeetCode】 343.剪绳子2</title>
    <link href="http://example.com/2021/08/21/%E3%80%90LeetCode%E3%80%91-343-%E5%89%AA%E7%BB%B3%E5%AD%902-md/"/>
    <id>http://example.com/2021/08/21/%E3%80%90LeetCode%E3%80%91-343-%E5%89%AA%E7%BB%B3%E5%AD%902-md/</id>
    <published>2021-08-21T05:51:51.000Z</published>
    <updated>2021-08-21T06:46:49.113Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>给你一根长度为 n 的绳子，请把绳子剪成整数长度的 m 段（m、n都是整数，n&gt;1并且m&gt;1），每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]<em>k[1]</em>...*k[m - 1] 可能的最大乘积是多少？例如，当绳子的长度是8时，我们把它剪成长度分别为2、3、3的三段，此时得到的最大乘积是18。</p></blockquote><p>答案需要取模 1e9+7（1000000007），如计算初始结果为：1000000008，请返回 1。</p><p>示例 1：</p><figure class="highlight kotlin"><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="number">2</span></span><br><span class="line">输出: <span class="number">1</span></span><br><span class="line">解释: <span class="number">2</span> = <span class="number">1</span> + <span class="number">1</span>, <span class="number">1</span> × <span class="number">1</span> = <span class="number">1</span></span><br><span class="line">示例 <span class="number">2</span>:</span><br><span class="line">输入: <span class="number">10</span></span><br><span class="line">输出: <span class="number">36</span></span><br><span class="line">解释: <span class="number">10</span> = <span class="number">3</span> + <span class="number">3</span> + <span class="number">4</span>, <span class="number">3</span> × <span class="number">3</span> × <span class="number">4</span> = <span class="number">36</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> int cuttingRope(int n) &#123;</span><br><span class="line">        <span class="keyword">if</span> (n &lt;= <span class="number">3</span>) <span class="keyword">return</span> n - <span class="number">1</span>;</span><br><span class="line">        long res = <span class="number">1</span>;</span><br><span class="line">        long seg = n / <span class="number">3</span>;</span><br><span class="line">        int rem = n % <span class="number">3</span>;</span><br><span class="line">        long p = (long)<span class="number">1e9</span> + <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//循环求余，有几个3</span></span><br><span class="line">        <span class="keyword">for</span>(int i = <span class="number">0</span>; i &lt; ((rem == <span class="number">1</span>) ? seg - <span class="number">1</span> : seg); i++)&#123;</span><br><span class="line">            res = res * <span class="number">3l</span> % p;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(rem == <span class="number">0</span>) <span class="keyword">return</span> (int)res;</span><br><span class="line">        <span class="keyword">if</span>(rem == <span class="number">1</span>) <span class="keyword">return</span> (int)(res * <span class="number">4</span> % p);</span><br><span class="line">        <span class="keyword">return</span> (int)(res * <span class="number">2</span> % p);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>首先使用贪心：绳子尽量分成长度为3 的子段，然后再区分余数为0，1，2的情况</p></blockquote><p>循环求余的通用公式：避免被除数过大导致越界问题：</p><figure class="highlight kotlin"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 求 (x^a) % p —— 循环求余法</span></span><br><span class="line"><span class="keyword">public</span> long  remainder(int x,int a,int p)&#123;  <span class="comment">//x为底数，a为幂，p为要取的模</span></span><br><span class="line">    long rem = <span class="number">1</span> ;</span><br><span class="line">    <span class="keyword">for</span> (int i = <span class="number">0</span>; i &lt; a; i++) &#123;</span><br><span class="line">        rem = (rem * x) % p ;   </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> rem;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>来源：https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/solution/mian-shi-ti-14-ii-jian-sheng-zi-iitan-xin-er-fen-f/</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;给你一根长度为 n 的绳子，请把绳子剪成整数长度的 m 段（m、n都是整数，n&amp;gt;1并且m&amp;gt;1），每段绳子的长度记为 k[0],k[1]...k[m - 1] 。请问 k[0]&lt;em&gt;k[1]&lt;/em&gt;...*k[m - 1] 可能的最大</summary>
      
    
    
    
    
    <category term="LeetCode" scheme="http://example.com/tags/LeetCode/"/>
    
  </entry>
  
  <entry>
    <title>Android中的ViewModel</title>
    <link href="http://example.com/2021/08/18/Android%E4%B8%AD%E7%9A%84ViewModel-1/"/>
    <id>http://example.com/2021/08/18/Android%E4%B8%AD%E7%9A%84ViewModel-1/</id>
    <published>2021-08-18T13:26:49.000Z</published>
    <updated>2021-08-18T13:27:32.700Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>ViewModel的一个重要作用就是帮助Activity分担一部分工作，专门用于存放与界面相关的数据，只要是界面上能看得到的数据，它的相关变量都应该存放在ViewModel中</p></blockquote><p>ViewModel的生命周期和Activity是不同的，在手机屏幕旋转的时候，Activity会被重新创建，但是ViewModel不会，只有Activity退出的时候，ViewModel才会和Activity一起销毁</p><figure><img src="https://tva1.sinaimg.cn/large/008i3skNgy1gtl9e6a9f3j60pq0scmyl02.jpg" alt="image-20210818212407408" /><figcaption aria-hidden="true">image-20210818212407408</figcaption></figure><h1 id="viewmodel的基本用法">ViewModel的基本用法</h1><blockquote><p>通常比较好的编程规范是给每一个Activity和Fragment都创建一个ViewModel</p></blockquote><h2 id="下面的程序可以做到在屏幕旋转的时候界面上显示的数字是不变的">下面的程序可以做到在屏幕旋转的时候，界面上显示的数字是不变的</h2><p>创建一个ViewModel类：</p><figure class="highlight kotlin"><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"><span class="class"><span class="keyword">class</span> <span class="title">MainViewModel</span> : <span class="type">ViewModel</span></span>() &#123;</span><br><span class="line">    <span class="keyword">var</span> counter = <span class="number">0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>绑定MainActivity和MainViewModel</p><figure class="highlight kotlin"><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="class"><span class="keyword">class</span> <span class="title">MainActivity</span> : <span class="type">AppCompatActivity</span></span>() &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">lateinit</span> <span class="keyword">var</span> viewModel: MainViewModel</span><br><span class="line"></span><br><span class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">onCreate</span><span class="params">(savedInstanceState: <span class="type">Bundle</span>?)</span></span> &#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState)</span><br><span class="line">        setContentView(R.layout.activity_main)</span><br><span class="line"></span><br><span class="line">        <span class="keyword">val</span> countReserve = sp.getInt(<span class="string">&quot;count_reserved&quot;</span>,<span class="number">0</span>)</span><br><span class="line"><span class="comment">//注意这里是通过ViewModeProvider去获得ViewModel的实例，而不是直接通过构造函数创建，不然每次调用onCreate方法时，都会创建一个ViewModel实例，ViewModel实例就不唯一了，就无法保存数据了</span></span><br><span class="line">        viewModel = ViewModelProvider(<span class="keyword">this</span>)[MainViewModel::<span class="keyword">class</span>.java]</span><br><span class="line">        plus_one.setOnClickListener &#123;</span><br><span class="line">            viewModel.counter++</span><br><span class="line">            refreshCounter()</span><br><span class="line">        &#125;</span><br><span class="line">        refreshCounter()</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">private</span> <span class="function"><span class="keyword">fun</span> <span class="title">refreshCounter</span><span class="params">()</span></span>&#123;</span><br><span class="line">        infoText.text = viewModel.counter.toString()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="向viewmodel传递参数">向ViewModel传递参数</h1><blockquote><p>下面的程序可以做到除了以上的功能外，还可以在退出程序后，重新打开的时候，界面显示的数字还是和之前一致的</p></blockquote><p>重新更改MainViewModel的内容，添加一个参数：</p><figure class="highlight kotlin"><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"><span class="comment">//这样在创建ViewModel的时候可以将内容传进去，每次退出程序并重新打开后，可以通过构造方法构建这个ViewModel</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainViewModel</span></span>(<span class="keyword">val</span> countReserve : <span class="built_in">Int</span>) : ViewModel() &#123;</span><br><span class="line">    <span class="keyword">var</span> counter = countReserve</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>需要一个ViewModelProvider.Factory来为ViewModel传递参数（还是不能直接使用ViewModel的构造方法）</p><figure class="highlight kotlin"><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="comment">//这里面重写了create方法，并在里面创建了MainViewModel的额实例</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MainViewModelFactory</span></span>(<span class="keyword">private</span> <span class="keyword">val</span> countReserve : <span class="built_in">Int</span>) : ViewModelProvider.Factory &#123;</span><br><span class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="type">&lt;T : ViewModel?&gt;</span> <span class="title">create</span><span class="params">(modelClass: <span class="type">Class</span>&lt;<span class="type">T</span>&gt;)</span></span>: T &#123;</span><br><span class="line">        <span class="keyword">return</span> MainViewModel(countReserve) <span class="keyword">as</span> T</span><br><span class="line"><span class="comment">//因为这个方法的调用时机和Activity的生命周期无关，所以不会产生多个ViewModel被拆功能键的问题</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>更改MainActivity中的内容</p><figure class="highlight kotlin"><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="class"><span class="keyword">class</span> <span class="title">MainActivity</span> : <span class="type">AppCompatActivity</span></span>() &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">lateinit</span> <span class="keyword">var</span> viewModel: MainViewModel</span><br><span class="line">    <span class="keyword">lateinit</span> <span class="keyword">var</span> sp : SharedPreferences</span><br><span class="line"></span><br><span class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">onCreate</span><span class="params">(savedInstanceState: <span class="type">Bundle</span>?)</span></span> &#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState)</span><br><span class="line">        setContentView(R.layout.activity_main)</span><br><span class="line"></span><br><span class="line">        sp = getPreferences(MODE_PRIVATE)</span><br><span class="line"><span class="comment">//在程序重新运行的时候，从持久化中取出之前存入的值</span></span><br><span class="line">        <span class="keyword">val</span> countReserve = sp.getInt(<span class="string">&quot;count_reserved&quot;</span>,<span class="number">0</span>)</span><br><span class="line"><span class="comment">//在这里传入Factory的实现类，并传入一个要传递给ViewModel构造函数的参数</span></span><br><span class="line">        viewModel = ViewModelProvider(<span class="keyword">this</span>,MainViewModelFactory(countReserve))[MainViewModel::<span class="keyword">class</span>.java]</span><br><span class="line"><span class="comment">//ViewModel更新操作</span></span><br><span class="line">        plus_one.setOnClickListener &#123;</span><br><span class="line">            viewModel.counter++</span><br><span class="line">            refreshCounter()</span><br><span class="line">        &#125;</span><br><span class="line"><span class="comment">//ViewModel清空操作</span></span><br><span class="line">        clear_btn.setOnClickListener &#123;</span><br><span class="line">            viewModel.counter = <span class="number">0</span></span><br><span class="line">            refreshCounter()</span><br><span class="line">        &#125;</span><br><span class="line">        refreshCounter()</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"><span class="comment">//在onPause的时候，将当前的ViewModel中的计数器的值放到sharedPreferences中持久化，以便在程序重新运行的时候被使用，可以保证不论是程序退出还是进入后台，计数都不会丢失</span></span><br><span class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">onPause</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="keyword">super</span>.onPause()</span><br><span class="line">        sp.edit &#123;</span><br><span class="line">            putInt(<span class="string">&quot;count_reserved&quot;</span>, viewModel.counter)</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">private</span> <span class="function"><span class="keyword">fun</span> <span class="title">refreshCounter</span><span class="params">()</span></span>&#123;</span><br><span class="line">        infoText.text = viewModel.counter.toString()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;ViewModel的一个重要作用就是帮助Activity分担一部分工作，专门用于存放与界面相关的数据，只要是界面上能看得到的数据，它的相关变量都应该存放在ViewModel中&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;ViewModel的生命周期和</summary>
      
    
    
    
    
    <category term="Android" scheme="http://example.com/tags/Android/"/>
    
  </entry>
  
  <entry>
    <title>Hello World</title>
    <link href="http://example.com/2021/08/18/hello-world/"/>
    <id>http://example.com/2021/08/18/hello-world/</id>
    <published>2021-08-18T07:58:33.577Z</published>
    <updated>2021-08-18T07:58:33.577Z</updated>
    
    <content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="quick-start">Quick Start</h2><h3 id="create-a-new-post">Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="run-server">Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="generate-static-files">Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="deploy-to-remote-sites">Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;Welcome to &lt;a href=&quot;https://hexo.io/&quot;&gt;Hexo&lt;/a&gt;! This is your very first post. Check &lt;a href=&quot;https://hexo.io/docs/&quot;&gt;documentation&lt;/a&gt; for</summary>
      
    
    
    
    
  </entry>
  
</feed>
