<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Stack on Moo&#39;s Blog</title>
    <link>https://blog.moo.ac/tags/stack/</link>
    <description>Recent content in Stack on Moo&#39;s Blog</description>
    <image>
      <title>Moo&#39;s Blog</title>
      <url>https://blog.moo.ac/images/papermod-cover.png</url>
      <link>https://blog.moo.ac/images/papermod-cover.png</link>
    </image>
    <generator>Hugo -- 0.145.0</generator>
    <language>en</language>
    <copyright>PaperMod Contributors</copyright>
    <lastBuildDate>Tue, 15 Sep 2020 19:22:41 +0800</lastBuildDate>
    <atom:link href="https://blog.moo.ac/tags/stack/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>算法: 有效的括号</title>
      <link>https://blog.moo.ac/posts/isvalid/</link>
      <pubDate>Tue, 15 Sep 2020 19:22:41 +0800</pubDate>
      <guid>https://blog.moo.ac/posts/isvalid/</guid>
      <description>栈算法</description>
      <content:encoded><![CDATA[<h2 id="问题描述">问题描述</h2>
<p>给定一个只包括<code> '('</code>, <code>')'</code>, <code>'{'</code>, <code>'}'</code>, <code>'['</code>, <code>']'</code> 的字符串, 判断字符串是否有效.</p>
<p>有效字符串需满足：</p>
<ol>
<li>左括号必须用相同类型的右括号闭合.</li>
<li>左括号必须以正确的顺序闭合.</li>
</ol>
<p>注意空字符串可被认为是有效字符串.</p>
<p>题目地址:https://leetcode-cn.com/problems/valid-parentheses/</p>
<p>(看了评论才知道是B站开发岗面试题)</p>
<h3 id="示例">示例</h3>
<pre tabindex="0"><code>输入: &#34;()&#34;
输出: true

输入: &#34;()[]{}&#34;
输出: true

输入: &#34;(]&#34;
输出: false

输入: &#34;([)]&#34;
输出: false

输入: &#34;{[]}&#34;
输出: true
</code></pre><h2 id="解答">解答</h2>
<h3 id="思路一">思路一</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">isValid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">while</span> <span class="s1">&#39;</span><span class="si">{}</span><span class="s1">&#39;</span> <span class="ow">in</span> <span class="n">s</span> <span class="ow">or</span> <span class="s1">&#39;()&#39;</span> <span class="ow">in</span> <span class="n">s</span> <span class="ow">or</span> <span class="s1">&#39;[]&#39;</span> <span class="ow">in</span> <span class="n">s</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;[]&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;()&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">s</span> <span class="o">==</span> <span class="s1">&#39;&#39;</span>
</span></span></code></pre></div><p>对于正确的来说, 每次都能去掉一对括号, 最后就成了空.</p>
<h3 id="思路二">思路二</h3>
<p>其实这个题主要是考大家关于栈的应用</p>
<h4 id="原理">原理</h4>
<ul>
<li>
<p>栈先入后出特点恰好与本题括号排序特点一致, 即若遇到左括号入栈, 遇到右括号时将对应栈顶左括号出栈, 则遍历完所有括号后 <code>stack </code>仍然为空；</p>
</li>
<li>
<p>建立哈希表<code>dic</code>构建左右括号对应关系：<code>key</code> 左括号, <code>value</code> 右括号；这样查询 2 个括号是否对应只需 $O(1)$ 时间复杂度；建立栈 <code>stack</code>, 遍历字符串<code>s</code> 并按照算法流程一一判断.</p>
</li>
</ul>
<h4 id="流程">流程</h4>
<p>如果 <code>c</code> 是左括号, 则入栈 <code>push</code>；
否则通过哈希表判断括号对应关系, 若 <code>stack</code> 栈顶出栈括号 <code>stack.pop()</code> 与当前遍历括号<code> c</code> 不对应, 则提前返回 <code>false</code>.</p>
<h4 id="提高算法效率">提高算法效率</h4>
<h5 id="提前返回false">提前返回<code>false</code></h5>
<ul>
<li>
<p>边界问题栈 <code>stack</code> 为空： 此时<code>stack.pop()</code>操作会报错；因此, 我们采用一个取巧方法, 给 stack 赋初值 <code>?</code> , 并在哈希表<code> dic</code> 中建立 <code>key</code>: <code>'?'</code>, <code>value</code>:<code>'?'</code>的对应关系予以配合. 此时当 <code>stack</code> 为空且<code> c</code> 为右括号时, 可以正常提前返回 <code>false</code>；</p>
</li>
<li>
<p>字符串 <code>s</code> 以左括号结尾： 此情况下可以正常遍历完整个 <code>s</code>, 但 stack 中遗留未出栈的左括号；因此, 最后需返回<code> len(stack) == 1</code>, 以判断是否是有效的括号组合.</p>
</li>
</ul>
<h4 id="时间复杂度">时间复杂度</h4>
<ul>
<li>时间复杂度 $O(N)$：正确的括号组合需要遍历 11 遍 <code>s</code>；</li>
<li>空间复杂度 $O(N)$：哈希表和栈使用线性的空间大小.</li>
</ul>
<h4 id="示意图">示意图</h4>
<p><img alt="20200915194118" loading="lazy" src="/posts/isvalid/isValid.assets/20200915194118.webp"></p>
<h4 id="代码">代码</h4>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">isValid</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">dic</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;{&#39;</span><span class="p">:</span> <span class="s1">&#39;}&#39;</span><span class="p">,</span>  <span class="s1">&#39;[&#39;</span><span class="p">:</span> <span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">:</span> <span class="s1">&#39;)&#39;</span><span class="p">,</span> <span class="s1">&#39;?&#39;</span><span class="p">:</span> <span class="s1">&#39;?&#39;</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="n">stack</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;?&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">s</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">dic</span><span class="p">:</span> <span class="n">stack</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">elif</span> <span class="n">dic</span><span class="p">[</span><span class="n">stack</span><span class="o">.</span><span class="n">pop</span><span class="p">()]</span> <span class="o">!=</span> <span class="n">c</span><span class="p">:</span> <span class="k">return</span> <span class="kc">False</span> 
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">stack</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
</span></span></code></pre></div><p>原作者:<a href="https://leetcode-cn.com/problems/valid-parentheses/solution/valid-parentheses-fu-zhu-zhan-fa-by-jin407891080/">Krahets</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>算法: 只出现一次的数字</title>
      <link>https://blog.moo.ac/posts/numonce/</link>
      <pubDate>Tue, 08 Sep 2020 22:29:09 +0800</pubDate>
      <guid>https://blog.moo.ac/posts/numonce/</guid>
      <description>排序算法</description>
      <content:encoded><![CDATA[<h2 id="只出现一次的数字">只出现一次的数字</h2>
<h3 id="问题描述">问题描述</h3>
<p>给定一个<strong>非空</strong>整数数组, 除了某个元素只出现一次以外, 其余每个元素均出现两次. 找出那个只出现了一次的元素.</p>
<p>题目地址: <a href="https://leetcode-cn.com/problems/single-number/">https://leetcode-cn.com/problems/single-number/</a></p>
<h4 id="说明">说明</h4>
<p>你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗？</p>
<h4 id="示例">示例</h4>
<pre tabindex="0"><code>输入: [2,2,1]
输出: 1
输入: [4,1,2,1,2]
输出: 4
</code></pre><h3 id="解答">解答</h3>
<p>开始想的是用collection函数来统计次数, 但发现题目的说明讲到了不使用额外的空间, 所以作罢.</p>
<p>后来想用sort来进行排序, 再进行<code>for num in nums</code>进行遍历, 来判断相邻两个是否相同从而找出不同的元素, 但这样O(n)的时间复杂度就太高了. 而且严格来说sort也使用了额外的空间(见下文解释)</p>
<h4 id="python的sort方法">python的sort方法</h4>
<p>见python<a href="https://github.com/python/cpython/blob/master/Objects/listobject.c">源码</a>中的sort实现</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">PyList_Sort</span><span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="n">v</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">==</span> <span class="nb">NULL</span> <span class="o">||</span> <span class="o">!</span><span class="nf">PyList_Check</span><span class="p">(</span><span class="n">v</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nf">PyErr_BadInternalCall</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">v</span> <span class="o">=</span> <span class="nf">list_sort_impl</span><span class="p">((</span><span class="n">PyListObject</span> <span class="o">*</span><span class="p">)</span><span class="n">v</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">v</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nf">Py_DECREF</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>使用的是<a href="https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/Timsort%25EF%25BC%258C%25E5%258F%25A6%25E5%25A4%2596%25EF%25BC%258C%25E5%259B%25BD%25E5%2586%2585%25E6%259C%2589%25E4%25B8%2580%25E4%25B8%25AA%25E6%2596%2587%25E6%25A1%25A3%25EF%25BC%258C%25E9%2580%2582%25E5%25BD%2593%25E7%25BF%25BB%25E8%25AF%2591%25EF%25BC%259Ahttp%3A//blog.csdn.net/yangzhongblog/article/details/8184707%25EF%25BC%258C%25E8%25BF%2599%25E9%2587%258C%25E6%2588%25AA%25E5%258F%2596%25E4%25B8%2580%25E4%25B8%25AA%25E4%25B8%258D%25E5%2590%258C%25E6%258E%2592%25E5%25BA%258F%25E7%25AE%2597%25E6%25B3%2595%25E6%25AF%2594%25E8%25BE%2583%25E7%259A%2584%25E5%259B%25BE%25E7%25A4%25BA%25EF%25BC%258C%25E5%25B0%25B1%25E6%2598%258E%25E7%2599%25BDsorted%25E7%259A%2584%25E5%25A8%2581%25E5%258A%259B%25E4%25BA%2586%25E3%2580%2582">Timsort算法</a>, 从时间复杂度来讲, 这个算法是高效的.<img alt="img" loading="lazy" src="/posts/numonce/numonce.assets/v2-497ffb4a451d35d331c65036686b8809_1440w.png"></p>
<p>从空间复杂度来讲，需要的开销在数量大的时候会增大.</p>
<p><img alt="img" loading="lazy" src="/posts/numonce/numonce.assets/v2-12073c104a48316f8e839879b68897ca_1440w.png"></p>
<p>下面是JSE7 中Timsort实现代码中的一段话，可以很好的说明Timsort的优势：</p>
<blockquote>
<p>A stable, adaptive, iterative mergesort that requires far fewer than n lg(n) comparisons when running on partially sorted arrays, while offering performance comparable to a traditional mergesort when run on random arrays. Like all proper mergesorts, this sort is stable and runs O(n log n) time (worst case). In the worst case, this sort requires temporary storage space for n/2 object references; in the best case, it requires only a small constant amount of space.</p></blockquote>
<p>大体是说，Timsort是稳定的算法，当待排序的数组中已经有排序好的数，它的时间复杂度会小于$n log(n)$。与其他合并排序一样，Timesrot是稳定的排序算法，最坏时间复杂度是$O（n log n）$。在最坏情况下，Timsort算法需要的<strong>临时空间</strong>是$\frac{n}{2}$，在最好情况下，它只需要一个<strong>很小的临时存储空间</strong>.</p>
<h4 id="最终解法">最终解法</h4>
<p>异或</p>
<ol>
<li>交换律：a ^ b ^ c &lt;=&gt; a ^ c ^ b</li>
<li>任何数于0异或为任何数 0 ^ n =&gt; n</li>
<li>相同的数异或为0: n ^ n =&gt; 0</li>
</ol>
<blockquote>
<p>2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 =&gt; 0 ^ 0 ^3 =&gt; 3</p></blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Solution</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">singleNumber</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">nums</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">        :type nums: List[int]
</span></span></span><span class="line"><span class="cl"><span class="s2">        :rtype: int
</span></span></span><span class="line"><span class="cl"><span class="s2">        &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="n">a</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">num</span> <span class="ow">in</span> <span class="n">nums</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="o">^</span> <span class="n">num</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">a</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
  </channel>
</rss>
