<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Two Pointers on 跟著 Desolve 學程式</title><link>https://desolve.pages.dev/tags/two-pointers/</link><description>Recent content in Two Pointers on 跟著 Desolve 學程式</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><lastBuildDate>Sat, 29 Jun 2019 00:00:00 +0800</lastBuildDate><atom:link href="https://desolve.pages.dev/tags/two-pointers/index.xml" rel="self" type="application/rss+xml"/><item><title>從LeetCode學演算法 - 3 Two Pointers</title><link>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-3-two-pointers/</link><pubDate>Sat, 29 Jun 2019 00:00:00 +0800</pubDate><guid>https://desolve.pages.dev/post/learn-algorithm-from-leetcode-3-two-pointers/</guid><description>&lt;img src="https://desolve.pages.dev/img/default-leetcode.webp" alt="Featured image of post 從LeetCode學演算法 - 3 Two Pointers" /&gt;&lt;p&gt;&lt;strong&gt;0015. 3Sum (Medium)&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="question"&gt;Question
&lt;/h2&gt;&lt;p&gt;Given an array &lt;code&gt;nums&lt;/code&gt; of &lt;em&gt;n&lt;/em&gt; integers, are there elements &lt;em&gt;a&lt;/em&gt;, &lt;em&gt;b&lt;/em&gt;, &lt;em&gt;c&lt;/em&gt; in &lt;code&gt;nums&lt;/code&gt;such that &lt;em&gt;a&lt;/em&gt; + &lt;em&gt;b&lt;/em&gt; + &lt;em&gt;c&lt;/em&gt; = 0? Find all unique triplets in the array which gives the sum of zero.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The solution set must not contain duplicate triplets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Given array nums = [-1, 0, 1, 2, -1, -4],
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#8087a2"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;A solution set is:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [-1, 0, 1],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [-1, -1, 2]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="分析解題"&gt;分析/解題
&lt;/h3&gt;&lt;p&gt;題目要求從陣列中找出所有數組a, b, c，&lt;br&gt;
使得三者相加為0，且不能重覆。&lt;/p&gt;
&lt;p&gt;老話一句，&lt;strong&gt;請記得問有沒有排序XD~&lt;/strong&gt;&lt;br&gt;
以暴力法解本題的話，會發現每次取三個做組合，&lt;br&gt;
顯然會得到一個O(N³)的時間複雜度的解。&lt;br&gt;
那麼，嘗試排序看看能得到比較好的解嗎？&lt;br&gt;
我們先拿題目的例子來看看，排序過後為&lt;br&gt;
[-4, -1, -1, 0, 1, 2]&lt;br&gt;
按順序排列會有什麼好處呢？&lt;br&gt;
假設我們先固定最左邊的-4為a(因為要組合，我們可以令a&amp;lt;=b&amp;lt;=c)，&lt;br&gt;
那麼b+c必須等於4，這邊使用一個簡單的技巧，&lt;br&gt;
先將b指定給-1的位置，c指定給2的位置，&lt;br&gt;
兩者相加等於1，表示&lt;strong&gt;應該要取更大的值&lt;/strong&gt; 才有機會讓和等於4，&lt;br&gt;
於是我們可以將b的位置向右移一格(這裡是重覆的所以可以跳過)，&lt;br&gt;
再次檢查和目標的大小比較。&lt;/p&gt;
&lt;p&gt;那麼很容易可以發現一件事情：&lt;br&gt;
當現在的值比目標值&lt;strong&gt;大&lt;/strong&gt; 時，表示&lt;strong&gt;應該要取更小的值&lt;/strong&gt; ，&lt;br&gt;
只有&lt;strong&gt;將c往左移動&lt;/strong&gt; 才有可能達到。&lt;br&gt;
反之，&lt;br&gt;
當現在的值比目標值&lt;strong&gt;小&lt;/strong&gt; 時，表示&lt;strong&gt;應該要取更大的值&lt;/strong&gt; ，&lt;br&gt;
只有將&lt;strong&gt;b往右移動&lt;/strong&gt; 才有可能達到。&lt;br&gt;
因此，在固定a值的時候，只要將後面的數按照上面的方法，&lt;br&gt;
一次移動一格的掃過一遍，就可以得到這個a值所可以成立的組合。&lt;/p&gt;
&lt;p&gt;所以最終我們只要將a從0~len(nums)-3按順序跑過一遍，&lt;br&gt;
將中間符合的組合都放進list中，即可得到答案。&lt;/p&gt;
&lt;p&gt;重覆性的部分，只要記得檢查前一個和這一個用的數字是否相同即可避免。&lt;/p&gt;
&lt;p&gt;上述的做法，由於使用到兩個指標(指針)，並透過移動它們來達到掃描陣列的目的，我們通常稱這樣的解法為&lt;strong&gt;Two Pointer&lt;/strong&gt; ，是蠻常用的技巧。&lt;br&gt;
時間複雜度的部分，排序的一般狀況是O(NlogN)，&lt;br&gt;
而a的長度是O(N)，每次都要掃完其後的長度，掃描部分即為O(N²)，&lt;br&gt;
所以總體的時間複雜度為O(N²)。&lt;/p&gt;
&lt;h3 id="java"&gt;Java
&lt;/h3&gt;&lt;script src="https://gist.github.com/Desolve/075ff6e7224a53d85c2acaf0c6b73b6e.js"&gt;&lt;/script&gt;
&lt;p&gt;這邊使用i, j, k標記，要用a, b, c也可XD&lt;br&gt;
使用Arrays.asList可以將一串元素塞成ArrayList。&lt;/p&gt;
&lt;h3 id="python"&gt;Python
&lt;/h3&gt;&lt;p&gt;Python的部分提供了另一個的思路，&lt;br&gt;
這是由 &lt;a class="link" href="https://leetcode.com/rouroukerr" target="_blank" rel="noopener"
&gt;RouRouKerr&lt;/a&gt;在討論區所提出的解法，這邊是改成Python3版本。&lt;br&gt;
他的想法是，在固定第一個數v的狀況，那當其中一個數為x，&lt;br&gt;
另一個數只能是-v-x(因為加總要等於0)。&lt;br&gt;
故每次將對應的互補數加入到dict中，&lt;br&gt;
我們只要從頭到尾檢查，即可得到所有的正確組合。&lt;br&gt;
這個想法跟前面Two Sum的解法概念是一樣的。&lt;br&gt;
(對應到Java版本的解法也附在註解處)&lt;/p&gt;
&lt;script src="https://gist.github.com/Desolve/6c1a4c1f6b3fad320f8f5e5b0bbcbb5b.js"&gt;&lt;/script&gt;
&lt;h2 id="面試實際可能會遇到的問題"&gt;面試實際可能會遇到的問題
&lt;/h2&gt;&lt;p&gt;「(Python)前面不檢查的話後面你怎麼處理重覆？」(用set)&lt;br&gt;
「假設目標不是0的話？」(方法應該是一樣的)&lt;br&gt;
「(Python)dictionary的部分使用set代替會比較快嗎？」(實測過會變慢XD)&lt;br&gt;
「(Java)如果可以改變input/output的變數形態的話，你會希望改動什麼？」&lt;br&gt;
(改output，因為輸出應該固定會是3元組的組合(長度必然是3)，&lt;br&gt;
那大可以使用List&amp;lt;int[]&amp;gt;，用List&amp;lt;List&lt;Integer&gt;&amp;gt;其實較不理想)&lt;/p&gt;
&lt;p&gt;只要掌握了Two Pointers的概念，很多題目其實可以在排序後輕鬆解決，&lt;br&gt;
但記得注意有些題目可以比O(NlogN)快的話，排序會提高時間複雜度歐！&lt;/p&gt;
&lt;p&gt;從LeetCode學演算法，我們下次見囉，掰~&lt;/p&gt;</description></item></channel></rss>