<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>lxj&#39;s blog</title>
  
  <subtitle>悟已往之不谏，知来者之可追。</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="https://luoxjnono.github.io/"/>
  <updated>2020-05-19T02:37:32.368Z</updated>
  <id>https://luoxjnono.github.io/</id>
  
  <author>
    <name>xj luo</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>leetcode2</title>
    <link href="https://luoxjnono.github.io/2020/05/19/leetcode2/"/>
    <id>https://luoxjnono.github.io/2020/05/19/leetcode2/</id>
    <published>2020-05-19T02:37:32.000Z</published>
    <updated>2020-05-19T02:37:32.368Z</updated>
    
    <summary type="html">
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>leetcode经典链表相关题目(思路、方法、code)</title>
    <link href="https://luoxjnono.github.io/2020/05/18/leetcode1/"/>
    <id>https://luoxjnono.github.io/2020/05/18/leetcode1/</id>
    <published>2020-05-18T03:05:06.000Z</published>
    <updated>2020-05-18T16:25:34.148Z</updated>
    
    <content type="html"><![CDATA[<p>链表是最常用的数据结构之一。</p><a id="more"></a><p>首先是链表的结构定义:</p><figure class="highlight c++"><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">* Definition <span class="keyword">for</span> singly-linked <span class="built_in">list</span>.</span><br><span class="line">* <span class="class"><span class="keyword">struct</span> <span class="title">ListNode</span> &#123;</span></span><br><span class="line">*     <span class="keyword">int</span> val;</span><br><span class="line">*     ListNode *next;</span><br><span class="line">*     ListNode(<span class="keyword">int</span> x) : val(x), next(<span class="literal">NULL</span>) &#123;&#125;</span><br><span class="line">* &#125;;</span><br><span class="line">*/</span><br></pre></td></tr></table></figure><h5 id="206-反转链表"><a href="#206-反转链表" class="headerlink" title="206.反转链表"></a>206.反转链表</h5><p>给定一个链表头节点，将其反转，并输出新的头节点</p><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">reverseList</span><span class="params">(ListNode* head)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line"><span class="keyword">if</span>(head==<span class="literal">NULL</span>||head-&gt;next==<span class="literal">NULL</span>)</span><br><span class="line">            <span class="keyword">return</span> head;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">        ListNode* mid=<span class="literal">NULL</span>;</span><br><span class="line">        ListNode* next_node=head-&gt;next;</span><br><span class="line">        head-&gt;next=<span class="literal">NULL</span>;<span class="comment">//这一步很重要，防止链表循环</span></span><br><span class="line">        <span class="keyword">while</span>(next_node!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">            mid=next_node;</span><br><span class="line">            next_node=next_node-&gt;next;</span><br><span class="line">            mid-&gt;next=head;</span><br><span class="line">            head=mid;</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><span class="line">    &#125;      </span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>时间复杂度为O(n), 空间复杂度O(1)</p><p>递归法：</p><figure class="highlight c++"><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> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">reverseList</span><span class="params">(ListNode* head)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        #如果为<span class="literal">NULL</span>或单节点则返回自身</span><br><span class="line"><span class="keyword">if</span>(head==<span class="literal">NULL</span>||head-&gt;next==<span class="literal">NULL</span>) <span class="keyword">return</span> head;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">ListNode* newhead=<span class="literal">NULL</span>;</span><br><span class="line">newhead=reverseList(head-&gt;next); <span class="comment">//这意味这已经将除了head之后节点的已经反转</span></span><br><span class="line">head-&gt;next-&gt;next=head;  <span class="comment">//故需要令让head-&gt;next的next指向head实现head的反转</span></span><br><span class="line">head-&gt;next=<span class="literal">NULL</span>;   <span class="comment">//防止链表循环，将head的next置空</span></span><br><span class="line"><span class="comment">//每层递归都要返回最后一个节点</span></span><br><span class="line">            <span class="keyword">return</span> newhead; </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><h5 id="92-反转链表-II"><a href="#92-反转链表-II" class="headerlink" title="92. 反转链表 II"></a>92. 反转链表 II</h5><p>反转从m到n的链表，请使用一趟扫描完成反转</p><p>说明：1$\le$m$\le$n$\le$链表长度</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: 1-&gt;2-&gt;3-&gt;4-&gt;5-&gt;NULL, m = 2, n = 4</span><br><span class="line">输出: 1-&gt;4-&gt;3-&gt;2-&gt;5-&gt;NULL</span><br></pre></td></tr></table></figure><h5 id="160-相交链表"><a href="#160-相交链表" class="headerlink" title="160. 相交链表"></a>160. 相交链表</h5><p>编写一个程序，找到连个单链表相交的起始节点。</p><p><img src="/2020/05/18/leetcode1/leetcode1%5C160_statement.png" alt="160_statement"></p><p>解题思路：</p><p>从图中我们可以发现，在相交之后的链表长度是相同的，所以我们从头开始遍历知道两个链表长度相同时再逐个进行比较。</p><figure class="highlight c++"><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">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode *<span class="title">getIntersectionNode</span><span class="params">(ListNode *headA, ListNode *headB)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> lenA=<span class="number">0</span>,lenB=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">if</span> (headA==<span class="literal">NULL</span>||headB==<span class="literal">NULL</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">        ListNode* node=headA;</span><br><span class="line">        <span class="keyword">while</span>(node!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">        node=node-&gt;next;</span><br><span class="line">        lenA++;</span><br><span class="line">        &#125;</span><br><span class="line">        node=headB;</span><br><span class="line">        <span class="keyword">while</span>(node!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">        node=node-&gt;next;</span><br><span class="line">        lenB++;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">int</span> len=lenA-lenB;</span><br><span class="line">        <span class="keyword">if</span>(lenA&lt;lenB)&#123;</span><br><span class="line">        node=headA;</span><br><span class="line">        headA=headB;</span><br><span class="line">        headB=node;</span><br><span class="line">        len*=<span class="number">-1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(len&gt;<span class="number">0</span>)&#123;</span><br><span class="line">        headA=headA-&gt;next;</span><br><span class="line">        len--;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(headA!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span>(headA==headB)</span><br><span class="line">        <span class="keyword">return</span> headA;</span><br><span class="line">        headA=headA-&gt;next;</span><br><span class="line">        headB=headB-&gt;next;</span><br><span class="line">        </span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>时间复杂度为O(n)，空间复杂度为O(1)。</p><h5 id="141-环形链表"><a href="#141-环形链表" class="headerlink" title="141. 环形链表"></a>141. 环形链表</h5><p><strong>这类链表题目一般都是使用双指针法解决的，例如寻找距离尾部第K个节点、寻找环入口、寻找公共尾部入口等。</strong></p><p>给定一个链表，判断链表中是否有环。</p><p>第一种结果： fast 指针走过链表末端，说明链表无环，直接返回 null；</p><p>TIPS: 若有环，两指针一定会相遇。因为每走 11 轮，fast 与 slow 的间距 +1+1，fast 终会追上 slow；</p><p><img src="/2020/05/18/leetcode1/leetcode1%5C%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8.PNG" alt="环形链表"></p><p>思路：使用快慢指针：快指针每次遍历两个节点，慢指针每次遍历一个节点，没有换很快回NULL，有的话两个指针将会相遇。</p><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">hasCycle</span><span class="params">(ListNode *head)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(head==<span class="literal">NULL</span>||head-&gt;next==<span class="literal">NULL</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        ListNode* quick=head;</span><br><span class="line">        ListNode* slow=head;</span><br><span class="line">        <span class="keyword">while</span>(quick!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span>(quick-&gt;next!=<span class="literal">NULL</span>&amp;&amp;quick-&gt;next-&gt;next!=<span class="literal">NULL</span>)</span><br><span class="line">                quick=quick-&gt;next-&gt;next;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                quick=<span class="literal">NULL</span>;</span><br><span class="line">            slow=slow-&gt;next;</span><br><span class="line">            <span class="keyword">if</span>(quick==slow)</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//附上一年前的代码</span></span><br><span class="line"><span class="function"><span class="keyword">bool</span> <span class="title">hasCycle</span><span class="params">(struct ListNode *head)</span> </span>&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">ListNode</span> *<span class="title">fast</span>=<span class="title">head</span>, *<span class="title">slow</span>=<span class="title">head</span>;</span></span><br><span class="line">    <span class="keyword">while</span>( slow &amp;&amp; fast &amp;&amp; fast-&gt;next )&#123;</span><br><span class="line">        fast=fast-&gt;next-&gt;next;</span><br><span class="line">        slow=slow-&gt;next;</span><br><span class="line">        <span class="keyword">if</span>(fast==slow) <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="142-环形链表-II"><a href="#142-环形链表-II" class="headerlink" title="142. 环形链表 II"></a>142. 环形链表 II</h5><p>在141基础上进行改进，给定一个链表，返回链表开始入环的第一个节点。 如果链表无环，则返回 null。</p><p>方法1：使用SET或者哈希映射</p><p>对于每个节点，将其地址通过哈希映射或者直接存入到SET中，然后依次遍历链表，检测新节点是否已经在SET中或者已经被哈希映射。如果遍历结束，则说明没用环。如果遍历过程中发现该地址已经出现在哈希映射表或者SET中，则说明已经遍历过该节点，说明存在环，且该节点为入环节点。</p><figure class="highlight c++"><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> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode *<span class="title">detectCycle</span><span class="params">(ListNode *head)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        <span class="built_in">set</span>&lt;ListNode *&gt; node_set; <span class="comment">//用set存的是ListNode *</span></span><br><span class="line"><span class="keyword">while</span>(head)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(node_set.find(head)!=node_set.end()) <span class="comment">//说明之前已经出现</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">return</span> head;</span><br><span class="line">&#125;</span><br><span class="line">node_set.insert(head); <span class="comment">//将其加入set，继续遍历</span></span><br><span class="line">head=head-&gt;next;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">NULL</span>; </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>上面的做法时间和空间效率都不高。</p><p>方法2：快慢指针法：</p><p>具体解法：</p><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode *<span class="title">detectCycle</span><span class="params">(ListNode *head)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        ListNode* fast=head,*slow=head;</span><br><span class="line">        <span class="keyword">while</span>(<span class="number">1</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span> (fast==<span class="literal">NULL</span>||fast-&gt;next==<span class="literal">NULL</span>)</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">            fast=fast-&gt;next-&gt;next;</span><br><span class="line">            slow=slow-&gt;next;</span><br><span class="line">            <span class="keyword">if</span> (fast==slow)</span><br><span class="line">                <span class="keyword">break</span>;&#125;</span><br><span class="line">            fast=head;</span><br><span class="line">            <span class="keyword">while</span>(fast!=slow)</span><br><span class="line">            fast=fast-&gt;next,slow=slow-&gt;next;</span><br><span class="line">            <span class="keyword">return</span> fast;</span><br><span class="line">            </span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5 id="86-分隔链表"><a href="#86-分隔链表" class="headerlink" title="86. 分隔链表"></a>86. 分隔链表</h5><p>给定一个链表和一个特定值 <em>x</em>，对链表进行分隔，使得所有小于 <em>x</em> 的节点都在大于或等于 <em>x</em> 的节点之前。</p><p>你应当保留两个分区中每个节点的初始相对位置。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">输入: 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><p>分析：可以设置两个<strong>辅助头结点</strong>，一个用来存储小于x的节点的链接，一个用来存储大于等于x的节点的链接。因此在此基础上<strong>遍历该链表，如果当前节点的之小于x，则将其加入到小于x的链表列，否则加入到大于等于x的链表列。最终，将两个链表合并即可</strong>。</p><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">partition</span><span class="params">(ListNode* head, <span class="keyword">int</span> x)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(head==<span class="literal">NULL</span>||head-&gt;next==<span class="literal">NULL</span>) <span class="keyword">return</span> head;</span><br><span class="line">        </span><br><span class="line">        ListNode a(0),b(0);</span><br><span class="line">        ListNode* less_head=&amp;a;</span><br><span class="line">        ListNode* more_head=&amp;b;</span><br><span class="line">        <span class="keyword">while</span>(head)  <span class="comment">//遍历链表，将每一项加入到对应的链表列</span></span><br><span class="line">        &#123;</span><br><span class="line">        <span class="keyword">if</span>(head-&gt;val&lt;x)</span><br><span class="line">        &#123;</span><br><span class="line">        less_head-&gt;next=head;</span><br><span class="line">        less_head=less_head-&gt;next;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">&#123;</span><br><span class="line">more_head-&gt;next=head;</span><br><span class="line">more_head=more_head-&gt;next;</span><br><span class="line">&#125;</span><br><span class="line">head=head-&gt;next;</span><br><span class="line">&#125;</span><br><span class="line">        <span class="comment">//将两个链表列进行合并</span></span><br><span class="line">more_head-&gt;next=<span class="literal">NULL</span>;  </span><br><span class="line">less_head-&gt;next=b.next;<span class="comment">//令小于链表的尾指向more.next即可</span></span><br><span class="line"><span class="keyword">return</span> a.next;<span class="comment">//返回尾小于链表的next即可</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5 id="83-删除排序链表中的重复元素"><a href="#83-删除排序链表中的重复元素" class="headerlink" title="83. 删除排序链表中的重复元素"></a>83. 删除排序链表中的重复元素</h5><p>给定一个排序链表，删除所有重复的元素，使得每个元素只出现一次。</p><figure class="highlight plain"><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">输入: 1-&gt;1-&gt;2</span><br><span class="line">输出: 1-&gt;2</span><br><span class="line"></span><br><span class="line">输入: 1-&gt;1-&gt;2-&gt;3-&gt;3</span><br><span class="line">输出: 1-&gt;2-&gt;3</span><br></pre></td></tr></table></figure><figure class="highlight c++"><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 class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">deleteDuplicates</span><span class="params">(ListNode* head)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(head==<span class="literal">NULL</span>||head-&gt;next==<span class="literal">NULL</span>)</span><br><span class="line">        <span class="keyword">return</span> head;</span><br><span class="line">        ListNode*pre =head;</span><br><span class="line">        ListNode*next=head-&gt;next;</span><br><span class="line">        <span class="keyword">while</span>(next!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">        <span class="keyword">if</span>(pre-&gt;val==next-&gt;val)&#123;</span><br><span class="line">        next=next-&gt;next;</span><br><span class="line">        pre-&gt;next=next;<span class="comment">//去掉重复的节点</span></span><br><span class="line">        &#125;</span><br><span class="line">            <span class="keyword">else</span>&#123;</span><br><span class="line">                next=next-&gt;next;</span><br><span class="line">                pre=pre-&gt;next;</span><br><span class="line">            &#125;</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><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5 id="82-删除排序链表中的重复元素-II（递归）"><a href="#82-删除排序链表中的重复元素-II（递归）" class="headerlink" title="82. 删除排序链表中的重复元素 II（递归）"></a>82. 删除排序链表中的重复元素 II（递归）</h5><p>给定一个排序链表，删除所有含有重复数字的节点，只保留原始链表中 <em>没有重复出现</em> 的数字。在原来的基础上，只要重复出现了的元素全部删除。</p><p>头节点有重复的话将会比较麻烦，这里采用递归的思想：</p><p><strong>每次对第一个节点进行检测，如果非重复，则将其加入，对后面继续执行。如果重复，则向后遍历直至与其不一致，执行遍历。</strong></p><figure class="highlight c++"><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><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function">ListNode* <span class="title">deleteDuplication</span><span class="params">(ListNode *pHead)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (pHead==<span class="literal">NULL</span> || pHead-&gt;next==<span class="literal">NULL</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> pHead;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (pHead-&gt;val==pHead-&gt;next-&gt;val) &#123; <span class="comment">// 当前节点是重复节点</span></span><br><span class="line">            ListNode *node = pHead-&gt;next;</span><br><span class="line">            <span class="keyword">while</span> (node != <span class="literal">NULL</span> &amp;&amp; node-&gt;val == pHead-&gt;val) &#123;</span><br><span class="line">                <span class="comment">// 向后遍历直至与其不一致</span></span><br><span class="line">                node = node-&gt;next;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> deleteDuplication(node); <span class="comment">// 从第一个与当前结点不同的结点继续递归</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            pHead-&gt;next = deleteDuplication(pHead-&gt;next); <span class="comment">// 从下一个节点继续递归</span></span><br><span class="line">            <span class="keyword">return</span> pHead;<span class="comment">//保留当前节点</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5 id="19-删除链表的倒数第N个节点"><a href="#19-删除链表的倒数第N个节点" class="headerlink" title="19. 删除链表的倒数第N个节点"></a>19. 删除链表的倒数第N个节点</h5><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">给定一个链表: 1-&gt;2-&gt;3-&gt;4-&gt;5, 和 n = 2.</span><br><span class="line">当删除了倒数第二个节点后，链表变为 1-&gt;2-&gt;3-&gt;5.</span><br></pre></td></tr></table></figure><p>思路1：删除倒数第n个，即正数第L-n-1个，我们用一个哑节点作为辅助从而简化情况。</p><figure class="highlight c++"><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 class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function">ListNode* <span class="title">removeNthFromEnd</span><span class="params">(ListNode* head, <span class="keyword">int</span> n)</span> </span>&#123;    </span><br><span class="line">ListNode dummy=ListNode(<span class="number">0</span>);</span><br><span class="line">dummy.next=head;</span><br><span class="line"><span class="keyword">int</span> lenth=<span class="number">0</span>;</span><br><span class="line">ListNode first=head;</span><br><span class="line"><span class="keyword">while</span>(first!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">    lenth++;</span><br><span class="line">    first=first.next;</span><br><span class="line">&#125;</span><br><span class="line">lenth-=n;</span><br><span class="line">first=dummy;</span><br><span class="line"><span class="keyword">while</span>(lenth&gt;<span class="number">0</span>)&#123;</span><br><span class="line">    lenth--;</span><br><span class="line">    first=first.next;</span><br><span class="line">&#125;</span><br><span class="line">first.next=first.next.next;</span><br><span class="line"><span class="keyword">return</span> dummy.next;</span><br><span class="line">&#125;&#125;;</span><br></pre></td></tr></table></figure><p>思路二：通过一次遍历完成</p><p>上述算法可以优化为只使用一次遍历。我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1 步，而第二个指针将从列表的开头出发。现在，这两个指针被 n 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔，直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 nn 个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function">ListNode* <span class="title">removeNthFromEnd</span><span class="params">(ListNode* head, <span class="keyword">int</span> n)</span> </span>&#123; </span><br><span class="line">ListNode dummy=ListNode(<span class="number">0</span>);</span><br><span class="line">    dummy.next=head;</span><br><span class="line">    ListNode fir=dummy;</span><br><span class="line">    ListNode sec=dummy;</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++)</span><br><span class="line">        fir=fir.next;</span><br><span class="line">    <span class="keyword">while</span>(first!=<span class="literal">NULL</span>)&#123;</span><br><span class="line">        fir=fir.next;</span><br><span class="line">        sec=sec.next;</span><br><span class="line">    &#125;</span><br><span class="line">    sec.next=sec.next.next;</span><br><span class="line">    <span class="keyword">return</span> dummy.next;</span><br><span class="line">&#125;&#125;；</span><br></pre></td></tr></table></figure><p>结果要好一点点。</p><h5 id="138-复制带随机指针的链表"><a href="#138-复制带随机指针的链表" class="headerlink" title="138. 复制带随机指针的链表"></a>138. 复制带随机指针的链表</h5><p>给定一个链表，每个节点包含一个额外增加的随机指针，该指针可以指向链表中的任何节点或空节点。</p><p>要求返回这个链表的 深拷贝。 </p><p>我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示：</p><p>val：一个表示 Node.val 的整数。<br>random_index：随机指针指向的节点索引（范围从 0 到 n-1）；如果不指向任何节点，则为  null 。</p><h5 id="2-两数相加"><a href="#2-两数相加" class="headerlink" title="2. 两数相加"></a>2. 两数相加</h5><p>给出两个 非空 的链表用来表示两个非负的整数。其中，它们各自的位数是按照 逆序 的方式存储的，并且它们的每个节点只能存储 一位 数字。</p><p>如果，我们将这两个数相加起来，则会返回一个新的链表来表示它们的和。</p><p>您可以假设除了数字 0 之外，这两个数都不会以 0 开头。</p><figure class="highlight plain"><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">输入：(2 -&gt; 4 -&gt; 3) + (5 -&gt; 6 -&gt; 4)</span><br><span class="line">输出：7 -&gt; 0 -&gt; 8</span><br><span class="line">原因：342 + 465 = 807</span><br></pre></td></tr></table></figure><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function">ListNode* <span class="title">addTwoNumbers</span><span class="params">(ListNode* l1, ListNode* l2)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ListNode *head=<span class="keyword">new</span> ListNode(<span class="number">0</span>);   <span class="comment">//head是结果</span></span><br><span class="line">ListNode *p=l1,*q=l2,*cur=head; </span><br><span class="line"><span class="keyword">int</span> carry=<span class="number">0</span>;<span class="comment">//作为进位 </span></span><br><span class="line"><span class="keyword">int</span> x=<span class="number">0</span>,y=<span class="number">0</span>;</span><br><span class="line"><span class="keyword">while</span>(p!=<span class="literal">NULL</span>||q!=<span class="literal">NULL</span>) <span class="comment">//如果其中一个为0，则将其后面节点均视为0即可 </span></span><br><span class="line">&#123;</span><br><span class="line">x=(p==<span class="literal">NULL</span>)?<span class="number">0</span>:(p-&gt;val);</span><br><span class="line">            y=(q==<span class="literal">NULL</span>)?<span class="number">0</span>:(q-&gt;val);</span><br><span class="line"><span class="keyword">int</span> sum=x+y+carry; <span class="comment">//加起来</span></span><br><span class="line">carry=sum/<span class="number">10</span>; <span class="comment">//如果小于10则为0,否则为1 </span></span><br><span class="line">cur-&gt;next=<span class="keyword">new</span> ListNode(sum%<span class="number">10</span>);</span><br><span class="line">cur=cur-&gt;next;</span><br><span class="line"><span class="keyword">if</span>(p!=<span class="literal">NULL</span>) p=p-&gt;next;</span><br><span class="line"><span class="keyword">if</span>(q!=<span class="literal">NULL</span>) q=q-&gt;next; </span><br><span class="line">&#125; </span><br><span class="line"><span class="keyword">if</span>(carry&gt;<span class="number">0</span>) <span class="comment">//说明虽然相加完了,但是还是有进位</span></span><br><span class="line">cur-&gt;next=<span class="keyword">new</span> ListNode(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">return</span> head-&gt;next; </span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h5 id="148-排序链表"><a href="#148-排序链表" class="headerlink" title="148. 排序链表"></a>148. 排序链表</h5><p>如题，将链表排序。</p><p>通过快慢指针找到中点，然后用归并排序。</p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function">ListNode* <span class="title">sortList</span><span class="params">(ListNode* head)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (head == <span class="literal">NULL</span> || head-&gt;next == <span class="literal">NULL</span>) <span class="comment">//链表为空或者单节点 </span></span><br><span class="line">  <span class="keyword">return</span> head;</span><br><span class="line">        ListNode* pmid;</span><br><span class="line">        ListNode* slow = head;  <span class="comment">//慢指针 </span></span><br><span class="line">        ListNode* fast = head;  <span class="comment">//快指针 </span></span><br><span class="line">        <span class="keyword">while</span> (fast &amp;&amp; fast-&gt;next)</span><br><span class="line">        &#123;</span><br><span class="line">            pmid = slow;</span><br><span class="line">            slow = slow-&gt;next;</span><br><span class="line">            fast = fast-&gt;next-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        pmid-&gt;next = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> Merge(sortList(head), sortList(slow));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function">ListNode* <span class="title">Merge</span><span class="params">(ListNode* l1, ListNode* l2)</span>  <span class="comment">//将两个有序链表合并 </span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        <span class="function">ListNode <span class="title">dummy</span><span class="params">(<span class="number">0</span>)</span></span>;  <span class="comment">//作为一个哑结点 </span></span><br><span class="line">        ListNode *p = &amp;dummy;</span><br><span class="line">        <span class="keyword">while</span> (l1 &amp;&amp; l2)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (l1-&gt;val &lt; l2-&gt;val)</span><br><span class="line">            &#123;</span><br><span class="line">                p-&gt;next = l1;</span><br><span class="line">                l1 = l1-&gt;next;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                p-&gt;next = l2;</span><br><span class="line">                l2 = l2-&gt;next;</span><br><span class="line">            &#125;</span><br><span class="line">            p = p-&gt;next;</span><br><span class="line">        &#125;</span><br><span class="line">        p-&gt;next = (l1 == <span class="literal">NULL</span>)? l2 : l1;</span><br><span class="line">        <span class="keyword">return</span> dummy.next;  <span class="comment">//返回哑结点下一个节点 </span></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;链表是最常用的数据结构之一。&lt;/p&gt;
    
    </summary>
    
      <category term="leetcode" scheme="https://luoxjnono.github.io/categories/leetcode/"/>
    
    
  </entry>
  
  <entry>
    <title>leetcode 经典栈相关题目(思路、方法、code)</title>
    <link href="https://luoxjnono.github.io/2020/05/01/leeetcode3/"/>
    <id>https://luoxjnono.github.io/2020/05/01/leeetcode3/</id>
    <published>2020-05-01T11:02:04.000Z</published>
    <updated>2020-05-21T11:35:14.399Z</updated>
    
    <content type="html"><![CDATA[<p>刷几条栈相关的题目。</p><a id="more"></a><h4 id="20-有效的括号"><a href="#20-有效的括号" class="headerlink" title="20. 有效的括号"></a><a href="https://leetcode-cn.com/problems/valid-parentheses/" target="_blank" rel="noopener">20. 有效的括号</a></h4><p>给定一个只包括 ‘(’，’)’，’{’，’}’，’[’，’]’ 的字符串，判断字符串是否有效。</p><p>有效字符串需满足：</p><ul><li>左括号必须用相同类型的右括号闭合</li><li>左括号必须以正确的顺序闭合</li><li>注意空字符串可被认为是有效字符串</li></ul><figure class="highlight plain"><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">示例 1:</span><br><span class="line">输入: &quot;()&quot;</span><br><span class="line">输出: true</span><br><span class="line">示例 2:</span><br><span class="line">输入: &quot;()[]&#123;&#125;&quot;</span><br><span class="line">输出: true</span><br></pre></td></tr></table></figure><figure class="highlight c++"><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> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">isValid</span><span class="params">(<span class="built_in">string</span> s)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">stack</span>&lt;<span class="keyword">char</span>&gt; st;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>;i&lt;s.size();i++)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(s[i]==<span class="string">'('</span>||s[i]==<span class="string">'&#123;'</span>||s[i]==<span class="string">'['</span>) <span class="comment">//左括号加入</span></span><br><span class="line">st.push(s[i]);</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span>(st.size()&gt;<span class="number">0</span>&amp;&amp;(s[i]==<span class="string">')'</span>&amp;&amp;st.top()==<span class="string">'('</span>||s[i]==<span class="string">']'</span>&amp;&amp;st.top()==<span class="string">'['</span>||s[i]==<span class="string">'&#125;'</span>&amp;&amp;st.top()==<span class="string">'&#123;'</span>))<span class="comment">//右括号需要判断能否消除,不能消除即出错</span></span><br><span class="line">st.pop();</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span>(st.size()==<span class="number">0</span>)</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;    </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ol start="155"><li>最小栈<br>设计一个支持 push ，pop ，top 操作，并能在常数时间内检索到最小元素的栈。</li></ol><figure class="highlight c++"><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">push(x) —— 将元素 x 推入栈中。</span><br><span class="line">pop() —— 删除栈顶的元素。</span><br><span class="line">top() —— 获取栈顶元素。</span><br><span class="line">getMin() —— 检索栈中的最小元素。</span><br></pre></td></tr></table></figure><p>分析：通常的栈结构，push,pop,top均可以满足，但是 getMin()不能满足，能否增添一个变量用来标记最小值？如果有这个变量，则每次push元素我们都可以将元素进行比较，这样就可以O(1)获取最小元素。但是仔细想想，如果将最小元素pop了出来，那么现在的最下元素怎样标记？只能遍历获得，因此最终是O(n)获取最小元素。</p><p>故需要转换思路，怎样才能动态地存取最小元素？采用辅助栈。</p><p>使用两个栈，一个栈作为正常栈，另一个栈作为辅助栈。辅助栈用来存取当前的最小值，如果最小值更新，则压入新的最小值即可。</p><p><strong>使用两个栈，一个栈作为正常栈，另一个栈作为辅助栈</strong>。辅助栈用来存取当前的最小值，如果最小值更新，则压入新的最小值即可。</p><figure class="highlight plain"><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">入栈 3 </span><br><span class="line">|   |    |   |</span><br><span class="line">|   |    |   |</span><br><span class="line">|_3_|    |_3_|</span><br><span class="line">stack  minStack</span><br><span class="line"></span><br><span class="line">入栈 5 ,5大于minStack的栈顶，故不压入</span><br><span class="line">|   |    |   |</span><br><span class="line">| 5 |    |   |</span><br><span class="line">|_3_|    |_3_|</span><br><span class="line">stack  minStack</span><br><span class="line"></span><br><span class="line">入栈 2 ，2小于最小值栈的栈顶，故将其入栈</span><br><span class="line">| 2 |    |   |</span><br><span class="line">| 5 |    | 2 |</span><br><span class="line">|_3_|    |_3_|</span><br><span class="line">stack  minStack</span><br><span class="line"></span><br><span class="line">出栈 2，发现2是最小栈的栈顶，故minStack也出栈</span><br><span class="line">|   |    |   |</span><br><span class="line">| 5 |    |   |</span><br><span class="line">|_3_|    |_3_|</span><br><span class="line">stack  minStack</span><br><span class="line"></span><br><span class="line">出栈 5，发现5不是最小栈的栈顶，因此minStack 不处理</span><br><span class="line">|   |    |   |</span><br><span class="line">|   |    |   |</span><br><span class="line">|_3_|    |_3_|</span><br><span class="line">stack  minStack</span><br></pre></td></tr></table></figure><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">MinStack</span> &#123;</span></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"><span class="built_in">stack</span>&lt;<span class="keyword">int</span>&gt; data;</span><br><span class="line"><span class="built_in">stack</span>&lt;<span class="keyword">int</span>&gt; min;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">/** initialize your data structure here. */</span></span><br><span class="line">    MinStack() </span><br><span class="line">&#123;</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">void</span> <span class="title">push</span><span class="params">(<span class="keyword">int</span> x)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        data.push(x);</span><br><span class="line"><span class="keyword">if</span>(!min.empty()&amp;&amp;x&lt;=min.top()) <span class="comment">//最小栈不是空且最小栈栈顶元素小于等于x，则入栈 </span></span><br><span class="line">min.push(x); </span><br><span class="line"><span class="keyword">if</span>(min.empty()) <span class="comment">//最小栈为空 </span></span><br><span class="line">        min.push(x);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">pop</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="keyword">if</span>(data.top()==min.top()) <span class="comment">//如果要pop的元素等于最小栈栈顶，则将其pop </span></span><br><span class="line">min.pop();</span><br><span class="line">data.pop();   </span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">top</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">      <span class="keyword">return</span> data.top();  <span class="comment">//返回data的栈顶即可  </span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">getMin</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> min.top(); <span class="comment">//返回min的栈顶即可 </span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h4 id="946-验证栈序列"><a href="#946-验证栈序列" class="headerlink" title="946. 验证栈序列"></a><a href="https://leetcode-cn.com/problems/validate-stack-sequences/" target="_blank" rel="noopener">946. 验证栈序列</a></h4><p>给定 pushed 和 popped 两个序列，每个序列中的 值都不重复，只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时，返回 true；否则，返回 false。</p><figure class="highlight plain"><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">示例 1：</span><br><span class="line">输入：pushed = [1,2,3,4,5], popped = [4,5,3,2,1]</span><br><span class="line">输出：true</span><br><span class="line">解释：我们可以按以下顺序执行：</span><br><span class="line">push(1), push(2), push(3), push(4), pop() -&gt; 4,</span><br><span class="line">push(5), pop() -&gt; 5, pop() -&gt; 3, pop() -&gt; 2, pop() -&gt; 1</span><br><span class="line"></span><br><span class="line">示例 2：</span><br><span class="line">输入：pushed = [1,2,3,4,5], popped = [4,3,5,1,2]</span><br><span class="line">输出：false</span><br><span class="line">解释：1 不能在 2 之前弹出。</span><br></pre></td></tr></table></figure><p>用栈来模拟这个过程即可。</p><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">bool</span> <span class="title">validateStackSequences</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; pushed, <span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; popped)</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line"><span class="built_in">stack</span>&lt;<span class="keyword">int</span>&gt; S;</span><br><span class="line"><span class="keyword">int</span> length=pushed.size();</span><br><span class="line"><span class="keyword">int</span> j=<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;length;i++)</span><br><span class="line">&#123;</span><br><span class="line">S.push(pushed[i]);</span><br><span class="line"><span class="keyword">while</span>(!S.empty()&amp;&amp;S.top()==popped[j]) <span class="comment">//每次push后都要将能消除的消除了</span></span><br><span class="line">&#123;</span><br><span class="line">S.pop();</span><br><span class="line">j++;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span>(!S.empty())</span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>; </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ol start="496"><li>下一个更大元素 I<br>给定两个 没有重复元素 的数组 nums1 和 nums2 ，其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2中的下一个比其大的值。</li></ol><p>nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在，对应位置输出 −1。</p><figure class="highlight plain"><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">示例 1:</span><br><span class="line">输入: nums1 = [4,1,2], nums2 = [1,3,4,2].</span><br><span class="line">输出: [-1,3,-1]</span><br><span class="line">解释:</span><br><span class="line">    对于num1中的数字4，你无法在第二个数组中找到下一个更大的数字，因此输出 -1。</span><br><span class="line">    对于num1中的数字1，第二个数组中数字1右边的下一个较大数字是 3。</span><br><span class="line">    对于num1中的数字2，第二个数组中没有下一个更大的数字，因此输出 -1。</span><br></pre></td></tr></table></figure><p>此处忽略先。</p><h4 id="84-柱状图中最大的矩形"><a href="#84-柱状图中最大的矩形" class="headerlink" title="84. 柱状图中最大的矩形"></a><a href="https://leetcode-cn.com/problems/largest-rectangle-in-histogram/" target="_blank" rel="noopener">84. 柱状图中最大的矩形</a></h4><p>给定 <em>n</em> 个非负整数，用来表示柱状图中各个柱子的高度。每个柱子彼此相邻，且宽度为 1 。</p><p>求在该柱状图中，能够勾勒出来的矩形的最大面积。</p><figure class="highlight plain"><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">输入: [2,1,5,6,2,3]</span><br><span class="line">输出: 10</span><br><span class="line">自己画图看看。</span><br></pre></td></tr></table></figure><p>困难，以后再做。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;刷几条栈相关的题目。&lt;/p&gt;
    
    </summary>
    
      <category term="leetcode" scheme="https://luoxjnono.github.io/categories/leetcode/"/>
    
    
  </entry>
  
  <entry>
    <title>sql中各种连接的区别</title>
    <link href="https://luoxjnono.github.io/2019/09/21/join/"/>
    <id>https://luoxjnono.github.io/2019/09/21/join/</id>
    <published>2019-09-21T10:54:13.000Z</published>
    <updated>2019-09-23T02:43:14.487Z</updated>
    
    <content type="html"><![CDATA[<p>上篇文章讲到了外连接，现在简述一下各种连接之间的区别。</p><a id="more"></a><p>自然连接和等值连接就是保留笛卡尔积关系记录中<strong>所有匹配的数据记录。</strong>根据左右两表的相同列创建一个隐含的join操作，相同列就是两表中列名相同的两列。</p><p>外连接：就是在笛卡尔积的记录中，不仅保留所有匹配的记录，而且还会保留部分不匹配的记录。按照保留不匹配条件数据记录来源可以分为左外连接、右外连接和全外连接。</p><p>右外连接：除了保存所有匹配的数据记录，还保留右表中未匹配的数据记录。</p><p>全外连接：除了保存所有匹配的数据记录，还保留左表和右表中匹配的数据记录。</p><p> 左外连接：除了保存所有匹配的数据记录，还保留左表中未匹配的数据记录。</p><p>具体的问题以后遇到问题了再来这里说一下。</p><p><img src="/2019/09/21/join/.%5C1.jpg" alt="1"></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;上篇文章讲到了外连接，现在简述一下各种连接之间的区别。&lt;/p&gt;
    
    </summary>
    
      <category term="数据库" scheme="https://luoxjnono.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
  </entry>
  
  <entry>
    <title>mysql各种连接以及视图</title>
    <link href="https://luoxjnono.github.io/2019/09/19/sql1/"/>
    <id>https://luoxjnono.github.io/2019/09/19/sql1/</id>
    <published>2019-09-19T11:24:38.000Z</published>
    <updated>2019-09-19T12:24:00.119Z</updated>
    
    <content type="html"><![CDATA[<p>这学期刚学数据库，讲讲遇到的难题。</p><a id="more"></a><p>用两个表（a_table、b_table），关联字段a_table.a_id和b_table.b_id 称为连接，现在我来演示一下MySQL的内连接、外连接（ 左(外)连接、右(外)连接、全(外)连接）。</p><h3 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h3><h4 id="建表"><a href="#建表" class="headerlink" title="建表"></a>建表</h4><figure class="highlight plain"><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">CREATE TABLE `a_table` (</span><br><span class="line">  `a_id` int(11) DEFAULT NULL,</span><br><span class="line">  `a_name` varchar(10) DEFAULT NULL,</span><br><span class="line">  `a_part` varchar(10) DEFAULT NULL</span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8</span><br><span class="line"></span><br><span class="line">CREATE TABLE `b_table` (</span><br><span class="line">  `b_id` int(11) DEFAULT NULL,</span><br><span class="line">  `b_name` varchar(10) DEFAULT NULL,</span><br><span class="line">  `b_part` varchar(10) DEFAULT NULL</span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8</span><br></pre></td></tr></table></figure><p><img src="/2019/09/19/sql1/1.png" alt="1568892709924"></p><h4 id="内连接-inner-join-…-on-…"><a href="#内连接-inner-join-…-on-…" class="headerlink" title="内连接 inner join … on …"></a>内连接 inner join … on …</h4><p>执行语句：<strong>select * from a_table a inner join b_table bon a.a_id = b.b_id;</strong></p><p><img src="/2019/09/19/sql1/20171209133941291.png" alt="img"></p><p>说明返回关联字段相符的记录，及返回交集部分。</p><h4 id="左连接（左外连接）-left-outer-join…-on-…"><a href="#左连接（左外连接）-left-outer-join…-on-…" class="headerlink" title="左连接（左外连接） left  (outer) join… on …"></a>左连接（左外连接） left  (outer) join… on …</h4><p>执行语句：<strong>select * from a_table a left join b_table bon a.a_id = b.b_id;</strong></p><p><img src="https://img-blog.csdn.net/20171209141445680?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcGxnMTc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="img"></p><p>很直观：left join 是left outer join的简写，它的全称是左外连接，是外连接中的一种。左(外)连接，左表(a_table)的记录将会全部表示出来，而右表(b_table)只会显示符合搜索条件的记录。<strong>右表记录不足的地方均为NULL</strong>。</p><p>同理，右外连接反过来就行了，这里就不再说了。</p><p>以上说的都是最基本的情况，仅仅是为了留下最基础的印象，更复杂的情况还请自行解决。</p><h3 id="视图"><a href="#视图" class="headerlink" title="视图"></a>视图</h3><p>背景：关系型数据库中的数据是由一张一张的二维关系表所组成，简单的单表查询只需要遍历一个表，而<strong>复杂的多表查询需要将多个表连接起来进行查询任务。</strong>对于复杂的查询事件，每次查询都需要编写MySQL代码效率低下。为了解决这个问题，数据库提供了视图（view）功能。</p><table><thead><tr><th>操作指令</th><th>代码</th></tr></thead><tbody><tr><td>创建视图</td><td>CREATE VIEW 视图名（ , , , ）AS SELECT ( , , , ) FROM …;</td></tr><tr><td>使用视图</td><td>和表一样</td></tr><tr><td>修改视图</td><td>CREATE OR REPLACE VIEW 视图 AS SELECT() FROM()</td></tr><tr><td>查看视图</td><td>DESC / SHOW FIELDS FROM 视图</td></tr></tbody></table><p>总之，视图时虚拟表，不存储数据，而是按照指定的方式进行查询。说了那么多还是不知道视图时干嘛的，我们直接来看看例子。</p><p>我们现在希望查询一个用户的多项数据，但是通常不是在一个表里面，所以我们此时把他们内连接起来然后select。</p><p><img src="https://img-blog.csdn.net/20170318154707703?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="查询"></p><p>但是有一天我又要查看pid为p003的数据呢，又要写一次查询是吧，那真的是非常浪费时间和体力了，此时我们可以通过视图来实现。</p><p>具体流程</p><p>我们在场面的SELECT语句前面加上CREAT VIEW 视图名 AS就行了。</p><p><img src="https://img-blog.csdn.net/20170318155228367?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="创建视图"></p><p>下次我们再要用直接用视图就行了。</p><p>下面是修改的视图。</p><p><img src="https://img-blog.csdn.net/20170318155945767?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="修改视图"></p><p>下面是查看视图</p><p><img src="https://img-blog.csdn.net/20170320112149745?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="查看视图详情"><img src="https://img-blog.csdn.net/20170320111112130?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="查看视图"></p><p><strong>视图与数据变更</strong></p><p>很简单，普通的更新语句，将表product中的数据进行更新，再通过视图检索：</p><p><img src="https://img-blog.csdn.net/20170320113002561?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="视图与数据变更"></p><p>虽然视图时虚拟表，但是我们仍然可以插入数据。通过下图，我们可以看到，<strong>跨表插入数据系统反馈报错，提示不能修改超过一个表的数据。</strong></p><p><img src="https://img-blog.csdn.net/20170320113217656?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="视图变更数据"></p><p>如果在创建视图的时候制定了“<strong>WITH CHECK OPTION</strong>”，那么更新数据时不能插入或更新不符合视图限制条件的记录。</p><p><img src="https://img-blog.csdn.net/20170320113942203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbW94aWdhbmRhc2h1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="“WITH CHECK OPTION”"></p><p><strong>综上所述，我们需要注意的有两点：</strong></p><ol><li><strong>视图不是表，不直接存储数据，是一张虚拟的表；</strong></li><li><strong>一般情况下，在创建有条件限制的视图时，加上“WITH CHECK OPTION”命令。</strong></li></ol>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;这学期刚学数据库，讲讲遇到的难题。&lt;/p&gt;
    
    </summary>
    
      <category term="数据库" scheme="https://luoxjnono.github.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
      <category term="MySQL" scheme="https://luoxjnono.github.io/tags/MySQL/"/>
    
  </entry>
  
  <entry>
    <title>leetcode26、15</title>
    <link href="https://luoxjnono.github.io/2019/07/08/leetcode26/"/>
    <id>https://luoxjnono.github.io/2019/07/08/leetcode26/</id>
    <published>2019-07-08T01:01:38.000Z</published>
    <updated>2019-07-08T01:11:15.491Z</updated>
    
    <content type="html"><![CDATA[<p>两道双指针问题。</p><a id="more"></a><h4 id="26-删除排序数组中的重复项"><a href="#26-删除排序数组中的重复项" class="headerlink" title="26.删除排序数组中的重复项"></a>26.删除排序数组中的重复项</h4><p><strong>题目描述</strong></p><figure class="highlight plain"><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><br><span class="line"></span><br><span class="line">不要使用额外的数组空间，你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。</span><br></pre></td></tr></table></figure><p><strong>C++</strong></p><figure class="highlight c++"><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> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">removeDuplicates</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (nums.size() &lt;= <span class="number">1</span>) <span class="keyword">return</span> nums.size();</span><br><span class="line">            </span><br><span class="line">        <span class="keyword">int</span> lo = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">int</span> hi = lo + <span class="number">1</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">int</span> n = nums.size();</span><br><span class="line">        <span class="keyword">while</span> (hi &lt; n) &#123;</span><br><span class="line">            <span class="keyword">while</span> (hi &lt; n &amp;&amp; nums[hi] == nums[lo]) hi++;</span><br><span class="line">            nums[++lo] = nums[hi];</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">return</span> lo;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h4 id="15-三数之和（双指针）"><a href="#15-三数之和（双指针）" class="headerlink" title="15. 三数之和（双指针）"></a>15. 三数之和（双指针）</h4><p><strong>问题描述</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">给定一个包含 n 个整数的数组 nums，判断 nums 中是否存在三个元素 a，b，c ，使得 a + b + c = 0 ？</span><br><span class="line">找出所有满足条件且不重复的三元组。</span><br></pre></td></tr></table></figure><p><strong>思路</strong></p><ul><li>因为需要输出所有结果，所以不推荐使用 map 来做</li><li>判断 <code>a + b + c = 0</code>，实际上等价于判断 <code>-a = b + c</code></li><li>基本思路：对数组排序后，对每个 <code>a</code>，用首尾双指针进行遍历，具体过程看代码更清晰</li><li>去重的方法：排序后，跳过相同的数即可</li><li>注意边界条件</li></ul><p><strong>C++</strong></p><figure class="highlight c++"><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></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; threeSum(<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&amp; nums) &#123;</span><br><span class="line">        <span class="keyword">if</span> (nums.size() &lt; <span class="number">3</span>) <span class="keyword">return</span> <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt;();  <span class="comment">// 输入数量小于 3 直接退出</span></span><br><span class="line"></span><br><span class="line">        sort(nums.begin(), nums.end());                     <span class="comment">// 排序</span></span><br><span class="line"></span><br><span class="line">        <span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt;&gt; ret;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt;= nums.size() - <span class="number">3</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (i &gt; <span class="number">0</span> &amp;&amp; nums[i] == nums[i - <span class="number">1</span>]) <span class="keyword">continue</span>;  <span class="comment">// 跳过第一个数相同的情况</span></span><br><span class="line"></span><br><span class="line">            <span class="keyword">int</span> target = -nums[i];</span><br><span class="line">            <span class="keyword">int</span> lo = i + <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">int</span> hi = nums.size() - <span class="number">1</span>;</span><br><span class="line">            <span class="keyword">while</span> (lo &lt; hi) &#123;</span><br><span class="line">                <span class="keyword">if</span> (nums[lo] + nums[hi] &lt; target)</span><br><span class="line">                    lo++;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (nums[lo] + nums[hi] &gt; target)</span><br><span class="line">                    hi--;</span><br><span class="line">                <span class="keyword">else</span> &#123;</span><br><span class="line">                    ret.push_back(&#123; nums[i], nums[lo], nums[hi] &#125;);</span><br><span class="line">                    lo++, hi--;   <span class="comment">// 不要忘了这双指针都要移动</span></span><br><span class="line"></span><br><span class="line">                    <span class="keyword">while</span> (lo &lt; hi &amp;&amp; nums[lo] == nums[lo - <span class="number">1</span>]) lo++;   <span class="comment">// 跳过第二个数相同的情况</span></span><br><span class="line">                    <span class="keyword">while</span> (lo &lt; hi &amp;&amp; nums[hi] == nums[hi + <span class="number">1</span>]) hi--;   <span class="comment">// 跳过第三个数相同的情况</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> ret;</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;两道双指针问题。&lt;/p&gt;
    
    </summary>
    
      <category term="leetcode" scheme="https://luoxjnono.github.io/categories/leetcode/"/>
    
    
  </entry>
  
  <entry>
    <title>leetcode200.岛屿的个数</title>
    <link href="https://luoxjnono.github.io/2019/07/07/leetcode200/"/>
    <id>https://luoxjnono.github.io/2019/07/07/leetcode200/</id>
    <published>2019-07-07T04:17:57.000Z</published>
    <updated>2019-07-07T04:21:42.643Z</updated>
    
    <content type="html"><![CDATA[<p>经典的dfs、bfs问题。</p><a id="more"></a><p><strong>问题描述</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">给定一个由 &apos;1&apos;（陆地）和 &apos;0&apos;（水）组成的的二维网格，计算岛屿的数量。一个岛被水包围，并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。</span><br><span class="line"></span><br><span class="line">示例 1:</span><br><span class="line">  输入:</span><br><span class="line">  11110</span><br><span class="line">  11010</span><br><span class="line">  11000</span><br><span class="line">  00000</span><br><span class="line">  输出: 1</span><br><span class="line">示例 2:</span><br><span class="line">  输入:</span><br><span class="line">  11000</span><br><span class="line">  11000</span><br><span class="line">  00100</span><br><span class="line">  00011</span><br><span class="line">  输出: 3</span><br></pre></td></tr></table></figure><p><strong>思路</strong></p><ul><li>经典的 DFS | BFS 问题，搜索连通域的个数</li></ul><p><strong>Code</strong>: DFS</p><p>思路很简单，通过一个dfs找出连通的岛屿然后标志为0，如此以往直至没有1。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">class Solution &#123;</span><br><span class="line">    int n, m;</span><br><span class="line">public:</span><br><span class="line">    int numIslands(vector&lt;vector&lt;char&gt;&gt;&amp; grid) &#123;  // 注意：是 char 不是 int</span><br><span class="line">        if (!grid.empty()) n = grid.size();</span><br><span class="line">        else return 0;</span><br><span class="line">        if (!grid[0].empty()) m = grid[0].size();</span><br><span class="line">        else return 0;</span><br><span class="line">        </span><br><span class="line">        int ret = 0;</span><br><span class="line">        for (int i=0; i&lt;n; i++)</span><br><span class="line">            for (int j=0; j&lt;m; j++) &#123;</span><br><span class="line">                if (grid[i][j] != &apos;0&apos;) &#123;</span><br><span class="line">                    ret += 1;</span><br><span class="line">                    dfs(grid, i, j);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        </span><br><span class="line">        return ret;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    void dfs(vector&lt;vector&lt;char&gt;&gt;&amp; grid, int i, int j) &#123;</span><br><span class="line">        if (i &lt; 0 || i &gt;= n || j &lt; 0 || j &gt;= m )  // 边界判断（递归基）</span><br><span class="line">            return;</span><br><span class="line">            </span><br><span class="line">        if (grid[i][j] == &apos;0&apos;)</span><br><span class="line">            return;</span><br><span class="line">        else &#123;</span><br><span class="line">            grid[i][j] = &apos;0&apos;;  // 如果不想修改原数据，可以复制一个</span><br><span class="line">            // 4 个方向 dfs；一些问题会扩展成 8 个方向，本质上没有区别</span><br><span class="line">            dfs(grid, i+1, j);</span><br><span class="line">            dfs(grid, i-1, j);</span><br><span class="line">            dfs(grid, i, j+1);</span><br><span class="line">            dfs(grid, i, j-1);</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>Code</strong>: BFS</p><figure class="highlight c++"><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="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line">    <span class="keyword">int</span> n, m;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">numIslands</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">char</span>&gt;&gt;&amp; grid)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (!grid.empty()) n = grid.size();</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">if</span> (!grid[<span class="number">0</span>].empty()) m = grid[<span class="number">0</span>].size();</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">int</span> ret = <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++)</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> (grid[i][j] != <span class="string">'0'</span>) &#123;</span><br><span class="line">                    ret += <span class="number">1</span>;</span><br><span class="line">                    bfs(grid, 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> ret;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">bfs</span><span class="params">(<span class="built_in">vector</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">char</span>&gt;&gt;&amp; grid, <span class="keyword">int</span> i, <span class="keyword">int</span> j)</span> </span>&#123;</span><br><span class="line">        <span class="built_in">queue</span>&lt;<span class="built_in">vector</span>&lt;<span class="keyword">int</span>&gt; &gt; q;</span><br><span class="line">        </span><br><span class="line">        q.push(&#123;i,j&#125;);</span><br><span class="line">        grid[i][j] = <span class="string">'0'</span>;</span><br><span class="line">        <span class="keyword">while</span> (!q.empty()) &#123;</span><br><span class="line">            i = q.front()[<span class="number">0</span>], j = q.front()[<span class="number">1</span>];</span><br><span class="line">            q.pop();  <span class="comment">// 当前节点出队</span></span><br><span class="line">                      <span class="comment">// 当前节点的四周节点依次入队</span></span><br><span class="line">            <span class="keyword">if</span> (i &gt; <span class="number">0</span> &amp;&amp; grid[i<span class="number">-1</span>][j] == <span class="string">'1'</span>) &#123;</span><br><span class="line">                q.push(&#123;i<span class="number">-1</span>,j&#125;);</span><br><span class="line">                grid[i<span class="number">-1</span>][j] = <span class="string">'0'</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (i &lt; n<span class="number">-1</span> &amp;&amp; grid[i+<span class="number">1</span>][j] == <span class="string">'1'</span>) &#123;</span><br><span class="line">                q.push(&#123;i+<span class="number">1</span>,j&#125;);</span><br><span class="line">                grid[i+<span class="number">1</span>][j] = <span class="string">'0'</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (j &gt; <span class="number">0</span> &amp;&amp; grid[i][j<span class="number">-1</span>] == <span class="string">'1'</span>) &#123;</span><br><span class="line">                q.push(&#123;i,j<span class="number">-1</span>&#125;);</span><br><span class="line">                grid[i][j<span class="number">-1</span>] = <span class="string">'0'</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (j &lt; m<span class="number">-1</span> &amp;&amp; grid[i][j+<span class="number">1</span>] == <span class="string">'1'</span>) &#123;</span><br><span class="line">                q.push(&#123;i,j+<span class="number">1</span>&#125;);</span><br><span class="line">                grid[i][j+<span class="number">1</span>] = <span class="string">'0'</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></pre></td></tr></table></figure><p>总结：dfs比较容易实现而且效率更高。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;经典的dfs、bfs问题。&lt;/p&gt;
    
    </summary>
    
      <category term="leetcode" scheme="https://luoxjnono.github.io/categories/leetcode/"/>
    
    
  </entry>
  
  <entry>
    <title>leetcode124. 二叉树中的最大路径和（DFS）</title>
    <link href="https://luoxjnono.github.io/2019/07/06/leetcode124/"/>
    <id>https://luoxjnono.github.io/2019/07/06/leetcode124/</id>
    <published>2019-07-06T08:21:16.000Z</published>
    <updated>2019-07-06T08:43:38.662Z</updated>
    
    <content type="html"><![CDATA[<p>二叉树dfs操作</p><a id="more"></a><p><strong>题目描述</strong></p><figure class="highlight plain"><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><br><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,3]</span><br><span class="line"></span><br><span class="line">       1</span><br><span class="line">      / \</span><br><span class="line">     2   3</span><br><span class="line"></span><br><span class="line">输出: 6</span><br></pre></td></tr></table></figure><p><strong>思路</strong></p><ul><li><p>利用一个子函数，求出每个节点<strong>最大深度路径和</strong>（做法类似求<strong>树的深度</strong>）</p><ul><li>注意，因为节点中的值可能为负数，所以最大深度路径和不一定都会到达叶子</li><li>同样，最大深度路径和也可能为负数，此时应该返回 0</li></ul></li><li><p>接着对每个节点，<strong>经过该节点</strong>的最大路径和为</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">该节点的值 + 左子树的最大深度路径和 + 右子树的最大深度路径和</span><br></pre></td></tr></table></figure></li><li><p><strong>空树的最大路径和</strong>应该为负无穷（作为递归基）；</p></li></ul><p><strong>C++</strong></p><p>代码实现：</p><figure class="highlight c++"><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 class="class"><span class="keyword">class</span> <span class="title">Solution</span> &#123;</span></span><br><span class="line">    <span class="keyword">const</span> <span class="keyword">int</span> inf = <span class="number">0x3f3f3f3f</span>;</span><br><span class="line">    <span class="keyword">int</span> ret = -inf;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">maxDeepSum</span><span class="params">(TreeNode* node)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span> (node == <span class="literal">nullptr</span>)</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> l_sum = max(<span class="number">0</span>, maxDeepSum(node-&gt;left));</span><br><span class="line">        <span class="keyword">int</span> r_sum = max(<span class="number">0</span>, maxDeepSum(node-&gt;right));</span><br><span class="line"></span><br><span class="line">        ret = max(ret, node-&gt;val + l_sum + r_sum);</span><br><span class="line">        <span class="keyword">return</span> node-&gt;val + max(l_sum, r_sum);</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">maxPathSum</span><span class="params">(TreeNode* root)</span> </span>&#123;</span><br><span class="line">        maxDeepSum(root);</span><br><span class="line">        <span class="keyword">return</span> ret;</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;二叉树dfs操作&lt;/p&gt;
    
    </summary>
    
      <category term="leetcode" scheme="https://luoxjnono.github.io/categories/leetcode/"/>
    
    
  </entry>
  
  <entry>
    <title>操作系统之内存管理</title>
    <link href="https://luoxjnono.github.io/2019/06/24/memo/"/>
    <id>https://luoxjnono.github.io/2019/06/24/memo/</id>
    <published>2019-06-24T07:53:59.000Z</published>
    <updated>2019-06-24T09:25:19.911Z</updated>
    
    <content type="html"><![CDATA[<p>内存管理部分</p><a id="more"></a><h3 id="内存管理"><a href="#内存管理" class="headerlink" title="内存管理"></a>内存管理</h3><p>逻辑地址：CPU所生成的地址</p><p>物理地址：内存单元看到的地址，用户程序绝不会看到的</p><p>逻辑地址–&gt;MMU(内存管理单元)–&gt;物理地址</p><p>连续内存分配：位每个进程分配一个连续的内存区域</p><p>首次适应、最佳适应、最差适应。</p><p>外部碎片：总的可用的内存之和可以满足请求，但是不连续</p><p>内部碎片：分配但未使用</p><h4 id="分页"><a href="#分页" class="headerlink" title="分页"></a>分页</h4><p>将物理内存分为固定大小的块，称为帧，逻辑内存也划分同样大小的块，称为页</p><p><img src="/2019/06/24/memo/1561364082754.png" alt="1561364082754"></p><p>分页是有内部碎片的，因为最后一帧可能用不完</p><p>TLB：</p><p><img src="/2019/06/24/memo/1561364454926.png" alt="1561364454926"></p><p>有效访问时间：EAT = (1 + e) a + (2 + e)(1 – a) = 2 + e – a</p><h4 id="分段"><a href="#分段" class="headerlink" title="分段"></a>分段</h4><p>程序相关的数据被划分为一个段，有段号+段偏移</p><p><img src="/2019/06/24/memo/1561365336756.png" alt="1561365336756"></p><p><img src="/2019/06/24/memo/1561365427153.png" alt="1561365427153"></p><p>以上是分段和分页结合</p><h3 id="虚拟内存"><a href="#虚拟内存" class="headerlink" title="虚拟内存"></a>虚拟内存</h3><p>感觉好多我都在ucore的实验报告中写过还很详细，不想写了，求求你摇了我吧。</p><p>两个特点：进程中所有存储器访问都是逻辑地址，这些逻辑地址在运行时被转换为物理地址。     一个进程可以划分为许多块，在执行过程中，这些块不需要连续地位于主存中</p><p>两个效果：主存中保留多个进程，进程可以比主存的全部空间还大</p><p>按需调页：只有程序需要时才载入页，那些从未访问的页不会调入到物理内存中</p><p>一种极端的情况就是所有的页都不在内存中，就开始执行进程，进程会立即出现页错误，并不断地出现页错误直到所有所需的页均在内存中</p><p>性能评价：</p><p>有效访问时间：参照页</p><p>copy on right：ucore做过</p><p>页面置换算法：具体在另一篇博客介绍了</p><p>FIFO: </p><p>算法：总是淘汰最先调入主存的那一页，或者说在主存中驻留时间最长的那一页（常驻的除外）。 </p><p>理由：最早调入内存的页面，其不再被访问的可能性最大。</p><p>最佳替换算法（OPT）：</p><p><strong>算法：</strong>调入一页而必须淘汰一个旧页时，所淘汰的页应该是<strong>以后不再访问的页或距现在最长时间后再访问的页</strong>。</p><p><strong>特点：</strong>不是实际可行的算法，可用来作为衡量各种具体算法的标准，具有理论意义。</p><p>最近最少使用算法（LRU）：</p><p>算法：淘汰的页面是在最近一段时间里较久未被访问的那页。</p><p>原理：根据程序局部性原理，那些刚被使用过的页面，可能马上还要被使用，而在较长时间里未被使用的页面，可能不会马上使用到。</p><p><strong>颠簸</strong></p><p>新进程–全局置换算法–页错误–调页–大家都出现页错误–设备不多–就绪队列变空–cpu利用率下降–增加多道程序———系统颠簸</p><p>频繁的也调度行为称为颠簸，若一个进程在换页上所用的时间多于执行时间，那么这个进程就在颠簸。</p><p><img src="/2019/06/24/memo/1561366840612.png" alt="1561366840612"></p><p>通过局部置换算法（或优先置换算法）能够限制系统颠簸。</p><p><strong>Global replacement</strong> – process selects a replacement frame from the set of all frames; one process can take a frame from another</p><p><strong>Local replacement</strong> – each process selects from only its own set of allocated frames</p><p>全局置换算法—不能控制其页错误率，有着更好的吞吐率；</p><p>局部置换算法—不能利用其它进程的空闲内存；</p><p>局部模型：研究进程实际正在使用多少帧</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;内存管理部分&lt;/p&gt;
    
    </summary>
    
      <category term="操作系统" scheme="https://luoxjnono.github.io/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    
  </entry>
  
  <entry>
    <title>操作系统之文件系统</title>
    <link href="https://luoxjnono.github.io/2019/06/24/file/"/>
    <id>https://luoxjnono.github.io/2019/06/24/file/</id>
    <published>2019-06-24T06:48:15.000Z</published>
    <updated>2019-06-24T09:29:21.470Z</updated>
    
    <content type="html"><![CDATA[<p>文件管理部分</p><a id="more"></a><p>文件系统里面常用的分配方法：</p><p><img src="/2019/06/24/file/1561359713561.png" alt="1561359713561"></p><p><strong>连续分配</strong>：创建文件时，给文件分配一组连续的块</p><p>优点：</p><p>简单，支持顺序存取和随机存取，顺序存取速度快</p><p>缺点：</p><p>外部碎片，预分配</p><p><strong>链式分配方法</strong>：创建文件时，每块包含指向下一块的指针</p><p>优点：提高了磁盘空间利用率，不存则外部碎片的问题，有利于问价插入、删除和扩充</p><p>缺点：存取速度慢，适宜顺去存取，不适宜随机存取，链接指针占用一定的空间</p><p><strong>索引分配</strong>：创建文件时，信息存放在不连续的物理快中，在文件分配表中有一个一级索引。支持顺序和直接访问，最普遍的一种文件分配形式。</p><p>优点：</p><p>顺序+随机存取，文件动态增长、删除和插入，充分利用外存空间</p><p>缺点：</p><p>需要访问两次内存、索引表、具体物理快，索引表本身带来了系统开销</p><p><strong>空闲空间管理</strong>：</p><p>位向量：0101010表示</p><p>链表：将空闲磁盘块连接起来</p><p>组：n个空闲块的地址放在第一个空闲块中，随后一块包含另外n个空闲块地址</p><p>计数：参考连续分配</p><p><strong>大规模存储结构</strong></p><p>寻道时间：磁头定位到磁道所需要的时间</p><p>旋转延迟：磁头到达扇区开始位置的时间</p><p>传送时间：传送所需要的时间</p><p><img src="/2019/06/24/file/1561362186684.png" alt="1561362186684"></p><p><strong>磁盘调度算法</strong>：</p><p>FCFS：先到先服务</p><p>Pickup：搭便车，经过时顺带调度</p><p>SSTF：最短寻道时间优先算法，离现在最近的先调度（<strong>较为普遍</strong>）</p><p>SCAN：电梯算法，来回（到端点处）</p><p>C-SCAN：只在去的时候调度</p><p>C-LOOK：和C-SCAN的区别是不到端点</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;文件管理部分&lt;/p&gt;
    
    </summary>
    
      <category term="操作系统" scheme="https://luoxjnono.github.io/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    
  </entry>
  
  <entry>
    <title>深度学习基础--卷积神经网络CNN</title>
    <link href="https://luoxjnono.github.io/2019/06/21/cnn/"/>
    <id>https://luoxjnono.github.io/2019/06/21/cnn/</id>
    <published>2019-06-21T03:03:56.000Z</published>
    <updated>2019-06-22T12:39:41.205Z</updated>
    
    <content type="html"><![CDATA[<p>卷积神经网络（<strong>Convolutional Neural Network</strong>）是一种前馈神经网络，它的人工神经元可以响应一部分覆盖范围内的周围单元，对于大型图像处理有出色表现。</p><a id="more"></a><h3 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h3><p>CNN具有可学习的权重和偏置常量(biases)的神经元组成。每个神经元都接收一些输入，并做一些点积计算，输出是每个分类的分数，普通神经网络里的一些计算技巧到这里依旧适用。</p><p>卷积神经网络默认输入是图像，可以让我们把特定的性质编码入网络结构，使我们的前馈函数更加有效率，并减少了大量参数。</p><h3 id="人工神经网络"><a href="#人工神经网络" class="headerlink" title="人工神经网络"></a>人工神经网络</h3><h5 id="神经元"><a href="#神经元" class="headerlink" title="神经元"></a><strong>神经元</strong></h5><p>神经网络由大量的神经元相互连接而成。每个神经元接受线性组合的输入后，最开始只是<strong>简单的线性加权</strong>，后来给每个神经元<strong>加上了非线性的激活函数，从而进行非线性变换后输出</strong>。每两个神经元之间的连接代表加权值，称之为权重（weight）。不同的权重和激活函数，则会导致神经网络不同的输出。</p><p>激活过程就像神经传输一样，一个激活然后传下去，每个神经元如下：</p><p><img src="/2019/06/21/cnn/20160716131107406.jpg" alt="img"></p><p>可以看出，这是 基本wx + b的形式，具体某个参数的含义也很明显了，其中b为偏置bias，可以理解成为更好达到目标而做调整的偏置项。。</p><p>举个例子：参照感知器。</p><h5 id="激活函数"><a href="#激活函数" class="headerlink" title="激活函数"></a><strong>激活函数</strong></h5><p>常用的非线性激活函数有sigmoid、tanh、relu等等，sigmoid函数我们前面介绍过了，但是把值域限制在0，1区间有什么好处呢？就是更好的分类。这里我们可以感受到偏置的作用：</p><p><img src="/2019/06/21/cnn/20190218213452278.jpg" alt="img"></p><h5 id="神经网络"><a href="#神经网络" class="headerlink" title="神经网络"></a><strong>神经网络</strong></h5><p>将多个神经元组织在一起就成了神经网络了，下面是一个简单的三层神经网络：</p><p><img src="/2019/06/21/cnn/20160703140745657.jpg" alt="img"></p><p>从左至右分别为输入层（输入向量）、隐藏层（是输入层和输出层之间众多神经元和链接组成的各个层面，含有激活函数）、输出层（输出向量）。</p><p>同时，每一层都可能由单个或多个神经元组成，每一层的输出将会作为下一层的输入数据。</p><p>下面是张量形式的一种表现，偏置项：x0、a0：</p><p><img src="/2019/06/21/cnn/20160703112107755.jpg" alt="20160703112107755"></p><h3 id="层次结构"><a href="#层次结构" class="headerlink" title="层次结构"></a>层次结构</h3><p>下面是cs231中给出的层次结构的例子：</p><p><img src="/2019/06/21/cnn/20160702205047459.jpg" alt="img"></p><ul><li>最左边是数据输入层，对数据做一些处理，比如去均值（把输入数据各个维度都中心化为0，避免数据过多偏差，影响训练效果）、归一化（把所有的数据都归一到同样的范围）、PCA/白化等等。CNN只对训练集做“去均值”这一步。</li></ul><p>然后是中间：</p><ul><li>CONV：<strong>卷积计算层</strong>，线性乘积求和。</li><li><strong>RELU</strong>：激活函数的一种。</li><li>POOL：<strong>池化层</strong>，简言之，即取区域平均或最大。</li></ul><p>最右边是全连接层。</p><p>你应该能想到卷积计算层是CNN的核心。</p><h3 id="卷积计算层"><a href="#卷积计算层" class="headerlink" title="卷积计算层"></a>卷积计算层</h3><p>卷积：对图像（不同的数据窗口数据）和滤波矩阵（因为每个神经元的多个权重固定，所以又可以看做一个恒定的滤波器filter）做<strong>内积</strong>（逐个元素相乘再求和）的操作就是所谓的『卷积』操作，也是卷积神经网络的名字来源。</p><p>下面Z的形成便是非严格意义上用了滤波器</p><p><img src="https://img-blog.csdn.net/20160716131107406" alt="img"></p><p>总之是每个神经元的权重问题</p><p>图像上的卷积</p><p>左边是图像输入，中间部分就是滤波器filter（带着一组固定权重的神经元），不同的滤波器filter会得到不同的输出数据，比如颜色深浅、轮廓。相当于如果想提取图像的不同特征，则用不同的滤波器filter，提取想要的关于图像的特定信息：颜色深浅或轮廓。<img src="/2019/06/21/cnn/20160702214116669.jpg" alt="img"></p><p>我们很自然的想到，在滤波的过程中有下面几个参数：</p><p>　<strong>a. 深度depth</strong>：神经元个数，决定输出的depth厚度。同时代表滤波器个数。<br>　<strong>b. 步长stride</strong>：决定滑动多少步可以到边缘。                                                                         c. 填充值zero-padding：在外围边缘补充若干圈0，使能滑倒末尾</p><p>下面是一个例子：</p><p><img src="/2019/06/21/cnn/20160707204048899.gif" alt="img"></p><ul><li><p>左边是输入（<strong>7*7*3</strong>中，7*7代表图像的像素/长宽，3代表R、G、B 三个颜色通道）</p></li><li><p>中间部分是两个不同的滤波器</p></li><li><p>最右边则是两个不同的输出</p></li></ul><p>我们可以看到，每次滤波器都是针对某一局部的数据窗口进行卷积，这就是所谓的CNN中的<strong>局部感知</strong>机制，因为一下子接受不了那么多信息，但是局部也是有侧重的，比如看美女，对脸、胸、腿是重点关注，所以这3个输入的权重相对较大。</p><p>与此同时，数据窗口滑动，导致输入在变化，但中间滤波器Filter w0的权重（即每个神经元连接数据窗口的权重）是固定不变的，这个权重不变即所谓的CNN中的<strong>参数（权重）共享</strong>机制。</p><ul><li>再打个比方，某人环游全世界，所看到的信息在变，但采集信息的双眼不变。btw，不同人的双眼 看同一个局部信息 所感受到的不同，即一千个读者有一千个哈姆雷特，所以不同的滤波器 就像不同的双眼，不同的人有着不同的反馈结果。</li></ul><h3 id="激励层"><a href="#激励层" class="headerlink" title="激励层"></a>激励层</h3><p>上次我们介绍了激活函数sigmoid，但实际梯度下降中，sigmoid容易饱和、造成终止梯度传递，且没有0中心化，我们可以尝试ReLU。</p><p> ReLU的优点是收敛快，求梯度简单。</p><h3 id="池化pool层"><a href="#池化pool层" class="headerlink" title="池化pool层"></a>池化pool层</h3><p>​    前头说了，池化，简言之，即取区域平均或最大，如下图所示（图引自cs231n），很好理解。</p><p><img src="/2019/06/21/cnn/20160703121026432.jpg" alt="img"></p><p>参考资料：</p><p><a href="https://blog.csdn.net/v_JULY_v/article/details/51812459" target="_blank" rel="noopener">https://blog.csdn.net/v_JULY_v/article/details/51812459</a></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;卷积神经网络（&lt;strong&gt;Convolutional Neural Network&lt;/strong&gt;）是一种前馈神经网络，它的人工神经元可以响应一部分覆盖范围内的周围单元，对于大型图像处理有出色表现。&lt;/p&gt;
    
    </summary>
    
      <category term="深度学习" scheme="https://luoxjnono.github.io/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/"/>
    
    
  </entry>
  
  <entry>
    <title>消极学习和积极学习</title>
    <link href="https://luoxjnono.github.io/2019/06/20/learn/"/>
    <id>https://luoxjnono.github.io/2019/06/20/learn/</id>
    <published>2019-06-20T13:41:04.000Z</published>
    <updated>2019-06-20T13:52:06.873Z</updated>
    
    <content type="html"><![CDATA[<p>上一篇我们介绍了knn，了解了它是一种lazy learning的算法，那么什么是eager learning呢？</p><a id="more"></a><p><strong>积极学习（Eager Learning）</strong></p><p>在进行某种判断（例如，确定一个点的分类或者回归中确定某个点对应的函数值）之前，先利用训练数据进行训练得到一个目标函数，待需要时就只利用训练好的函数进行决策，显然这是一种一劳永逸的方法。</p><p><strong>典型的算法：</strong></p><p>SVM、Find-S算法、候选消除算法、决策树、人工神经网络、贝叶斯方法;</p><p><strong>消极学习(Lazy Learning)</strong></p><p>这种学习方式指不是根据样本建立一般化的目标函数并确定其参数，而是简单地把训练样本存储起来，直到需要分类新的实例时才分析其与所存储样例的关系，据此确定新实例的目标函数值。也就是说这种学习方式只有到了需要决策时才会利用已有数据进行决策，而在这之前不会经历 Eager Learning所拥有的训练过程。</p><p><strong>典型的算法：</strong></p><p>KNN、局部加权回归、基于案例的推理</p><p>比较：</p><p>Lazy Learning是一个局部的近似，然而虽然不需要训练，它的复杂度还是需要 O(n)，而且要的存储空间比较大 、决策过程比较慢。</p><p>Eager Learning考虑到了所有训练样本，说明它是一个全局的近似，虽然它需要耗费训练时间，但它的决策时间基本为0.</p><p>总之，不管是哪种学习方法，我的电脑都是跑不动的。:fu:</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;上一篇我们介绍了knn，了解了它是一种lazy learning的算法，那么什么是eager learning呢？&lt;/p&gt;
    
    </summary>
    
      <category term="机器学习" scheme="https://luoxjnono.github.io/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
    
  </entry>
  
  <entry>
    <title>机器学习算法之KNN</title>
    <link href="https://luoxjnono.github.io/2019/06/20/knn/"/>
    <id>https://luoxjnono.github.io/2019/06/20/knn/</id>
    <published>2019-06-20T13:15:25.000Z</published>
    <updated>2019-06-20T14:04:37.419Z</updated>
    
    <content type="html"><![CDATA[<p>k-最近邻是<strong>基于实例的学习</strong>方法中最基本的算法。</p><a id="more"></a><h3 id="基本描述"><a href="#基本描述" class="headerlink" title="基本描述"></a>基本描述</h3><p>K最近邻(kNN，k-NearestNeighbor)分类算法，它的工作原理为：给定测试样本，基于某种距离度量找出训练集中与其<strong>最靠近的k个训练样本</strong>，然后基于这k个“邻居”的信息来进行预测。</p><p>在回归任务中可使用“平均法”，即将这k个样本的实值输出标记的平均值作为预测结果；还可基于距离远近进行加权平均或加权投票，距离越近的样本权重越大。<strong>既是最简单的机器学习算法之一，也是基于实例的学习方法中最基本的，又是最好的文本分类算法之一。</strong></p><p>通过上面的描述，我们可以得知算法理论步骤：</p><figure class="highlight plain"><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">1）算距离：给定测试对象，计算它与训练集中的每个对象的距离</span><br><span class="line">2）找邻居：圈定距离最近的k个训练对象，作为测试对象的近邻</span><br><span class="line">3）做分类：根据这k个近邻归属的主要类别，来对测试对象分类</span><br></pre></td></tr></table></figure><h3 id="算法优缺点"><a href="#算法优缺点" class="headerlink" title="算法优缺点"></a>算法优缺点</h3><p><strong>先来说说优点：</strong></p><p>①简单，易于理解，易于实现，无需参数估计，无需训练;<br>②精度高，对异常值不敏感（个别噪音数据对结果的影响不是很大）;<br>③适合对稀有事件进行分类;<br>④特别适合于多分类问题(multi-modal,对象具有多个类别标签)，KNN要比SVM表现要好</p><p><strong>再来说说缺点：</strong></p><p>①KNN算法是懒散学习方法（lazy learning,基本上不学习），一些积极学习的算法要快很多。<br>②类别评分不是规格化的（不像概率评分）。<br>③输出的可解释性不强，例如决策树的可解释性较强。                                                    ④还有一点也很容易想到，就是如果我们样本很不平衡的时候，有可能导致当输入一个新样本时，该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本，某一类的样本数量很大，那么或者这类样本并不接近目标样本，或者这类样本很靠近目标样本。不过这个时候我们可以通过采取权值的方法改进（比如最近权值高）。</p><p><img src="/2019/06/20/knn/20150805204307882.png" alt="20150805204307882"></p><h3 id="算法实现"><a href="#算法实现" class="headerlink" title="算法实现"></a>算法实现</h3><p>算法应该很容易实现，下面来看看在kaggle中的手写数字识别中的实现：</p><blockquote><p>首先我们完成将文件转化成向量的函数，方便读取：</p></blockquote><figure class="highlight python"><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="comment"># convert image to vector  </span></span><br><span class="line"><span class="function"><span class="keyword">def</span>  <span class="title">img2vector</span><span class="params">(filename)</span>:</span>  </span><br><span class="line">    rows = <span class="number">32</span>  </span><br><span class="line">    cols = <span class="number">32</span>  </span><br><span class="line">    imgVector = zeros((<span class="number">1</span>, rows * cols))   </span><br><span class="line">    fileIn = open(filename)  </span><br><span class="line">    <span class="keyword">for</span> row <span class="keyword">in</span> xrange(rows):  </span><br><span class="line">        lineStr = fileIn.readline()  </span><br><span class="line">        <span class="keyword">for</span> col <span class="keyword">in</span> xrange(cols):  </span><br><span class="line">            imgVector[<span class="number">0</span>, row * <span class="number">32</span> + col] = int(lineStr[col])  </span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> imgVector</span><br></pre></td></tr></table></figure><blockquote><p>然后我们加载整个数据库</p></blockquote><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># load dataSet  </span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">loadDataSet</span><span class="params">()</span>:</span>  </span><br><span class="line">    <span class="comment">## step 1: Getting training set  </span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"---Getting training set..."</span>  </span><br><span class="line">    dataSetDir = <span class="string">'./'</span></span><br><span class="line">    trainingFileList = os.listdir(dataSetDir + <span class="string">'trainingDigits'</span>) <span class="comment"># load the training set  </span></span><br><span class="line">    numSamples = len(trainingFileList)  </span><br><span class="line"> </span><br><span class="line">    train_x = zeros((numSamples, <span class="number">1024</span>))  </span><br><span class="line">    train_y = []  </span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> xrange(numSamples):  </span><br><span class="line">        filename = trainingFileList[i]  </span><br><span class="line"> </span><br><span class="line">        <span class="comment"># get train_x  </span></span><br><span class="line">        train_x[i, :] = img2vector(dataSetDir + <span class="string">'trainingDigits/%s'</span> % filename)   </span><br><span class="line"> </span><br><span class="line">        <span class="comment"># get label from file name such as "1_18.txt"  </span></span><br><span class="line">        label = int(filename.split(<span class="string">'_'</span>)[<span class="number">0</span>]) <span class="comment"># return 1  </span></span><br><span class="line">        train_y.append(label)  </span><br><span class="line"> </span><br><span class="line">    <span class="comment">## step 2: Getting testing set  </span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"---Getting testing set..."</span>  </span><br><span class="line">    testingFileList = os.listdir(dataSetDir + <span class="string">'testDigits'</span>) <span class="comment"># load the testing set  </span></span><br><span class="line">    numSamples = len(testingFileList)  </span><br><span class="line">    test_x = zeros((numSamples, <span class="number">1024</span>))  </span><br><span class="line">    test_y = []  </span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> xrange(numSamples):  </span><br><span class="line">        filename = testingFileList[i]  </span><br><span class="line"> </span><br><span class="line">        <span class="comment"># get train_x  </span></span><br><span class="line">        test_x[i, :] = img2vector(dataSetDir + <span class="string">'testDigits/%s'</span> % filename)   </span><br><span class="line"> </span><br><span class="line">        <span class="comment"># get label from file name such as "1_18.txt"  </span></span><br><span class="line">        label = int(filename.split(<span class="string">'_'</span>)[<span class="number">0</span>]) <span class="comment"># return 1  </span></span><br><span class="line">        test_y.append(label)  </span><br><span class="line"> </span><br><span class="line">    <span class="keyword">return</span> train_x, train_y, test_x, test_y</span><br></pre></td></tr></table></figure><blockquote><p>然后就是我们的knn算法了：</p></blockquote><figure class="highlight python"><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"># classify using kNN  </span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">kNNClassify</span><span class="params">(newInput, dataSet, labels, k)</span>:</span>  </span><br><span class="line">    numSamples = dataSet.shape[<span class="number">0</span>] <span class="comment"># shape[0] stands for the num of row  </span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">## step 1:计算距离</span></span><br><span class="line">    <span class="comment"># tile(A, reps): Construct an array by repeating A reps times  </span></span><br><span class="line">    <span class="comment"># the following copy numSamples rows for dataSet  </span></span><br><span class="line">    diff = tile(newInput, (numSamples, <span class="number">1</span>)) - dataSet <span class="comment"># Subtract element-wise</span></span><br><span class="line">    squaredDiff = diff ** <span class="number">2</span> <span class="comment"># squared for the subtract  </span></span><br><span class="line">    squaredDist = sum(squaredDiff, axis = <span class="number">1</span>) <span class="comment"># sum is performed by row  </span></span><br><span class="line">    distance = squaredDist ** <span class="number">0.5</span>  </span><br><span class="line"> </span><br><span class="line">    <span class="comment">## step 2: 排序</span></span><br><span class="line">    <span class="comment"># argsort() returns the indices that would sort an array in a ascending order  </span></span><br><span class="line">    sortedDistIndices = argsort(distance)  </span><br><span class="line"> </span><br><span class="line">    classCount = &#123;&#125; <span class="comment"># define a dictionary (can be append element)  </span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> xrange(k):  </span><br><span class="line">        <span class="comment">## step 3: 选最符合的k个</span></span><br><span class="line">        voteLabel = labels[sortedDistIndices[i]]  </span><br><span class="line"> </span><br><span class="line">        <span class="comment">## step 4: 统计标签</span></span><br><span class="line">        <span class="comment"># when the key voteLabel is not in dictionary classCount, get()  </span></span><br><span class="line">        <span class="comment"># will return 0  </span></span><br><span class="line">        classCount[voteLabel] = classCount.get(voteLabel, <span class="number">0</span>) + <span class="number">1</span>  </span><br><span class="line"> </span><br><span class="line">    <span class="comment">## step 5: 返回频数最大的标签</span></span><br><span class="line">    maxCount = <span class="number">0</span>  </span><br><span class="line">    <span class="keyword">for</span> key, value <span class="keyword">in</span> classCount.items():  </span><br><span class="line">        <span class="keyword">if</span> value &gt; maxCount:  </span><br><span class="line">            maxCount = value  </span><br><span class="line">            maxIndex = key  </span><br><span class="line">    <span class="keyword">return</span> maxIndex</span><br></pre></td></tr></table></figure><blockquote><p>最后是测试函数：</p></blockquote><figure class="highlight python"><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="comment"># test hand writing class  </span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">testHandWritingClass</span><span class="params">()</span>:</span>  </span><br><span class="line">    <span class="comment">## step 1: load data  </span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"step 1: load data..."</span>  </span><br><span class="line">    train_x, train_y, test_x, test_y = loadDataSet()  </span><br><span class="line"> </span><br><span class="line">    <span class="comment">## step 2: training...  </span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"step 2: training..."</span>  </span><br><span class="line">    <span class="keyword">pass</span>  </span><br><span class="line"> </span><br><span class="line">    <span class="comment">## step 3: testing  </span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"step 3: testing..."</span>  </span><br><span class="line">    numTestSamples = test_x.shape[<span class="number">0</span>]  </span><br><span class="line">    matchCount = <span class="number">0</span>  </span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> xrange(numTestSamples):  </span><br><span class="line">        predict = kNNClassify(test_x[i], train_x, train_y, <span class="number">3</span>)</span><br><span class="line">        <span class="keyword">if</span> predict == test_y[i]:  </span><br><span class="line">            matchCount += <span class="number">1</span>  </span><br><span class="line">    accuracy = float(matchCount) / numTestSamples  </span><br><span class="line"> </span><br><span class="line">    <span class="comment">## step 4: show the result  </span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">"step 4: show the result..."</span>  </span><br><span class="line">    <span class="keyword">print</span> <span class="string">'The classify accuracy is: %.2f%%'</span> % (accuracy * <span class="number">100</span>)</span><br></pre></td></tr></table></figure><p>由于这种题目的数据都是完整的，而且向量也是有规格的（32*32），也就是说每个测试例子都没有丢失的数据，而且每个参数的值也是在0-1的，所以这里不用进行数据处理阶段，至于要不要做特征工程我也不清楚。。。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;k-最近邻是&lt;strong&gt;基于实例的学习&lt;/strong&gt;方法中最基本的算法。&lt;/p&gt;
    
    </summary>
    
      <category term="机器学习" scheme="https://luoxjnono.github.io/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
      <category term="kaggle" scheme="https://luoxjnono.github.io/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/kaggle/"/>
    
    
  </entry>
  
  <entry>
    <title>简单的机器学习算法--k-means</title>
    <link href="https://luoxjnono.github.io/2019/06/19/k-means/"/>
    <id>https://luoxjnono.github.io/2019/06/19/k-means/</id>
    <published>2019-06-19T11:25:01.000Z</published>
    <updated>2019-06-19T11:35:37.709Z</updated>
    
    <content type="html"><![CDATA[<p>下面一种典型的<strong>无监督学习算法</strong>，主要用于将相似的样本自动归到一个类别中。</p><a id="more"></a><h3 id="算法概述"><a href="#算法概述" class="headerlink" title="算法概述"></a>算法概述</h3><p><strong>原理：</strong>根据样本之间的相似性，将样本划分到不同的类别中，对于不同的相似度计算方法，会得到不同的聚类结果</p><p><strong>常用方法：</strong>欧式距离法</p><p><strong>原理实现：</strong>确定常数K，常数K意味着最终的聚类数目，首先<strong>随机</strong>选定初始点为质心，并通过计算<strong>每一个样本与质心之间的相似度</strong>(这里为欧式距离)，将样本点归<strong>到最相似的类中</strong>，接着，<strong>重新计算每个类的质心</strong>(即为类中心)，<strong>重复这样的过程，直到质心不再改变</strong>，最终就确定了每个样本所属的类别以及每个类的质心。</p><p><strong>伪代码如下：</strong></p><figure class="highlight plain"><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">选择K个点作为初始质心</span><br><span class="line">repeat</span><br><span class="line">将每个点指派到最近的质心，形成K个簇</span><br><span class="line">重新计算每个簇的质心</span><br><span class="line">until 簇不发生变化或达到最大迭代次数</span><br></pre></td></tr></table></figure><h3 id="注意的问题"><a href="#注意的问题" class="headerlink" title="注意的问题"></a>注意的问题</h3><p>既然是无监督学习，很多情况下，我们并不知道数据的分布情况，所以我们这个时候要<strong>怎么确定k值</strong>才能达到我们的预期呢？</p><p>这里就涉及到很多的知识了，搞定了这些那可不得了，目前还没有时间，下次。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;下面一种典型的&lt;strong&gt;无监督学习算法&lt;/strong&gt;，主要用于将相似的样本自动归到一个类别中。&lt;/p&gt;
    
    </summary>
    
      <category term="机器学习" scheme="https://luoxjnono.github.io/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
    
  </entry>
  
  <entry>
    <title>机器学习入门：数字识别（逻辑回归）</title>
    <link href="https://luoxjnono.github.io/2019/06/16/digit-recognizer/"/>
    <id>https://luoxjnono.github.io/2019/06/16/digit-recognizer/</id>
    <published>2019-06-16T09:26:11.000Z</published>
    <updated>2019-06-16T10:19:55.885Z</updated>
    
    <content type="html"><![CDATA[<p>logistic回归一般用于二分类问题，比如判断一封邮件是否为垃圾邮件，判断照片中的人是男是女，也可以用于多分类问题，比如k类别，就进行k次logistic回归，下面是实现的一个实例。</p><a id="more"></a><p>思想也和简单，做十次逻辑回归，第一次将0作为一类，其他数字为另外一类，如此类推</p><p>1.读取内容并返回m*1024形式的样本以及对应的数字</p><figure class="highlight python"><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="function"><span class="keyword">def</span> <span class="title">loadData</span><span class="params">(direction)</span>:</span></span><br><span class="line">    trainfileList=listdir(direction)</span><br><span class="line">    m=len(trainfileList)</span><br><span class="line">    dataArray= zeros((m,<span class="number">1024</span>))</span><br><span class="line">    labelArray= zeros((m,<span class="number">1</span>))</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(m):</span><br><span class="line">        returnArray=zeros((<span class="number">1</span>,<span class="number">1024</span>))  <span class="comment">#每个txt文件形成的特征向量</span></span><br><span class="line">        filename=trainfileList[i]</span><br><span class="line">        fr=open(<span class="string">'%s/%s'</span> %(direction,filename))</span><br><span class="line">        <span class="keyword">for</span> j <span class="keyword">in</span> range(<span class="number">32</span>):<span class="comment">#32*32转化成1*1024的形式</span></span><br><span class="line">            lineStr=fr.readline()</span><br><span class="line">            <span class="keyword">for</span> k <span class="keyword">in</span> range(<span class="number">32</span>):</span><br><span class="line">                returnArray[<span class="number">0</span>,<span class="number">32</span>*j+k]=int(lineStr[k])</span><br><span class="line">        dataArray[i,:]=returnArray   <span class="comment">#存储特征向量</span></span><br><span class="line">    </span><br><span class="line">        filename0=filename.split(<span class="string">'.'</span>)[<span class="number">0</span>]</span><br><span class="line">        label=filename0.split(<span class="string">'_'</span>)[<span class="number">0</span>]</span><br><span class="line">        labelArray[i]=int(label)     <span class="comment">#存储类别</span></span><br><span class="line">    <span class="keyword">return</span> dataArray,labelArray</span><br></pre></td></tr></table></figure><ul><li><strong>sigmoid(inX)函数</strong></li></ul><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">sigmoid</span><span class="params">(inX)</span>:</span></span><br><span class="line">   <span class="keyword">return</span> <span class="number">1.0</span>/(<span class="number">1</span>+exp(-inX))</span><br></pre></td></tr></table></figure><p>然后用梯度下降算法得到回归系数：</p><p>alpha是步长，maxCycles是迭代步数。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">gradAscent</span><span class="params">(dataArray,labelArray,alpha,maxCycles)</span>:</span></span><br><span class="line">    dataMat=mat(dataArray)    <span class="comment">#size:m*n</span></span><br><span class="line">    labelMat=mat(labelArray)      <span class="comment">#size:m*1，表示结果</span></span><br><span class="line">    m,n=shape(dataMat)<span class="comment">#获取矩阵大小</span></span><br><span class="line">    weigh=ones((n,<span class="number">1</span>)) <span class="comment">#权重初始化，多次迭代后得到结果</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(maxCycles):</span><br><span class="line">        h=sigmoid(dataMat*weigh)</span><br><span class="line">        error=labelMat-h    <span class="comment">#size:m*1</span></span><br><span class="line">        weigh=weigh+alpha*dataMat.transpose()*error</span><br><span class="line">    <span class="keyword">return</span> weigh</span><br></pre></td></tr></table></figure><p>然后我们就得到了权重</p><p>最后我们进行分类，我们这里直接用sigmoid函数进行分类。</p><figure class="highlight python"><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="function"><span class="keyword">def</span> <span class="title">classfy</span><span class="params">(testdir,weigh)</span>:</span></span><br><span class="line">    dataArray,labelArray=loadData(testdir)</span><br><span class="line">    dataMat=mat(dataArray)</span><br><span class="line">    labelMat=mat(labelArray)</span><br><span class="line">    h=sigmoid(dataMat*weigh)  <span class="comment">#size:m*1</span></span><br><span class="line">    m=len(h)</span><br><span class="line">    error=<span class="number">0.0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(m):</span><br><span class="line">        <span class="keyword">if</span> int(h[i])&gt;<span class="number">0.5</span>:</span><br><span class="line">            <span class="keyword">print</span> int(labelMat[i]),<span class="string">'is classfied as: 1'</span></span><br><span class="line">            <span class="keyword">if</span> int(labelMat[i])!=<span class="number">1</span>:</span><br><span class="line">                error+=<span class="number">1</span></span><br><span class="line">                <span class="keyword">print</span> <span class="string">'error'</span></span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="keyword">print</span> int(labelMat[i]),<span class="string">'is classfied as: 0'</span></span><br><span class="line">            <span class="keyword">if</span> int(labelMat[i])!=<span class="number">0</span>:</span><br><span class="line">                error+=<span class="number">1</span></span><br><span class="line">                <span class="keyword">print</span> <span class="string">'error'</span></span><br><span class="line">    <span class="keyword">print</span> <span class="string">'error rate is:'</span>,<span class="string">'%.4f'</span> %(error/m)</span><br></pre></td></tr></table></figure><p>然后我们把这些函数整合起来</p><figure class="highlight python"><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="function"><span class="keyword">def</span> <span class="title">digitRecognition</span><span class="params">(trainDir,testDir,alpha=<span class="number">0.07</span>,maxCycles=<span class="number">10</span>)</span>:</span></span><br><span class="line">    data,label=loadData(trainDir)</span><br><span class="line">    weigh=gradAscent(data,label,alpha,maxCycles)</span><br><span class="line">    classfy(testDir,weigh)</span><br></pre></td></tr></table></figure><p>总结</p><p>可以看出我只对01进行了分类，而且做法太直接了，算是最基础的题目了，数据分析、特征工程直接忽略了，原因很简单，菜，而且时间也有限，不过这种类型的用逻辑回归处理不太好，所以有时间我会学习并复制另外一种解法。</p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;logistic回归一般用于二分类问题，比如判断一封邮件是否为垃圾邮件，判断照片中的人是男是女，也可以用于多分类问题，比如k类别，就进行k次logistic回归，下面是实现的一个实例。&lt;/p&gt;
    
    </summary>
    
      <category term="kaggle" scheme="https://luoxjnono.github.io/categories/kaggle/"/>
    
    
  </entry>
  
  <entry>
    <title>操作系统之死锁</title>
    <link href="https://luoxjnono.github.io/2019/06/16/%E6%AD%BB%E9%94%81/"/>
    <id>https://luoxjnono.github.io/2019/06/16/死锁/</id>
    <published>2019-06-16T07:25:30.000Z</published>
    <updated>2019-06-16T10:21:07.130Z</updated>
    
    <content type="html"><![CDATA[<p>在同步问题中的哲学家就餐问题中，通过信号量我们没有合适的解决方法，因为那会造成死锁，今天我就复习一下死锁。</p><a id="more"></a><h2 id="死锁特征"><a href="#死锁特征" class="headerlink" title="死锁特征"></a>死锁特征</h2><p>由于竞争资源或者通信关系 两个或更多线程在执行中出现 用于相互等待只能由其他进程引发的事件</p><p>互斥：任何时刻只能由一个进程使用资源实例</p><p>占有并等待：进程保持至少一个资源别难过正在等待其他进程的资源</p><p>非抢占：资源只能在进程使用后资源释放</p><p>循环等待：字面意思</p><p>资源分配图：</p><p><img src="/2019/06/16/死锁/Resource_allocation_mapping.png" alt="Resource_allocation_mapping"></p><p><img src="/2019/06/16/死锁/Resource_allocation_mapping_Deadlock.png" alt="Resource_allocation_mapping_Deadlock"></p><p>没有死锁是因为P4可能释放资源类型R2的实例</p><h2 id="死锁处理方法"><a href="#死锁处理方法" class="headerlink" title="死锁处理方法"></a>死锁处理方法</h2><p>通常操作系统忽略死锁 由应用进程处理死锁</p><p>   死锁预防(Deadlock Prevention)：确保死锁的至少一个必要条件不成立</p><ul><li>确保系统永远不会进入死锁状态</li></ul><p>死锁避免(Deadlock Avoidance)</p><ul><li>在使用前进行判断 只允许不会出现死锁的进程请求资源</li></ul><p>死锁检测和恢复(Deadlock Detection &amp; Recovery)</p><ul><li>在检测到系统进入死锁状态后 进行恢复</li></ul><h2 id="死锁预防"><a href="#死锁预防" class="headerlink" title="死锁预防"></a>死锁预防</h2><p>限制并发进程对资源的请求 使系统在任何时刻都不满足死锁的必要条件，<strong>但是会导致资源的利用率低。</strong></p><p> 互斥</p><ul><li><p>把互斥的共享资源封装成可同时访问</p><p>持有并等待</p></li><li><p>进程请求资源时 要求它不持有任何其他资源</p></li><li><p>仅允许进程在开始执行时 一次请求所有需要的资源</p></li><li><p>非抢占</p></li><li><p>如进程请求不能立即分配的资源 则释放已占有资源</p></li><li><p>只在能够同时获得所有需要资源时 才执行分配操作</p></li></ul><p>循环等待</p><ul><li>对资源排序 要求进程按顺序请求资源</li></ul><h2 id="死锁避免"><a href="#死锁避免" class="headerlink" title="死锁避免"></a>死锁避免</h2><p>构造一个算法以确保系统绝不会进入死锁状态，一直处于安全状态。</p><p><strong>安全状态</strong></p><p>系统处于安全状（以某种<strong>序列</strong>分配资源能避免死锁）</p><ul><li>针对所有已占有进程存在安全序列</li></ul><p>序列&lt;P1, P2, …, PN&gt; 是安全的</p><ul><li>Pi要求的资源 &lt;= 当前可用资源 + 所有Pj<strong>持有资源</strong> 其中 j &lt; i</li><li><strong>如Pi的资源请求不能立即分配 则Pi等待所有Pj(j &lt; i) 完成</strong></li><li>Pi完成后 Pi + 1 可得到所需资源 执行并释放所分配的资源</li><li>最终整个序列的所有Pi都能获得所需资源</li></ul><p>资源分配图方法</p><p><strong>每个资源有多个实例的时候这种方法就不适用了</strong></p><p>只有在将申请边变成分配边而不会导致资源分配图成环时，才安全。</p><p><img src="/2019/06/16/死锁/%E6%8D%95%E8%8E%B7.PNG" alt="捕获"></p><p>银行家算法</p><p>不能满足所有客户的需求时，不分配现金。</p><p><strong>当一个进程申请使用资源的时候，银行家算法通过先 试探 分配给该进程资源，然后通过安全性算法判断分配后的系统是否处于安全状态，若不安全则试探分配作废，让该进程继续等待。</strong></p><p><img src="/2019/06/16/死锁/20180508204335770.png" alt="20180508204335770"></p><p>数据结构实现：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">n = 线程数量</span><br><span class="line">m = 资源类型数量</span><br></pre></td></tr></table></figure><ul><li>Max(总需求量) = n x m 矩阵</li><li>Available(剩余空闲量) 长度为 m 的向量</li><li>Allocation(已分配量) = n x m 矩阵</li><li>Need(未来需要量) = n x m 矩阵</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Need[i, j] = Max[i, j] - Allocation[i, j]</span><br></pre></td></tr></table></figure><p>安全状态判断：</p><p>初始化：</p><ul><li><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Work = Available // 当前资源剩余空闲量</span><br><span class="line">Finish[i] = false for i : 1, 2, ..., n // 线程i有没有完成</span><br></pre></td></tr></table></figure></li></ul><ol><li>寻找线程Ti:<ul><li>Finish[i] = false</li><li>Need[i] &lt;= Work</li><li>去 步骤2</li></ul></li><li>找到线程Ti<ul><li>Work = Work + Allocation[i]</li><li>Finish[i] = true</li><li>回到 步骤1</li></ul></li></ol><p>查所有线程是否满足 Finish[i] == true</p><ul><li>若等 则系统处于安全状态</li></ul><p>资源分配算法：</p><figure class="highlight plain"><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">init: Requesti 线程Ti的资源请求向量</span><br><span class="line">      Requesti[j] 线程Ti请求资源Rj的实例</span><br><span class="line">do-while:</span><br><span class="line">1.如果 Requesti ≤ Need[i], 转到步骤2。否则, 拒绝资源申请, 因为线程已经超过了其最大要求</span><br><span class="line">2.如果 Requesti ≤ Available, 转到步骤3。否则, Ti 必须等待, 因为资源不可用</span><br><span class="line">3.通过安全状态判断来确定是否分配资源给Ti: 生成一个需要判断状态是否安全的资源分配环境</span><br><span class="line">Available = Available - Requesti;</span><br><span class="line">Allocation[i] = Allocation[i] + Requesti;</span><br><span class="line">Need[i]= Need[i] – Requesti;</span><br><span class="line">若安全 则分配资源给Ti</span><br><span class="line">若不安全 则拒绝Ti的资源请求</span><br></pre></td></tr></table></figure><p>实例：</p><p><img src="/2019/06/16/死锁/%E6%8D%95%E8%8E%B72.PNG" alt="捕获2"></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;在同步问题中的哲学家就餐问题中，通过信号量我们没有合适的解决方法，因为那会造成死锁，今天我就复习一下死锁。&lt;/p&gt;
    
    </summary>
    
      <category term="操作系统" scheme="https://luoxjnono.github.io/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    
  </entry>
  
  <entry>
    <title>操作系统之CPU调度</title>
    <link href="https://luoxjnono.github.io/2019/06/14/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E4%B9%8BCPU%E8%B0%83%E5%BA%A6/"/>
    <id>https://luoxjnono.github.io/2019/06/14/操作系统之CPU调度/</id>
    <published>2019-06-14T08:39:20.000Z</published>
    <updated>2019-06-14T08:55:38.444Z</updated>
    
    <content type="html"><![CDATA[<h4 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h4><p><strong>CPU调度</strong>：从就绪队列中选择进程并为之分配CPU</p><p><strong>抢占式</strong>：进程从运行状态切换到就绪状态、等待-&gt;就绪（优先级高则抢占）</p><p><strong>非抢占式</strong>：运行-&gt;等待，终止</p><a id="more"></a><p><img src="/2019/06/14/操作系统之CPU调度/process_control_with_process_state.png" alt="process_control_with_process_state"></p><h4 id="比较调度算法的准则"><a href="#比较调度算法的准则" class="headerlink" title="比较调度算法的准则"></a>比较调度算法的准则</h4><ul><li>CPU利用率<ul><li>CPU 处于忙状态的 时间百分比</li></ul></li><li>吞吐量<ul><li>单位时间内完成的 进程数量</li></ul></li><li>周转时间<ul><li>进程从 初始化 到 结束(包括等待)的总时间</li></ul></li><li>等待时间<ul><li>进程在 就绪队列中 的总时间</li></ul></li><li>响应时间<ul><li>从提交请求到产生响应所花费的总时间</li></ul></li></ul><h2 id="调度算法"><a href="#调度算法" class="headerlink" title="调度算法"></a>调度算法</h2><ul><li><p><strong>先到先服务算法</strong>（FCFS）</p><p>非抢占的，简单，平均等待时间长</p></li><li><p>短进程优先算法</p><ul><li><p>SPN: Shortest Process Next</p></li><li><p>SJF: Shortest Job First(<strong>最短作业优先调度算法</strong>)</p><p>真正困难时如何知道下一个CPU区间的长度</p></li></ul></li></ul><ul><li>SRT: Shortest Remaining Time(短剩余时间优先算法)</li></ul><ul><li><p><strong>优先级调度</strong>：可以实抢占式和非抢占的</p><p>可能会导致无穷阻塞或者饥饿，解决方法是老化</p></li></ul><ul><li><p>时间片<strong>轮转算法</strong> (各个进程轮流占用一个相等的时间片)</p><p>进程可能只需要小于时间片的CPU 区间。对于这种情况， 进程本身会自动释放CPU 调度程序接着处理就绪队列的下一个进程。否则，如果当前运 行进程的 CPU 区间比时间片要长，定时器会中断并产生操作系统中断，然后进行上下文切<br>换，将进程加入到就绪队列的尾部，接着CPU 调度程序会选择就绪队列中的下一个进程。</p></li><li><p><strong>多级队列调度</strong>：每个队列有自己的调度算法</p></li></ul><ul><li><p><strong>多级反馈队列算法</strong> (将就绪队列分成不同子序列 使用不同的算法)</p><p>多级反馈队列调度算法  (multilevel  feedback queue scheduling algorithm) 允 许进程在队列之间移动。主要思想是根据不同CPU 区间的特点以区分进程。如果进程使用 过多 CPU 时间，那么它会被转移到更低优先级队列。这种方案将νo 约束和交互进程留在 更高优先级队列。此外，在较低优先级队列中等待时间过长的进程会被转移到更高优先级<br>队列。这种形式的老化阻止饥饿的发生。</p></li></ul><p><img src="/2019/06/14/操作系统之CPU调度/MLFQ.png" alt="MLFQ"></p>]]></content>
    
    <summary type="html">
    
      &lt;h4 id=&quot;基本概念&quot;&gt;&lt;a href=&quot;#基本概念&quot; class=&quot;headerlink&quot; title=&quot;基本概念&quot;&gt;&lt;/a&gt;基本概念&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;CPU调度&lt;/strong&gt;：从就绪队列中选择进程并为之分配CPU&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;抢占式&lt;/strong&gt;：进程从运行状态切换到就绪状态、等待-&amp;gt;就绪（优先级高则抢占）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;非抢占式&lt;/strong&gt;：运行-&amp;gt;等待，终止&lt;/p&gt;
    
    </summary>
    
      <category term="操作系统" scheme="https://luoxjnono.github.io/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    
  </entry>
  
  <entry>
    <title>操作系统之进程切换</title>
    <link href="https://luoxjnono.github.io/2019/06/14/%E8%BF%9B%E7%A8%8B/"/>
    <id>https://luoxjnono.github.io/2019/06/14/进程/</id>
    <published>2019-06-14T06:12:18.000Z</published>
    <updated>2019-06-14T06:14:20.853Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>进程是操作系统对一个正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程，而每个进程都好像在独占的使用硬件。在大多数系统中，需要运行的进程数是多于可以运行他们的CPU个数的。无论是在多核还是单核系统中，一个CPU看上去都像是在并发的执行多个进程，这是通过处理器在进程间切换来实现的。 <strong>操作系统实现这种交错执行的机制称为上下文切换。</strong>，总而言之，<strong>进程是轮流使用处理器的。</strong></p><a id="more"></a><h2 id="进程"><a href="#进程" class="headerlink" title="进程"></a>进程</h2><p><strong>进程：一个执行中的程序的实例</strong>，系统中的每个程序都是运行在某个进程的上下文中的。，通常进程还包括堆栈段和数据段，不同的进程文本段相同，其他可能不同。</p><p><strong>进程五状态：</strong></p><p>创建，运行，等待，就绪，终止</p><p>一次只能由一个进程在处理器上运行，但是多个进程可处于就绪或者等待状态</p><p><img src="/2019/06/14/进程/1560492180766.png" alt="1560492180766"></p><p>PCB</p><p><img src="/2019/06/14/进程/1560492279607.png" alt="1560492279607"></p><h3 id="进程调度"><a href="#进程调度" class="headerlink" title="进程调度"></a>进程调度</h3><p>多道程序设计的目的就是无论何时都有进程在运行，从而使CPU的利用率最大化</p><p>进程调度是选择一个可用的进程</p><p><strong>调度队列</strong></p><p>作业队列：系统中的所有进程</p><p>就绪队列：驻留在内存中的就绪的、等待运行的进程</p><p><strong>调度程序</strong></p><p>长期（作业）调度程序（<strong>不频繁</strong>）：从缓冲池中选择进程，装入内存中准备执行。</p><p>它看i给你之多道程序设计的程度（内存中的进程数量）</p><p>短期（cpu）调度程序（<strong>频繁</strong>）：从准备执行的进程中选择进程，并为之分配cpu</p><h2 id="上下文切换"><a href="#上下文切换" class="headerlink" title="上下文切换"></a>上下文切换</h2><p>操作系统保持跟踪进程运行所需的所有状态信息，这种状态，也就是上下文，它包括许多信息，例如PC和寄存器文件的当前值，以及主存的内容。</p><p><strong>当操作系统决定要把控制权从当前进程转移到某个新进程时，就会进行上下文切换</strong>，<strong>即保存当前进程的上下文，恢复新进程的上下文，然后将控制权传递到新进程，新进程就会从上次停止的地方开始</strong></p><h3 id="上下文切换的过程"><a href="#上下文切换的过程" class="headerlink" title="上下文切换的过程　"></a><strong>上下文切换的过程</strong>　</h3><ul><li><strong>保存当前进程的上下文</strong></li><li><strong>恢复某个先前被抢占的进程被保存的上下文</strong></li><li><strong>将控制传递给这个新恢复的进程</strong></li></ul><p>而系统调用进行的是<strong>模式切换</strong>(mode switch)。模式切换与进程切换比较起来，容易很多，而且节省时间，因为模式切换最主要的任务只是切换进程寄存器上下文的切换。 </p><h3 id="那么进程切换何时发生呢？"><a href="#那么进程切换何时发生呢？" class="headerlink" title="那么进程切换何时发生呢？"></a><strong>那么进程切换何时发生呢？</strong></h3><p>进程切换一定发生在中断／异常／系统调用处理过程中，常见的有以下情况：</p><p>1、阻塞式系统调用、虚拟地址异常。</p><p>导致被中断进程进入等待态。</p><p>2、时间片中断、I/O中断后发现更改优先级进程。</p><p>导致被中断进程进入就绪态。</p><p>3、终止用系统调用、不能继续执行的异常。</p><p>导致被中断进程进入终止态。</p><h3 id="但是并不意味着所有的中断／异常都会引起进程切换。"><a href="#但是并不意味着所有的中断／异常都会引起进程切换。" class="headerlink" title="但是并不意味着所有的中断／异常都会引起进程切换。"></a><strong>但是并不意味着所有的中断／异常都会引起进程切换。</strong></h3><p>有一些中断／异常不会引起进程状态转换，不会引起进程切换，只是在处理完成后把控制权交还给被中断进程。</p><p>以下是处理流程：</p><p>1、（中断／异常等触发）正向模式切换并压入PSW／PC 。 </p><p>2、保存被中断进程的现场信息。</p><p>3、处理具体中断、异常。</p><p>4、恢复被中断进程的现场信息。</p><p>5、（中断返回指令触发）逆向模式转换并弹出PSW／PC。</p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;背景&quot;&gt;&lt;a href=&quot;#背景&quot; class=&quot;headerlink&quot; title=&quot;背景&quot;&gt;&lt;/a&gt;背景&lt;/h2&gt;&lt;p&gt;进程是操作系统对一个正在运行的程序的一种抽象。在一个系统上可以同时运行多个进程，而每个进程都好像在独占的使用硬件。在大多数系统中，需要运行的进程数是多于可以运行他们的CPU个数的。无论是在多核还是单核系统中，一个CPU看上去都像是在并发的执行多个进程，这是通过处理器在进程间切换来实现的。 &lt;strong&gt;操作系统实现这种交错执行的机制称为上下文切换。&lt;/strong&gt;，总而言之，&lt;strong&gt;进程是轮流使用处理器的。&lt;/strong&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="操作系统" scheme="https://luoxjnono.github.io/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"/>
    
    
  </entry>
  
  <entry>
    <title>kaggle入门：逻辑回归应用之泰坦尼克之灾</title>
    <link href="https://luoxjnono.github.io/2019/06/11/titanic/"/>
    <id>https://luoxjnono.github.io/2019/06/11/titanic/</id>
    <published>2019-06-11T07:50:01.000Z</published>
    <updated>2019-06-11T08:26:14.179Z</updated>
    
    <content type="html"><![CDATA[<p>上次说了特征工程，这次照着别人的博客来复现一下kaggle上的hello world，python语法之类的我还是不熟悉，所以尽量把第一个项目做好，我<strong>这里仅仅是把大体的流程介绍一下，不会涉及到太多的语法。</strong></p><a id="more"></a><p>作者： 寒小阳 出处：<a href="http://blog.csdn.net/han_xiaoyang/article/details/49797143" target="_blank" rel="noopener">http://blog.csdn.net/han_xiaoyang/article/details/49797143</a> </p><p>声明：版权所有，转载请注明出处，谢谢。</p><p>Github链接：<a href="https://github.com/HanXiaoyang/Kaggle_Titanic" target="_blank" rel="noopener">https://github.com/HanXiaoyang/Kaggle_Titanic</a></p><p>题目链接：<a href="https://www.kaggle.com/c/titanic" target="_blank" rel="noopener">https://www.kaggle.com/c/titanic</a></p><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>泰坦尼克号问题之背景</p><p>就是那个大家都熟悉的『Jack and Rose』的故事，豪华游艇倒了，大家都惊恐逃生，可是救生艇的数量有限，无法人人都有，副船长发话了『lady and kid first！』，所以是否获救其实并非随机，而是基于一些背景有rank先后的。</p><p>训练和测试数据是一些乘客的个人信息以及存活状况，要尝试根据它生成合适的模型并预测其他人的存活状况。对，<strong>这是一个二分类问题，是我们之前讨论的logistic regression所能处理的范畴。</strong></p><p>手把手教程马上就来，先来两条我看到的，觉得很重要的经验。</p><p>印象中Andrew Ng老师似乎在coursera上说过，应用机器学习，千万不要一上来就试图做到完美，<strong>先撸一个baseline的model出来，再进行后续的分析步骤，一步步提高</strong>，所谓后续步骤可能包括『分析model现在的状态(欠/过拟合)，分析我们使用的feature的作用大小，进行feature selection，以及我们模型下的bad case和产生的原因』等等。</p><p>Kaggle上的大神们，也分享过一些experience，说几条我记得的哈：</p><p><strong>『对数据的认识太重要了！』</strong><br><strong>『数据中的特殊点/离群点的分析和处理太重要了！』</strong><br><strong>『特征工程(feature engineering)太重要了！在很多Kaggle的场景下，甚至比model本身还要重要』</strong></p><p><strong>『要做模型融合(model ensemble)啊啊啊！』</strong></p><h2 id="初探数据"><a href="#初探数据" class="headerlink" title="初探数据"></a>初探数据</h2><figure class="highlight python"><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">import</span> pandas <span class="keyword">as</span> pd <span class="comment">#数据分析</span></span><br><span class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np <span class="comment">#科学计算</span></span><br><span class="line"><span class="keyword">from</span> pandas <span class="keyword">import</span> Series,DataFrame</span><br><span class="line"></span><br><span class="line">data_train = pd.read_csv(<span class="string">"/Users/Hanxiaoyang/Titanic_data/Train.csv"</span>)</span><br><span class="line">data_train</span><br></pre></td></tr></table></figure><p>得到典型的dataframe格式</p><p><img src="/2019/06/11/titanic/5.jpg" alt="5"></p><p>读取了数据之后，我们可以了解一下大体的情况</p><figure class="highlight python"><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="comment">#各个属性的数目以及百分比</span></span><br><span class="line">data_train.info()</span><br><span class="line">data_train.describe()</span><br></pre></td></tr></table></figure><h2 id="数据初步分析"><a href="#数据初步分析" class="headerlink" title="数据初步分析"></a>数据初步分析</h2><p>每个乘客都这么多属性，那我们咋知道哪些属性更有用，而又应该怎么用它们啊？说实话这会儿我也不知道，但我们记得前面提到过</p><p><strong>- 『对数据的认识太重要了！』</strong></p><p><strong>- 『对数据的认识太重要了！』</strong></p><p><strong>- 『对数据的认识太重要了！』</strong></p><p>重要的事情说三遍，恩，说完了。仅仅最上面的对数据了解，依旧无法给我们提供想法和思路。<strong>我们再深入一点来看看我们的数据，看看每个/多个 属性和最后的Survived之间有着什么样的关系呢。</strong>  </p><p>接下来就是数据分析的内容了，我们分别考察下列情况：</p><p><strong>乘客各属性分布</strong>（各个属性的人数）</p><p>然后是<strong>各个属性与获救结果的关联统计</strong>（看属性与获救结果是否有关）</p><p>ps：这个画图真有意思，这个库很不错</p><h2 id="简单数据预处理"><a href="#简单数据预处理" class="headerlink" title="简单数据预处理"></a>简单数据预处理</h2><p>大体数据的情况看了一遍，对感兴趣的属性也有个大概的了解了。 下一步干啥？<strong>咱们该处理处理这些数据，为机器学习建模做点准备了。</strong></p><p>对了，我这里说的数据预处理，其实就包括了很多Kaggler津津乐道的feature engineering过程，灰常灰常有必要！</p><ul><li><strong>『特征工程(feature engineering)太重要了！』</strong></li><li><strong>『特征工程(feature engineering)太重要了！』</strong></li><li><strong>『特征工程(feature engineering)太重要了！』</strong></li></ul><p>恩，重要的事情说三遍。</p><p><strong>先从最突出的数据属性开始吧，对，Cabin和Age，有丢失数据实在是对下一步工作影响太大。</strong></p><p>先说Cabin，暂时我们就按照刚才说的，按Cabin有无数据，将这个属性处理成Yes和No两种类型吧。</p><p>我们这里用scikit-learn中的RandomForest来拟合一下缺失的年龄数据(注：RandomForest是一个用在原始数据中做不同采样，建立多颗DecisionTree，再进行average等等来降低过拟合现象，提高结果的机器学习算法，我们之后会介绍到)</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn.ensemble <span class="keyword">import</span> RandomForestRegressor</span><br><span class="line"></span><br><span class="line"><span class="comment">### 使用 RandomForestClassifier 填补缺失的年龄属性</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">set_missing_ages</span><span class="params">(df)</span>:</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 把已有的数值型特征取出来丢进Random Forest Regressor中</span></span><br><span class="line">    age_df = df[[<span class="string">'Age'</span>,<span class="string">'Fare'</span>, <span class="string">'Parch'</span>, <span class="string">'SibSp'</span>, <span class="string">'Pclass'</span>]]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 乘客分成已知年龄和未知年龄两部分</span></span><br><span class="line">    known_age = age_df[age_df.Age.notnull()].values</span><br><span class="line">    unknown_age = age_df[age_df.Age.isnull()].values</span><br><span class="line"></span><br><span class="line">    <span class="comment"># y即目标年龄</span></span><br><span class="line">    y = known_age[:, <span class="number">0</span>]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># X即特征属性值</span></span><br><span class="line">    X = known_age[:, <span class="number">1</span>:]</span><br><span class="line"></span><br><span class="line">    <span class="comment"># fit到RandomForestRegressor之中</span></span><br><span class="line">    rfr = RandomForestRegressor(random_state=<span class="number">0</span>, n_estimators=<span class="number">2000</span>, n_jobs=<span class="number">-1</span>)</span><br><span class="line">    rfr.fit(X, y)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 用得到的模型进行未知年龄结果预测</span></span><br><span class="line">    predictedAges = rfr.predict(unknown_age[:, <span class="number">1</span>::])</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 用得到的预测结果填补原缺失数据</span></span><br><span class="line">    df.loc[ (df.Age.isnull()), <span class="string">'Age'</span> ] = predictedAges </span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> df, rfr</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">set_Cabin_type</span><span class="params">(df)</span>:</span></span><br><span class="line">    df.loc[ (df.Cabin.notnull()), <span class="string">'Cabin'</span> ] = <span class="string">"Yes"</span></span><br><span class="line">    df.loc[ (df.Cabin.isnull()), <span class="string">'Cabin'</span> ] = <span class="string">"No"</span></span><br><span class="line">    <span class="keyword">return</span> df</span><br><span class="line"></span><br><span class="line">data_train, rfr = set_missing_ages(data_train)</span><br><span class="line">data_train = set_Cabin_type(data_train)</span><br></pre></td></tr></table></figure><p>然后我们就把数据补全了</p><p><strong>因为逻辑回归建模时，需要输入的特征都是数值型特征，我们通常会先对类目型的特征因子化。 什么叫做因子化呢？字面意思，把不是数值型的类目属性全都转成0，1的数值属性</strong></p><figure class="highlight python"><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">dummies_Cabin = pd.get_dummies(data_train[<span class="string">'Cabin'</span>], prefix= <span class="string">'Cabin'</span>)</span><br><span class="line"></span><br><span class="line">dummies_Embarked = pd.get_dummies(data_train[<span class="string">'Embarked'</span>], prefix= <span class="string">'Embarked'</span>)</span><br><span class="line"></span><br><span class="line">dummies_Sex = pd.get_dummies(data_train[<span class="string">'Sex'</span>], prefix= <span class="string">'Sex'</span>)</span><br><span class="line"></span><br><span class="line">dummies_Pclass = pd.get_dummies(data_train[<span class="string">'Pclass'</span>], prefix= <span class="string">'Pclass'</span>)</span><br><span class="line"></span><br><span class="line">df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=<span class="number">1</span>)</span><br><span class="line">df.drop([<span class="string">'Pclass'</span>, <span class="string">'Name'</span>, <span class="string">'Sex'</span>, <span class="string">'Ticket'</span>, <span class="string">'Cabin'</span>, <span class="string">'Embarked'</span>], axis=<span class="number">1</span>, inplace=<span class="literal">True</span>)</span><br><span class="line">df.head()</span><br></pre></td></tr></table></figure><p>这样，看起来，是不是我们需要的属性值都有了，且它们都是数值型属性呢。</p><p>有一种临近结果的宠宠欲动感吧，莫急莫急，我们还得做一些处理，仔细看看Age和Fare两个属性，乘客的数值幅度变化，也忒大了吧！！如果大家了解逻辑回归与梯度下降的话，会知道，各属性值之间scale差距太大，将对收敛速度造成几万点伤害值！甚至不收敛！ (╬▔皿▔)…所以我们先用scikit-learn里面的preprocessing模块对这俩货做一个scaling，所谓scaling，其实就是将一些变化幅度较大的特征化到[-1,1]之内。</p><figure class="highlight python"><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="keyword">import</span> sklearn.preprocessing <span class="keyword">as</span> preprocessing</span><br><span class="line">scaler = preprocessing.StandardScaler()</span><br><span class="line">age_scale_param = scaler.fit(df[<span class="string">'Age'</span>].values.reshape(<span class="number">-1</span>,<span class="number">1</span>))</span><br><span class="line">df[<span class="string">'Age_scaled'</span>] = scaler.fit_transform(df[<span class="string">'Age'</span>].values.reshape(<span class="number">-1</span>,<span class="number">1</span>), age_scale_param)</span><br><span class="line">fare_scale_param = scaler.fit(df[<span class="string">'Fare'</span>].values.reshape(<span class="number">-1</span>,<span class="number">1</span>))</span><br><span class="line">df[<span class="string">'Fare_scaled'</span>] = scaler.fit_transform(df[<span class="string">'Fare'</span>].values.reshape(<span class="number">-1</span>,<span class="number">1</span>), fare_scale_param)</span><br><span class="line">df.head()</span><br></pre></td></tr></table></figure><p><img src="/2019/06/11/titanic/18.jpg" alt="18"></p><p>恩，好看多了，万事俱备，只欠建模。马上就要看到成效了，哈哈。</p><h2 id="逻辑回归建模"><a href="#逻辑回归建模" class="headerlink" title="逻辑回归建模"></a>逻辑回归建模</h2><p><strong>我们把需要的feature字段取出来，转成numpy格式，使用scikit-learn中的LogisticRegression建模。</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> sklearn <span class="keyword">import</span> linear_model</span><br><span class="line"></span><br><span class="line"><span class="comment"># 用正则取出我们要的属性值</span></span><br><span class="line">train_df = df.filter(regex=<span class="string">'Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*'</span>)</span><br><span class="line">train_np = train_df.values</span><br><span class="line"></span><br><span class="line"><span class="comment"># y即第0列：Survival结果</span></span><br><span class="line">y = train_np[:, <span class="number">0</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># X即第1列及以后：特征属性值</span></span><br><span class="line">X = train_np[:, <span class="number">1</span>:]</span><br><span class="line"></span><br><span class="line"><span class="comment"># fit到LogisticRegression之中</span></span><br><span class="line">clf = linear_model.LogisticRegression(solver=<span class="string">'liblinear'</span>,C=<span class="number">1.0</span>, penalty=<span class="string">'l1'</span>, tol=<span class="number">1e-6</span>)</span><br><span class="line">clf.fit(X, y)</span><br><span class="line"></span><br><span class="line">clf</span><br></pre></td></tr></table></figure><p>good，很顺利，我们得到了一个model。</p><p>先淡定！淡定！你以为把test.csv直接丢进model里就能拿到结果啊…骚年，图样图森破啊！我们的”test_data”也要做和”train_data”一样的预处理啊！！</p><figure class="highlight python"><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">data_test = pd.read_csv(<span class="string">"/home/kesci/input/titanic8120/test.csv"</span>)</span><br><span class="line">data_test.loc[ (data_test.Fare.isnull()), <span class="string">'Fare'</span> ] = <span class="number">0</span></span><br><span class="line"><span class="comment"># 接着我们对test_data做和train_data中一致的特征变换</span></span><br><span class="line"><span class="comment"># 首先用同样的RandomForestRegressor模型填上丢失的年龄</span></span><br><span class="line">tmp_df = data_test[[<span class="string">'Age'</span>,<span class="string">'Fare'</span>, <span class="string">'Parch'</span>, <span class="string">'SibSp'</span>, <span class="string">'Pclass'</span>]]</span><br><span class="line">null_age = tmp_df[data_test.Age.isnull()].values</span><br><span class="line"><span class="comment"># 根据特征属性X预测年龄并补上</span></span><br><span class="line">X = null_age[:, <span class="number">1</span>:]</span><br><span class="line">predictedAges = rfr.predict(X)</span><br><span class="line">data_test.loc[ (data_test.Age.isnull()), <span class="string">'Age'</span> ] = predictedAges</span><br><span class="line"></span><br><span class="line"><span class="comment">#数据正规化</span></span><br><span class="line">data_test = set_Cabin_type(data_test)</span><br><span class="line">dummies_Cabin = pd.get_dummies(data_test[<span class="string">'Cabin'</span>], prefix= <span class="string">'Cabin'</span>)</span><br><span class="line">dummies_Embarked = pd.get_dummies(data_test[<span class="string">'Embarked'</span>], prefix= <span class="string">'Embarked'</span>)</span><br><span class="line">dummies_Sex = pd.get_dummies(data_test[<span class="string">'Sex'</span>], prefix= <span class="string">'Sex'</span>)</span><br><span class="line">dummies_Pclass = pd.get_dummies(data_test[<span class="string">'Pclass'</span>], prefix= <span class="string">'Pclass'</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=<span class="number">1</span>)</span><br><span class="line">df_test.drop([<span class="string">'Pclass'</span>, <span class="string">'Name'</span>, <span class="string">'Sex'</span>, <span class="string">'Ticket'</span>, <span class="string">'Cabin'</span>, <span class="string">'Embarked'</span>], axis=<span class="number">1</span>, inplace=<span class="literal">True</span>)</span><br><span class="line"><span class="comment">#归一化</span></span><br><span class="line">df_test[<span class="string">'Age_scaled'</span>] = scaler.fit_transform(df_test[<span class="string">'Age'</span>].values.reshape(<span class="number">-1</span>,<span class="number">1</span>), age_scale_param)</span><br><span class="line">df_test[<span class="string">'Fare_scaled'</span>] = scaler.fit_transform(df_test[<span class="string">'Fare'</span>].values.reshape(<span class="number">-1</span>,<span class="number">1</span>), fare_scale_param)</span><br><span class="line">df_test.head()</span><br></pre></td></tr></table></figure><p>然后就真的可以丢尽model了<del>~</del></p><figure class="highlight python"><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">test = df_test.filter(regex=<span class="string">'Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*'</span>)</span><br><span class="line">predictions = clf.predict(test)</span><br><span class="line">result = pd.DataFrame(&#123;<span class="string">'PassengerId'</span>:data_test[<span class="string">'PassengerId'</span>].values, <span class="string">'Survived'</span>:predictions.astype(np.int32)&#125;)</span><br><span class="line">result.to_csv(<span class="string">"/home/kesci/work/savedata/titanic/logistic_regression_predictions.csv"</span>, index=<span class="literal">False</span>)</span><br></pre></td></tr></table></figure><p>结果符合预期，然后去make a submission啦啦啦！</p><h2 id="逻辑回归系统优化"><a href="#逻辑回归系统优化" class="headerlink" title="逻辑回归系统优化"></a>逻辑回归系统优化</h2><p>亲，你以为结果提交上了，就完事了？ 我不会告诉你，这只是万里长征第一步啊(泪牛满面)！！！<strong>这才刚撸完baseline model啊！！！还得优化啊！！！</strong></p><p>……未完持续，等我搞定baseline后再来继续优化</p><p>本文中用机器学习解决问题的过程大概如下图所示：</p><p><img src="/2019/06/11/titanic/100f3a39031e73bd0a8.jpg" alt="100f3a39031e73bd0a8"></p>]]></content>
    
    <summary type="html">
    
      &lt;p&gt;上次说了特征工程，这次照着别人的博客来复现一下kaggle上的hello world，python语法之类的我还是不熟悉，所以尽量把第一个项目做好，我&lt;strong&gt;这里仅仅是把大体的流程介绍一下，不会涉及到太多的语法。&lt;/strong&gt;&lt;/p&gt;
    
    </summary>
    
      <category term="kaggle" scheme="https://luoxjnono.github.io/categories/kaggle/"/>
    
    
  </entry>
  
  <entry>
    <title>机器学习初步：逻辑回归</title>
    <link href="https://luoxjnono.github.io/2019/06/11/%E9%80%BB%E8%BE%91%E5%9B%9E%E5%BD%92/"/>
    <id>https://luoxjnono.github.io/2019/06/11/逻辑回归/</id>
    <published>2019-06-11T07:19:25.000Z</published>
    <updated>2019-06-16T09:45:48.622Z</updated>
    
    <content type="html"><![CDATA[<h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><p>逻辑回归是应用非常广泛的一个分类机器学习算法，它将数据拟合到一个logit函数(或者叫做logistic函数)中，从而能够完成对事件发生的概率进行预测。</p><a id="more"></a><h2 id="由来"><a href="#由来" class="headerlink" title="由来"></a>由来</h2><p>我们知道，线性回归可以预测出连续值结果，但是在生活中，我们是主要要解决分类问题，这个时候我们可以通过设定一个阈值来解决这个问题，但是这种模型很难对复杂的情况进行的分析。</p><p><img src="/2019/06/11/逻辑回归/1560234269522.png" alt="1560234269522"></p><p>所以线性回归+阈值并不好，这个时候逻辑回归诞生了！</p><p>核心思想：线性回归的结果输出是一个连续值，而值的范围是无法限定的，那我们有没有办法把这个结果值映射为可以帮助我们判断的结果呢。ok，sigmoid函数可以实现这种功能。</p><p><img src="/2019/06/11/逻辑回归/1560234473968.png" alt="1560234473968"></p><p>所以我们定义线性回归的预测函数为Y=WTX，那么逻辑回归的输出Y= g(WTX)，其中y=g(z)函数正是上述sigmoid函数(或者简单叫做S形函数)。</p><h2 id="判定边界"><a href="#判定边界" class="headerlink" title="判定边界"></a>判定边界</h2><p>那么为什么通过把函数值限制在一定范围内就可以分类呢，我们还需要判定边界。可以理解为是用以对不同类别的数据分割的边界，边界的两旁应该是不同类别的数据。下面是一个例子：</p><p><img src="/2019/06/11/逻辑回归/1560234600900.png" alt="1560234600900"></p><p>这个边界是没有规则的，那么逻辑回归是如何根据样本点获得这些边界的呢？</p><p>回到sigmoid函数，我们发现：  </p><p>​        当g(z)≥0.5时,，<strong>z&gt;=0,意味着y=1</strong>，故z=0是一个决策边界</p><p>解释：</p><p>hθ(x)的因变量取值区间是[0，1]，并且关于坐标点（0，0.5）对称（可从Sigmoid Logistic Function图中看出来），所以以hθ(x)=g(θTX)=0.5的点为分界点，所以hθ(x)=g(θTX)≥0.5,时，则θTX≥0。而最后预估y的时候是把y分为两部分，分别用1和0去表示，hθ(x)=g(θTX)≥0.5的点表示为1，hθ(x)=g(θTX)≤0.5的点表示为0.</p><p>在逻辑回归中，z就是θTX。</p><p>先看第一个例子hθ(x)=g(θ0+θ1X1+θ2X2)，其中θ0 ,θ1 ,θ2分别取-3, 1, 1。则当−3+X1+X2≥0时, y = 1; 则X1+X2=3是一个决策边界，图形表示如下，刚好把图上的两类点区分开来：</p><p><img src="/2019/06/11/逻辑回归/1560234900255.png" alt="1560234900255"></p><p>至于那些更复杂的曲线，hθ(x)也更复杂，这就是上面那个曲线边界出现的原因</p><h2 id="代价函数与梯度下降"><a href="#代价函数与梯度下降" class="headerlink" title="代价函数与梯度下降"></a>代价函数与梯度下降</h2><p>所以无论二维三维更高维，<strong>分类边界可以统一表示成h(x)=ΘTx</strong>，我们如何判定hθ(x)中的参数θ是否合适？如何选择θ？</p><p>我们要寻找出<strong>最佳参数Θ</strong>，使得对于1类别的点x，h(x)趋于正无穷，对于0类别的点x，h(x)趋于负无穷</p><p><strong>跳过大量的证明，由cost函数的得知，我们是通过sigmoid函数进行的计算然后找出最佳的θ，从而得出合适的边界，在处理数据时我们通过边界判断。</strong></p><p>（这个时候就不是判定边界的事情了，只要你的参数确定了，判定边界自然也就确定了，所以核心行还是参数的确定，这个时候需要用到数分的知识，通过多次迭代，找出代价最小的参数（可能有多个参数12345……）,而我们是通过给定的代价函数求参数的）</p><p>所谓的代价函数Cost Function，其实是一种衡量我们在这组参数下预估的结果和实际结果差距的函数，下面是线性回归的代价函数，比较直观：</p><p><img src="/2019/06/11/逻辑回归/1560235101791.png" alt="1560235101791"></p><p>当然核心是选择合适的参数θ，我们要找到 有曲面为碗状的作为合适的代价函数g(θTx)好像并不符合这种特性，</p><p><img src="/2019/06/11/逻辑回归/1560235444486.png" alt="1560235444486"></p><p>这个函数有很好的惩罚效果，具体推理会在西瓜上总结</p><p> 下面我们说说梯度下降，梯度下降算法是调整参数θ使得代价函数J(θ)取得最小值的最基本方法之一。从直观上理解，就是我们在碗状结构的凸函数上取一个初始值，然后挪动这个值一步步靠近最低点的过程</p><p>从数学上理解，我们为了找到最小值点，就应该朝着下降速度最快的方向(导函数/偏导方向)迈进，每次迈进一小步，再看看此时的下降最快方向是哪，再朝着这个方向迈进，直至最低点。这个应该不难理解吧。</p><p>这个部分唯一的疑点就是我变量的幂要怎么选取（非线性的话要对变量进行映射）</p><h2 id="代码与实现"><a href="#代码与实现" class="headerlink" title="代码与实现"></a>代码与实现</h2><p>只有实践能够解决所有疑问，上面说那么多没啥用的。</p><p>下面是python画出的一份数据图</p><p><img src="/2019/06/11/逻辑回归/1560236011234.png" alt="1560236011234"></p><p>我们来看看关键的代码实现</p><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#sigmoid函数</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">sigmoid</span><span class="params">(X)</span>:</span></span><br><span class="line">    <span class="string">'''Compute sigmoid function '''</span></span><br><span class="line">    den =<span class="number">1.0</span>+ e **(<span class="number">-1.0</span>* X)</span><br><span class="line">    gz =<span class="number">1.0</span>/ den</span><br><span class="line">    <span class="keyword">return</span> gz</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">compute_cost</span><span class="params">(theta,X,y)</span>:</span></span><br><span class="line">    <span class="string">'''computes cost given predicted and actual values'''</span></span><br><span class="line">    m = X.shape[<span class="number">0</span>]<span class="comment">#number of training examples</span></span><br><span class="line">    theta = reshape(theta,(len(theta),<span class="number">1</span>))</span><br><span class="line">    </span><br><span class="line">    J =(<span class="number">1.</span>/m)*(-transpose(y).dot(log(sigmoid(X.dot(theta))))- transpose(<span class="number">1</span>-y).dot(log(<span class="number">1</span>-sigmoid(X.dot(theta)))))</span><br><span class="line">    </span><br><span class="line">    grad = transpose((<span class="number">1.</span>/m)*transpose(sigmoid(X.dot(theta))- y).dot(X))</span><br><span class="line">    <span class="comment">#optimize.fmin expects a single value, so cannot return grad</span></span><br><span class="line">    <span class="keyword">return</span> J[<span class="number">0</span>][<span class="number">0</span>]<span class="comment">#,grad</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">compute_grad</span><span class="params">(theta, X, y)</span>:</span></span><br><span class="line">    <span class="string">'''compute gradient'''</span></span><br><span class="line">    theta.shape =(<span class="number">1</span>,<span class="number">3</span>)</span><br><span class="line">    grad = zeros(<span class="number">3</span>)</span><br><span class="line">    h = sigmoid(X.dot(theta.T))</span><br><span class="line">    delta = h - y</span><br><span class="line">    l = grad.size</span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> range(l):</span><br><span class="line">        sumdelta = delta.T.dot(X[:, i])</span><br><span class="line">        grad[i]=(<span class="number">1.0</span>/ m)* sumdelta *<span class="number">-1</span></span><br><span class="line">    theta.shape =(<span class="number">3</span>,)</span><br><span class="line">    <span class="keyword">return</span>  grad</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>它始于输出结果为有实际意义的连续值的线性回归，但是线性回归对于分类的问题没有办法准确而又具备鲁棒性地分割，因此我们设计出了逻辑回归这样一个算法，它的<strong>输出结果表征了某个样本属于某类别的概率</strong>。</p><p>而直观地在二维空间理解逻辑回归，是sigmoid函数的特性，<strong>使得判定的阈值能够映射为平面的一条判定边界</strong>，当然随着特征的复杂化，判定边界可能是多种多样的样貌，但是它能够较好地把两类样本点分隔开，解决分类问题。</p><p><strong>求解逻辑回归参数的传统方法是梯度下降，构造为凸函数的代价函数后，每次沿着偏导方向(下降速度最快方向)迈进一小部分，直至N次迭代后到达最低点。</strong></p><p>总结一下思绪，<strong>logistic回归的任务就是要找到最佳的拟合参数,从而得出边界，从而可以对数据进行判断。</strong>。</p><p>不愧是逻辑回顾，先撤了，具体的实现过一阵子看看，现在会用逻辑回归就行了。</p><p>又回来看了一下，才发现sigmoid函数的精妙之处，希望有时间能将数学证明过一遍。</p><p>参考资料：<a href="http://blog.csdn.net/han_xiaoyang/article/details/49123419" target="_blank" rel="noopener">http://blog.csdn.net/han_xiaoyang/article/details/49123419</a></p>]]></content>
    
    <summary type="html">
    
      &lt;h2 id=&quot;概念&quot;&gt;&lt;a href=&quot;#概念&quot; class=&quot;headerlink&quot; title=&quot;概念&quot;&gt;&lt;/a&gt;概念&lt;/h2&gt;&lt;p&gt;逻辑回归是应用非常广泛的一个分类机器学习算法，它将数据拟合到一个logit函数(或者叫做logistic函数)中，从而能够完成对事件发生的概率进行预测。&lt;/p&gt;
    
    </summary>
    
      <category term="机器学习" scheme="https://luoxjnono.github.io/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"/>
    
    
  </entry>
  
</feed>
