[{"content":"歡迎使用台股即時查詢系統！請在下方圖表左上角點擊「股票代號」，輸入您想查詢的台股（例如：2330 或 鴻海）。\n查詢 畫支撐 畫壓力 清除線條 資料載入中... ","date":"2026-05-02T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/tools.webp","permalink":"https://learnwithdesolve.netlify.app/post/tw-stock-chart/","title":"📈 台股即時 K 線查詢系統"},{"content":"當了新手奶爸以後，出門在外最煩的就是沒有剛好70度的水，\n簡單寫一個程式來算看看吧!\n也提供大家參考~\n🍼 泡奶溫度計算器 冷水溫度 (°C) 熱水溫度 (°C) 目標溫度 (°C) 總泡奶量 (ml) 啟用自動對齊 10ml 單位 (建議) 計算中... ","date":"2026-05-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/tools.webp","permalink":"https://learnwithdesolve.netlify.app/post/milk-calculator/","title":"🍼 泡奶溫度計算器"},{"content":"白挖的加密貨幣，不香嗎？\n寫在前面： (基礎+進階+面試篇)從 LeetCode 學演算法 + 面試成功指南**\n(3990元 長期有效) https://bit.ly/lc2022all\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/lc2022adv\n正文開始!\n今天要介紹的是Bybit Lauchpool的PIRATE挖礦。\nhttps://www.bybit.com/zh-TW/trade/spot/launchpool?ref=66DYKO#0 如果讀者對於加密貨幣及交易所有一些基本的認識的話，\n應該聽說過Bybit交易所，它是目前交易所中排名前五的交易所。\n(下圖為CoinMarketCap的排名列表)\n什麼是PIRATE？\n根據官方的說明：\nPirate Nation is a fully onchain pirate-themed role-playing game (RPG) on Proof of Play Apex. Players assemble their pirate crews, build their ships, explore the great seas, search for treasure, level up, battle fantastic creatures, and compete with other players to top the leaderboards. It aims to define the next wave of casual gaming on mobile, with a fun and engaging FOCG (fully onchain game) that allows players to earn, spend, create, and share. Pirate Nation is currently being played on a desktop browser, with a mobile (iOS and Android) release planned for 1H 2024. The roadmap for their game is updated live for the community on a regular basis.\n簡單來說，它就是一個區塊鏈遊戲的貨幣，對遊戲本身有興趣的話，可以參見 https://piratenation.game/。\n為什麼要在Bybit上挖PIRATE？\n在Bybit上，它是近期除了NOT (NOTCOIN，先前也上架了幣安，算是一個遊戲迷因幣)外，年化報酬相對較高的。目前直接質押USDT來挖，還有3天的時間可以挖，而且年化目前還有55.02% 。\n(一般隨著時間，或多或少都有後知後覺發現的人加入XD)\n(上面是2024/06/16時的截圖)\nMNT(Mantle幣，Bybit的平台幣)和USDT的質押池最低都是100顆起投，\nMNT上限為5000顆，USDT上限為2000顆。\n以USDT來說，筆者2000顆目前取得質押2天的收益為26.3851 PIRATE，\n以現價0.267左右計算的話，約略等於7.044 USDT，也就是一天3.522 USDT，\n一天0.1761%，年化約64.27% (你看看，又下降了XD)\n(質押後收益分配要第 t+2 日才給予)\nPIRATE的價格？\nPIRATE剛開盤的最高點為0.35，回落到0.129以後，\n後續一度漲到接近0.4，而目前來到0.27附近。\n由於PIRATE本身是遊代幣的原因，筆者對該遊戲全無研究，\n遊戲代幣也很難去估計其基本面和市值，和ENA不同，\n看好基本面的加密貨幣，或者可以賣一半留一半；\n而這類代幣筆者原則上建議全數賣出，落袋為安，\n只要不要自行入場的話，怎麼樣都是不會虧的 。\n以上分享，提供給大家參考～\n如果讀者還沒有使用過Bybit交易所的話，歡迎使用筆者的refer連結：\nhttps://www.bybit.com/zh-TW/trade/spot/launchpool?ref=66DYKO#0 如果是需要開Bybit帳戶的話也歡迎使用： https://www.bybit.com/invite?ref=66DYKO%230 免責聲明：\n以上分享均屬個人心得，不構成任何投資建議，進行任何投資前請務必先進行投資內容及風險之評估，並自負盈虧XD。\n","date":"2024-06-16T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-crypto.webp","permalink":"https://learnwithdesolve.netlify.app/post/bybit-lauchpool-pirate/","title":"(限時)活動分享-Bybit Lauchpool PIRATE"},{"content":"Categories: Graph/DFS Level: Medium Introduction: (Basic + Advanced + Interview Edition) Learning Algorithms from LeetCode + Interview Success Guide (Regular price: 3591 NTD, Discounted price until 2024/05/16 23:59)\nhttps://hiskio.com/bundles/egb397?s=tc\n(Regular price: 3990 NTD, Valid for a long term) https://bit.ly/lc2022all\nPlease help me click on the “SHOW EMBED” below and give it 5 likes~ If you like it, you can also give me a round of applause~ (Liking doesn’t cost anything, thank you for supporting my writing~)\nQuestion There is a directed graph of n nodes with each node labeled from 0 to n - 1. The graph is represented by a 0-indexed 2D integer array graph where graph[i] is an integer array of nodes adjacent to node i, meaning there is an edge from node i to each node in graph[i].\nA node is a terminal node if there are no outgoing edges. A node is a ** safe node** if every possible path starting from that node leads to a ** terminal node** (or another safe node).\nReturn an array containing all the *safe nodes * of the graph. The answer should be sorted in ascending order.\nExample 1 1 2 3 4 5 Input: graph = [[1,2],[2,3],[5],[0],[5],[],[]] Output: [2,4,5,6] Explanation: The given graph is shown above. Nodes 5 and 6 are terminal nodes as there are no outgoing edges from either of them. Every path starting at nodes 2, 4, 5, and 6 all lead to either node 5 or 6. Example 2 1 2 3 Input: graph = [[1,2,3,4],[1,2],[3,4],[0,4],[]] Output: [4] Explanation: Constraints n == graph.length 1 \u0026lt;= n \u0026lt;= 104 0 \u0026lt;= graph[i].length \u0026lt;= n 0 \u0026lt;= graph[i][j] \u0026lt;= n - 1 graph[i] is sorted in a strictly increasing order. The graph may contain self-loops. The number of edges in the graph will be in the range [1, 4 * 104]. Analysis/Approach:\nThere is a directed graph with n nodes, each labeled from 0 to n-1. The graph is represented using a 2D array called “graph,” where graph[i] represents the nodes connected to node i with an edge. The direction of the edge is from node i to each node in graph[i]. If a node has no outgoing edges , it is considered a terminal node . If all possible paths from a node ** lead to terminal nodes**, the node is considered a ** safe node**.\nThe task is to find all the safe nodes in the graph and return them in ascending order as an array (or list). To determine if a node is a safe node, we need to check if there are any cycles in the paths starting from that node. ** If there is a cycle, the node itself and all the nodes in the cycle will not be safe nodes.** Additionally, since we need to check that all paths are cycle-free to determine a safe node, ** the results from earlier checks for nodes can be applied to later checks.**\nTo solve this problem, we can use a depth-first search (DFS ) approach to traverse each node and its paths until the end (or until we can determine if there is a cycle). The steps for solving the problem are as follows:\nInitialize two arrays/lists, vis and ** path**, to keep track of whether a node has been visited and whether it is part of a cycle. Both arrays/lists should have a length equal to the number of nodes in the graph, n, and initialized with 0 (or False). Initialize an empty result list called res . Declare a DFS function that takes the current node, graph , vis , and path as parameters and returns ** True if a cycle is found** and ** False if no cycle is found**. In the DFS function, perform the following steps: 4.1. Set vis[curr] and ** path[curr]** to ** 1** (indicating that the node has been visited and is temporarily part of a cycle). 4.2. Iterate over the nodes u in graph[curr] : 4.2.1. If vis[u] is 0 (indicating that the node hasn’t been visited), recursively call DFS with u as the current node and check if it returns True. ** If True, return True (indicating a cycle is found). 4.2.2. Otherwise, if path[u] == 1 (indicating that u is already part of a cycle), return ** True. 4.3. After the loop ends without returning True , it means there is no cycle found when going down from the current node. ** Reset path[curr] to 0 and return False. (Since we set all the path[curr] alone with 1, we need to set it back)** In the main function, use a loop to iterate over i from 0 to n-1 . If vis[i] is 0, call DFS with i as the current node. After all iterations, use another loop to iterate over i from 0 to n-1 and add the nodes i with path[i] == 0 to the res list. Return the res list. Here is the code implementation in both Java and Python:\nJava In the Java implementation, an ArrayList is used for the res variable. If we want to reduce the number of parameters passed to the dfs function, we can make vis and path class variables. However, since their lengths are tied to the number of nodes in the graph, they still need to be initialized within the eventualSafeNodes method.\nPython As mentioned before, in the Python implementation, using nested functions can slightly reduce the number of variables that need to be passed as arguments. In fact, if we move the vis and path arrays/lists to the outermost scope, they don\u0026rsquo;t need to be passed as arguments at all because the nested function can access variables from the outer scope.\nYou may try rewriting the code and experimenting with this approach.\nPotential Interview Questions:\n“What are the time and space complexities?”\n(O(V+E)/O(V) , where V is the number of nodes in the graph and E is the number of edges in the graph)\n“Can we use a single array/list to handle visited nodes and cycles?” (Hint: State can have more than 1 or 0; you can use 3 different states to handle this)\nSimilar and Extended Topics:\nSpecial thanks to suggestions/corrections from viewers:\n(Welcome to provide feedback to help with corrections~)\nLearn Algorithms from LeetCode — See you next time!\nWant to see more problems? Feel free to check out Article 0 for the topic you want!\nAlso, follow our Facebook page for notifications on new articles:\nLearn with Desolve ","date":"2024-05-01T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithms-from-leetcode-121-0802-find-eventual-safe-states/","title":"Learn Algorithms from LeetCode-121 (0802. Find Eventual Safe States)"},{"content":"Categories: Graph/DFS Level: Medium 寫在前面 (基礎+進階+面試篇)從 LeetCode 學演算法 + 面試成功指南**\n(3591元有效期限至 2024/05/16 23:59)\nhttps://hiskio.com/bundles/egb397?s=tc\n(3990元 長期有效) https://bit.ly/lc2022all\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/lc2022adv\nQuestion There is a directed graph of n nodes with each node labeled from 0 to n - 1. The graph is represented by a 0-indexed 2D integer array graph where graph[i] is an integer array of nodes adjacent to node i, meaning there is an edge from node i to each node in graph[i].\nA node is a terminal node if there are no outgoing edges. A node is a ** safe node** if every possible path starting from that node leads to a ** terminal node** (or another safe node).\nReturn an array containing all the *safe nodes * of the graph. The answer should be sorted in ascending order.\nExample 1 1 2 3 4 5 Input: graph = [[1,2],[2,3],[5],[0],[5],[],[]] Output: [2,4,5,6] Explanation: The given graph is shown above. Nodes 5 and 6 are terminal nodes as there are no outgoing edges from either of them. Every path starting at nodes 2, 4, 5, and 6 all lead to either node 5 or 6. Example 2 1 2 3 4 Input: graph = [[1,2,3,4],[1,2],[3,4],[0,4],[]] Output: [4] Explanation: Only node 4 is a terminal node, and every path starting at node 4 leads to node 4. Constraints n == graph.length 1 \u0026lt;= n \u0026lt;= 104 0 \u0026lt;= graph[i].length \u0026lt;= n 0 \u0026lt;= graph[i][j] \u0026lt;= n - 1 graph[i] is sorted in a strictly increasing order. The graph may contain self-loops. The number of edges in the graph will be in the range [1, 4 * 104]. 分析/解題 有一個有向圖，當中包含了n個節點，每個節點分別被標記為0~n-1。\n這個圖使用2D的array graph來表示，\n當中graph[i]代表所有從節點i有邊(edge)相連的節點，\n且方向是從節點i到每個graph[i]中的節點。\n如果一個節點沒有任何向外的邊 的話，則該節點是terminal node ；\n如果從一個節點出去的所有可能的路徑 都導向到terminal node 的話，\n則該節點是safe node 。\n試找出所有圖中的safe nodes，並且以陣列(串列)型態回傳，\n當中答案必須要以升冪排序 (由小到大排列)。\n首先我們要思考的是，怎麼樣的狀況下會沒辦法terminal呢？\n按照定義，一旦導到terminal node ，則由於沒有向外的邊，\n於是路徑就會停在terminal node了(因為無路可走 )。\n換句話說，如果要不停下來的話，就要一直有路可走。\n但節點和邊都是有限的 ，那麼就只有當存在環 的狀況下，\n才能夠一直有路可以走囉！\n因此，要判斷一個點是否為safe node，\n端看從該點出發的路徑是否存在有環 ；\n如果有環的話，則包含該點，以及環上的所有節點都不會是safe node 。\n同時，由於我們判斷safe node必須要所有路徑 都沒有環存在，\n因此前面檢查過的節點結果，會同樣適用於後面的檢查 。\n例如：從點A出發，如果其中一條路徑我們走過點B跟點C，\n那麼下次當檢查從點B出發的時候，\n我們可以直接採納前面點A出發經過點B時對點B判斷的結果，\n如此一來就不用重新再走一遍了！\n那麼這題應該要做的就是遍歷每一個節點及路徑，\n並且每條路徑都走到底(或者走到可以判定是否有環)為止，\n這顯然適用於DFS的做法。\n讓我們來試著列看看解題步驟：\n初始化兩個陣列(串列) vis, path ，分別代表該節點是否已造訪過，\n以及該節點是否為某個環的一部分，兩者的長度均為graph的節點數量n，\n預設值均為0(或False也可以)。 初始化一個空的res串列備用。 宣告一個dfs函式，代入curr, graph, vis, path (curr為要檢查的node)，\n其回傳True則代表存在環，False則代表不存在環 。 在dfs函式中，進行以下處理：\n4–1. 將vis[curr]和path[curr]均設為1 (也就是已造訪，且暫定環存在 )\n4–2. 迴圈從graph[curr] 中取出節點u：\n4–2–1. 若vis[u]為0 (表示這個節點還沒被造訪) -\u0026gt; 代入到dfs往下檢查，如得到回傳True的話則也回傳True(代表確定有環)\n4–2–2. 否則，若path[u] == 1 (表示** u在環上**)，回傳True。\n4–3. 經過迴圈結束後尚未回傳，代表其實從curr往下走並不存在環，\n這時候重新將path[curr]設為0 ，並且回傳False 。\n(前面直接回傳True的時候，因為我們預先將沿路的path[curr]設為1，\n因此離開的時候整條路徑上的節點都被標記成環了 ；\n反過來說，當發現不存在環的時候，該還原的就要還原回來 。) 在主函式中，使用迴圈令i依次從0~n-1 ，\n如果vis[i] == 0 的話，就代入進行dfs。 都做完的狀況下，再次使用迴圈令i從0~n-1 ，\n將path[i] == 0 的i 加入到res。 回傳res。 依此，寫成程式碼如下：\nJava Java的部分使用了ArrayList給res使用，\n如果想要讓dfs不要帶入那麼多東西的話，\n也可以將vis跟path設定為class variables，\n不過因為長度跟graph的節點數掛勾，\n所以還是要在eventualSafeNodes裡才能初始化。\nPython Python的部分如同以前提到過的，\n使用子函式也可以稍微減少需要代入的變數量，\n甚至將vis和path放最前面的話也可以連它們都不需要代入，\n因為子函式可以去取得到上面這層的變數。\n(讀者可以自行嘗試再改寫看看)\n面試實際可能會遇到的問題 「時間／空間複雜度？」\n(O(V+E)/O(V)，V為graph的節點數，E為graph的邊數)\n「能不能只用一個陣列／串列來處理經過的節點和環？」\n(提示：State可以不只有1或0，可以設定3種state來處理)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/lc2022base\n","date":"2024-05-01T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-121-0802-find-eventual-safe-states/","title":"從LeetCode學演算法-121 (0802. Find Eventual Safe States)"},{"content":"白挖的加密貨幣，不香嗎？\n寫在前面： (基礎+進階+面試篇)從 LeetCode 學演算法 + 面試成功指南**\n(3990元 長期有效) https://bit.ly/lc2022all\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/lc2022adv\n正文開始!\n今天要介紹的是Bybit Lauchpool的ENA挖礦。\nhttps://www.bybit.com/zh-TW/trade/spot/launchpool?ref=66DYKO#0 如果讀者對於加密貨幣及交易所有一些基本的認識的話，\n應該聽說過Bybit交易所，它是目前交易所中排名前五的交易所。\n(下圖為CoinMarketCap的排名列表)\n什麼是ENA？\n根據官方的說明：\nEthena is a synthetic dollar protocol built on Ethereum that will provide a crypto-native solution for money that is not reliant on traditional banking system infrastructure, alongside a globally accessible dollar-denominated savings instrument — the ‘Internet Bond’.\n白話文來說，ENA是一種治理代幣，它所想要處理的是產生一種新型的穩定幣，而這個穩定幣(USDe)就是藉由對沖以太坊的抵押品，來提供掛鉤美元的價值，並提供Staking的利息。\n為什麼要在Bybit上挖ENA？\n如果讀者有在關注幣圈，或主要使用幣安(Binance)交易所的話，\n應該知道ENA是最近一期幣安上新幣挖礦的項目，而且才剛挖完；\n在幣安上挖礦的方式，\n是質押BNB(幣安的平台幣) 或FDUSD(幣安主推的穩定幣) 來進行挖礦。\n而在Bybit上，\n你可以直接質押USDT來挖，而且年化還蠻高的XD。\n(下面是2024/04/04時的截圖)\n兩個池子的最低質押額均為100顆，收益率會隨著分的人而下降，\n所以要參加就要快一點，能挖多少算多少XD\n以筆者前一天的狀況為例，質押366.5169USDT，\n一天分配到了6.3365顆ENA，如果以一顆1 USDT來計算的話，\n一天領到了1.72% ，年化達631% (所以你看，越早挖越好XD)\nENA的價格？\nENA在幣安的現貨價格在昨天最高來到1.320 ，\n來回測了幾次0.95，現價在1.1 上下徘徊。\n看過不少五花八門的分析，大多數文章看好其價格落在1.2 ~ 2 之間。\n但，這重要嗎？不重要XD\n就質押USDT挖ENA出來賣就好了，賣多少算多少，\n價格這個點不是我們所能控制的，只要它能落在1塊錢上下，\n筆者認為，取一些USDT暫時擺到Bybit進行質押，\n在目前看來應該是一個投報率不錯的選擇，\n而且相應來說風險應和質押USDT活存是差不多的。\n以上分享，提供給大家參考～\n如果讀者還沒有使用過Bybit交易所的話，歡迎使用筆者的refer連結：\nhttps://www.bybit.com/zh-TW/trade/spot/launchpool?ref=66DYKO#0 如果是需要開Bybit帳戶的話也歡迎使用： https://www.bybit.com/invite?ref=66DYKO%230 免責聲明：\n以上分享均屬個人心得，不構成任何投資建議，進行任何投資前請務必先進行投資內容及風險之評估，並自負盈虧XD。\n","date":"2024-04-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-crypto.webp","permalink":"https://learnwithdesolve.netlify.app/post/bybit-lauchpool-ena/","title":"(限時)活動分享-Bybit Lauchpool ENA"},{"content":"不要再讓人看到錯誤的變數命名尷尬了! Code Spell Checker是你的好夥伴!\n作為需要撰寫程式的各位讀者，是否日常中會遇到以下問題呢？\n變數名稱想取有意義的，又怕太長打錯字？ 跟別人合作的時候老是看到錯字連篇，又礙於同(ㄑㄧㄢˊ)事(ㄅㄟˋ)情(ㄅㄞˇ)誼(ㄌㄠˇ)，不好意思要求修正？ 自己寫完程式跑不過，最後才發現在一個不起眼的地方打錯了變數名稱？ 以上東西，在VS Code中使用Code Spell Checker就能搞定！\n(2的話可能會再複雜一點，建議推薦同事們一起裝起來)\n在VS Code左側選單的Extension中，鍵入Code Spell Checker，選擇第一個後，按右邊的Install進行安裝。\n註：筆者已經安裝了，所以這邊會顯示Uninstall\n接下來呢？\n接下來Code Spell Checker就會變成糾錯小魔人，\n每個你打開的檔案都會被掃過一次，如果它覺得：\n「阿這邊好像怪怪的呦～」\n那麼底下就會出現波浪符號的標記，如下所示：\n將滑鼠移過去就能看到它的說明，\n按下 Quick Fix\u0026hellip; 或Ctrl + . 則會顯示建議修改的字：\n肯定是打太快了XD\n通常狀況下，如果是typo的狀況，往往第一個字就會是正確的字了！\n選擇完以後，就會幫你修改成正確的樣子；同時，如果有使用到對應變數/函式的話，原則上它會幫你同步做修改 ，如下所示，我呼叫faetures(3533)的函式名稱也被同步改過去了。\n如果這個字並不是錯字，而是在這個專案中大家約定俗成的縮寫字，\n或者是專業用語的字的話，怎麼辦呢？\n可以選擇 Add: to user settings 或 ** Add: to workspace settings**；\n前者是對於使用者通用 ，也就是變成加到你在VS Code的字典裡；\n後者僅對於現在開的這個專案有效 ，\n在專案目錄底下會新增一個.vscode資料夾，\n當中有一個settings.json來儲存你的字典。\n其他還有一些細部的功能，如果有興趣的讀者可以再玩玩看XD\n但現在最重要的就是，\n強烈建(ㄧㄠ)議(ㄑㄧㄡˊ)各位的主管、同事、合作夥伴們，\n每個人的VS Code都給它裝上那麼一套，\n世界肯定會變更美好的！\n不然等到像筆者接手前人的Code的時候，看著滿坑滿谷的問題，\n才後悔莫及的時候，已經來不及囉 T_T\n以上，分享給大家~\n","date":"2023-08-05T00:00:00+08:00","permalink":"https://learnwithdesolve.netlify.app/post/code-spell-checker/","title":"震驚！他終於不再眼花打錯字了，只因做了這件事 - Code Spell Checker"},{"content":"git rebase -i 以及預設編輯器修改方法\n在git的常見指令當中，git rebase是一個工作時常用的到的東西；\n尤其當本地端要和遠端的server同步的時候，\n我們常常會下：\n1 git pull --rebase 該指令原則上會將遠端的新commit(s)下載下來，\n擺在本地端的HEAD上，最後再將本地端的commit(s)重新銜接上去；\n在這個過程中，pull下來的分支被當成主幹，而本地端多出來的那些commit(s)則被視作要銜接上去的分支。\n問題來了，如果我們在工作時共同開發的時候，\n也許某些功能彼此的用途或目的比較一致，\n我們會希望commits的順序是A -\u0026gt; D-\u0026gt; B -\u0026gt; C，\n但本地目前是A -\u0026gt; C，遠端目前是D -\u0026gt; B，\n如果進行pull rebase沒有發生衝突的話，\n會變成D-\u0026gt;B-\u0026gt;A-\u0026gt;C，顯然和我們想要的不同。\n這個時候，一個比較簡單的方法是使用git rebase -i [commit-id]。\n筆者使用自己之前練題放上github的repository當作範例：\n假定我想要調整0148和0238的commit順序的話，\n可以這麼下：\n1 git rebase -i 971725c 這意義代表以971725c為基準(這個基底是不能調的!)，\n以互動的模式來幫我調整後面的commits，\n接著只要在文字編輯器上將想調整的commit直接調順序即可。\n當然，如果想要直接砍掉某個commit，也可以將pick改成drop，\n它就會直接消失囉！（慎用XD）\n另外一方面，如果是VSCode的話，可以考慮安裝GitLens的Extension，\n操作起來會更直覺：\ngit rebase -i在有裝GitLens的狀況下可以直接拖拉\n最後，有安裝VSCode的話，\n預設編輯器應該會變成使用VSCode開啟。\n(不管是rebase還是做commit都是)\n但如果預設不是的話，\n可以使用以下方式修改：\n(請特別注意，由於VS Code的路徑內含空格 ，而且需要下**\u0026ndash;wait** 等待，\n所以外側要下雙引號 ，然後內側路徑要用單引號括起來 ，\n才不會出現路徑錯誤的問題。)\n1 git config --global core.editor \u0026#34;\u0026#39;C:\\Users\\user\\AppData\\Local\\Programs\\Microsoft VS Code\\bin\\code\u0026#39; --wait\u0026#34; 以上提供大家參考~\n","date":"2023-06-13T00:00:00+08:00","permalink":"https://learnwithdesolve.netlify.app/post/git-rebase-i/","title":"短心得-git rebase -i"},{"content":"Categories: Graph/Union Find Level: Medium** Introduction: (Basic + Advanced + Interview Edition) Learning Algorithms from LeetCode + Interview Success Guide (Regular price: 3591 NTD, Discounted price until 2023/06/30 23:59)\nhttps://hiskio.com/bundles/eCP23B397?s=tc\n(Regular price: 3990 NTD, Valid for a long term) https://bit.ly/lc2022all\nPlease help me click on the “SHOW EMBED” below and give it 5 likes~ If you like it, you can also give me a round of applause~ (Liking doesn’t cost anything, thank you for supporting my writing~)\nQuestion There are n cities. Some of them are connected, while some are not. If city a is connected directly with city b, and city b is connected directly with city c, then city a is connected indirectly with city c.\nA province is a group of directly or indirectly connected cities and no other cities outside of the group.\nYou are given an n x n matrix isConnected where isConnected[i][j] = 1 if the ith city and the jth city are directly connected, and isConnected[i][j] = 0 otherwise.\nReturn the total number of *provinces *.\nExample 1 1 2 Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]] Output: 2 Example 2 1 2 Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]] Output: 3 Constraints 1 \u0026lt;= n \u0026lt;= 200 n == isConnected.length n == isConnected[i].length isConnected[i][j] is 1 or 0. isConnected[i][i] == 1 isConnected[i][j] == isConnected[j][i] Analysis/Approach:\nThere are n cities, some of which are directly connected to each other, while others are not. If city a is directly connected to city b, and city b is directly connected to city c, then city a is indirectly connected to city c. (That’s a lot of unnecessary words LOL)\nA province is a group of cities that are directly or indirectly connected, and there are no other cities in this group. (In other words, if you can walk from x to y, they are considered part of the same province).\nGiven an n x n matrix isConnected, where isConnected[i][j] = 1 means the ith city is directly connected to the jth city, and isConnected[i][j] = 0 means they are not directly connected, return the total number of provinces.\nWe have discussed many concepts related to graphs in Article 115 and the previous article. Today, let’s take a closer look at the usage of Union Find.\nSince the variable name “isConnected” is too long, we will use “edges” to refer to it for convenience.\nFirst, we need to find the number of provinces, which is another typical scenario where Union Find can be used. However, as we mentioned before, if we only trace back along the edges to find the root, the find operation for a single point can potentially take O(n) time. Therefore, we need to simplify the process by performing ** path compression** during the ** union** operation.\nIn the union operation, instead of arbitrary assignment as before, we can now choose to check which root has a higher rank and merge the group with the lower rank into the group with the higher rank. The root of the group with the lower rank should be set as the root of the group with the higher rank. This way, during the union process, since we always merge the smaller group into the larger one, it will be less likely to create long chains of connections. This technique is called path compression .\nTherefore, our implementation of the find operation and union operation will look like this:\nfind(root, i) :\nInitialize r as root[i] If r and root[r] are not equal (indicating that we haven’t reached the node that is the root), enter the loop: Set root[r] as root[root[r]] Set r as root[r] (move up one level and continue the evaluation) After the loop (steps 2–4) ends, set root[i] as r, indicating that the topmost leader of node i is r. union(root, rank, x, y):\nApply the find operation to x and y separately to obtain their respective roots rx and ry . If rx and ry are the same , it means they are already in the same group, so return false . If they are different, compare the ranks rank[rx] and rank[ry]: If rank[rx] ≥ rank[ry] , increase rank[rx] by rank[ry] and set root[ry] as rx . Otherwise, if rank[rx] \u0026lt; rank[ry] , increase rank[ry] by rank[rx] and set root[rx] as ry . After initializing root and rank (from 1 to n-1 and ** 1**), we can use a nested loop to call the union operation for the pairs of cities that are connected by edges. Finally, we iterate through each node and perform the find operation to determine the ** unique roots** and store them in a HashSet. The answer can be obtained by checking the size of the HashSet.\nHere is an implementation in Java:\nJava We can use Arrays.fill() to set values in Java. Since we don’t specifically need the true/false return value for the union operation, we can change its return type to void and modify the necessary parts accordingly. Finally, we can use a HashSet to record the answers, iterate through i, call find(), and add the results. The final answer can be obtained by checking the size of the HashSet.\nNotice that you could start j from i+1 rather than 0.\nPython In Python, the implementation is similar except for the use of sub-functions.\nPotential Interview Questions:\n“What are the time and space complexities?”\n(O(n²)/O(n), as even with path compression, traversing all edges still takes O(n²) time, and the space complexity only needs to consider the space for recording roots and ranks.)\nSimilar and Extended Topics: 0684. Redundant Connection (Medium)\nSpecial thanks to suggestions/corrections from viewers:\n(Welcome to provide feedback to help with corrections~)\nLearn Algorithms from LeetCode — See you next time!\nWant to see more problems? Feel free to check out Article 0 for the topic you want!\nAlso, follow our Facebook page for notifications on new articles:\nLearn with Desolve ","date":"2023-06-06T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces-en/","title":"Learn Algorithms from LeetCode-120 (0547. Number of Provinces)"},{"content":"Categories: Graph/Union Find Level: Medium 寫在前面 (基礎+進階+面試篇)從 LeetCode 學演算法 + 面試成功指南**\n(3591元 特價中: 2023/06/30 23:59後截止) https://hiskio.com/bundles/eCP23B397?s=tc\n(3990元 長期有效) https://bit.ly/lc2022all\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/lc2022adv\nQuestion There are n cities. Some of them are connected, while some are not. If city a is connected directly with city b, and city b is connected directly with city c, then city a is connected indirectly with city c.\nA province is a group of directly or indirectly connected cities and no other cities outside of the group.\nYou are given an n x n matrix isConnected where isConnected[i][j] = 1 if the ith city and the jth city are directly connected, and isConnected[i][j] = 0 otherwise.\nReturn the total number of *provinces *.\nExample 1 1 2 Input: isConnected = [[1,1,0],[1,1,0],[0,0,1]] Output: 2 Example 2 1 2 Input: isConnected = [[1,0,0],[0,1,0],[0,0,1]] Output: 3 Constraints 1 \u0026lt;= n \u0026lt;= 200 n == isConnected.length n == isConnected[i].length isConnected[i][j] is 1 or 0. isConnected[i][i] == 1 isConnected[i][j] == isConnected[j][i] 分析/解題 有n個城市，其中一些城市彼此相連，而另一些則沒有。\n如果城市a與城市b直接相連，並且城市b與城市c直接相連，\n那麼城市a與城市c之間間接相連。(OS: 好廢話XD)\n一個省(province)是一組直接或間接相連的城市，\n且該群組中沒有其他的城市。\n(也就是直要可以從x走到y，它們就視為相同省)\n給定一個n x n的矩陣isConnected，\n其中isConnected[i][j] = 1表示第i個城市和第j個城市直接相連，isConnected[i][j] = 0則表示它們不直接相連，回傳省的總數量。\n我們已經在第115篇 以及上一篇中提到了很多Graph的概念，\n今天再來仔細一點探討Union Find的用法。\n由於isConnected太長了，我們底下還是直接使用edges來稱呼比較簡便。\n首先看到了要找provinces的組數，\n顯然又是一個很典型能使用Union Find的場合；\n但先前我們提到過，如果只是一路沿著edge往回trace老大的話，\n對於單一點的find有可能達到O(n)，\n因此我們需要做一些簡化：在union 的合併時，\n就盡可能地先行收斂 。那麼我們應該怎麼做呢？\n我們這邊定義一個串列叫做rank，\n用以表達每個節點往上對到的root所含有的節點總數。\n那麼在合併的時候，有別於先前的任意指定，\n我們這次可以選擇先檢查誰的rank大，\n接著人多欺負人少 \u0026hellip;\u0026hellip;不對，是rank大的合併掉rank小 的群組；\nrank小的群組的root要設定為rank大的群組的root。\n這麼一來，在合併的過程中，由於一直是大的合併小的，\n相對而言會較不容易將union的連接拉太多層，\n這個手法我們稱之為路徑壓縮(path compression) 。\n因此，我們的find的寫法和union的寫法會像這樣：\nfind(root, i):\n先取到r = root[i] 如果r和root[r]不相等(代表還沒走到自己是root(老大)的節點)進行迴圈: 將root[root[r]]的值塞給root[r] 令r = root[r] (來到上面一層，繼續準備判斷) 在2~4的迴圈結束後，直接令root[i] = r，\n標明節點i的最上面的老大是r。 union(root, rank, x, y):\n對x, y分別使用find，取得各自的root rx, ry 如果rx和ry相同 ，代表已經是同一組了，直接回傳false 如果不同，則看rank[rx]和rank[ry]的關係，\nrank[rx] ≥ rank[ry] 的話，就將rank[rx]遞增rank[ry] ，\n並且令root[ry] = rx ；\n反之，若rank[rx] \u0026lt; rank[ry] ，則將rank[ry]遞增rank[rx] ，\n並且令root[rx] = ry 。 那麼，剩下來我們只需要做完對root和rank的初始化(1~n-1 跟1 )\n剩下就是雙層迴圈 對有edge 的兩點呼叫union ，\n最後對於每個節點確認它們不重複的root有哪些 即可。\n依此，寫成程式碼如下：\nJava Java的部分一樣可以用Arrays.fill() 來設定定值，\n同時因為我們union其實沒特別用到true/false的需求，\n可以設定為void，直接將對應該改的東西改一改，\n並直接return即可。\n同時，在記錄答案時，我們可以使用HashSet，\n在最後對i做遍歷並逐個進行find()，並加到當中，\n最後檢查res.size()即可得到我們要的答案。\n另外可以留意的是，雙重迴圈的union(i, j)因為沒有方向性的關係，\n第二層的j可以從i+1開始 就好，不需要從0開始。\nPython Python的部分除了改成用子函式以外，\n其餘則大同小異。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n( O(n²)/O(n)，因為即便有經過path的壓縮，遍歷所有edge仍然要O(n²)，\n空間的部分則是只需要考慮記錄root和rank的空間)\n相似及延伸 Redundant Connection (Medium) Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/lc2022base\n","date":"2023-06-06T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-120-0547-number-of-provinces/","title":"從LeetCode學演算法-120 (0547. Number of Provinces)"},{"content":"Categories: Graph/DFS Level: Medium Introduction: (Basic + Advanced + Interview Edition) Learning Algorithms from LeetCode + Interview Success Guide (Regular price: 3591 NTD, Discounted price until 2023/06/30 23:59)\nhttps://hiskio.com/bundles/eCP23B397?s=tc\n(Regular price: 3990 NTD, Valid for a long term) https://bit.ly/lc2022all\nPlease help me click on the “SHOW EMBED” below and give it 5 likes~ If you like it, you can also give me a round of applause~ (Liking doesn’t cost anything, thank you for supporting my writing~)\nQuestion Given a directed acyclic graph (DAG ) of n nodes labeled from 0 to n - 1, find all possible paths from node 0 to node n - 1 and return them in any order .\nThe graph is given as follows: graph[i] is a list of all nodes you can visit from node i (i.e., there is a directed edge from node i to node graph[i][j]).\nExample 1 1 2 3 Input: graph = [[1,2],[3],[3],[]] Output: [[0,1,3],[0,2,3]] Explanation: There are two paths: 0 -\u0026gt; 1 -\u0026gt; 3 and 0 -\u0026gt; 2 -\u0026gt; 3. Example 2 1 2 Input: graph = [[4,3,1],[3,2,4],[3],[4],[]] Output: [[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]] Constraints n == graph.length 2 \u0026lt;= n \u0026lt;= 15 0 \u0026lt;= graph[i][j] \u0026lt; n graph[i][j] != i (i.e., there will be no self-loops). All the elements of graph[i] are unique . The input graph is guaranteed to be a ** DAG**. Analysis/Approach: Given a directed acyclic graph (DAG) with n nodes labeled from 0 to n — 1, we need to find all possible paths from node 0 to node n — 1 and return them in any order.\nThe graph is represented in the following way: graph[i] represents a list of nodes that can be visited from node i. (Directly visiting means there is a directed edge from node i to graph[i][j].)\nLet’s talk about graphs in this article. As mentioned in Article 115 , in a graph with directionality (a -\u0026gt; b and b -\u0026gt; a are considered different edges), it is called a directed graph . If a directed graph does not have cycles (a cycle means there is a path starting from a point a and ending at a, forming a loop), it is called a ** directed acyclic graph**, abbreviated as ** DAG**.\nSince the problem guarantees that the graph is a DAG, it is impossible to return to the same node from any starting node, and it is also impossible to backtrack, meaning there are no duplicates in the paths.\nLet’s try to outline the steps to find the paths:\nStart from i = 0 and examine the connections in graph[i] . For example, in Example 1, node 0 connects to nodes 1 and 2, so there are two paths: 0-\u0026gt;1 and 0-\u0026gt;2. For the path 0-\u0026gt;1, we need to check the connections from node 1. It is connected only to node 3, which happens to be the last node in this graph. Therefore, we have found one valid path: 0-\u0026gt;1-\u0026gt;3. Similarly, for the path 0-\u0026gt;2, it only has one connection: 0-\u0026gt;2-\u0026gt;3. Therefore, for this problem, we can use DFS starting from node 0 and recursively explore the graph. Along the way, we need to keep track of the current path at each step. Whenever we reach the destination node, we add that path to the result list. Finally, we return the entire result.\nThe steps for solving this problem are as follows:\nInitialize a list called res to store the resulting paths. Define a function dfs with parameters (i, path), where i is the current node and path is the path taken to reach node i (including i). Inside the function, first check if i is equal to the length of the graph minus 1. If true, it means we have reached node n-1, and this path is one of the answers. Add it to res. If the previous check fails, it means we need to continue exploring. Iterate through the next node nxt in graph[i] and recursively call dfs with nxt and the updated path (path + nxt). Start the recursion by calling dfs with (0, [0]). After Step 5 is completed, return res. Based on this, the code can be written as follows:\nJava In Java, the res list is obviously two-dimensional, so we can use an ArrayList to store the paths. In the helper (or dfs) function, since we cannot use nested functions like in Python, we need to include graph, i, path, and res as parameters. Since the path is reused in each recursion, we use backtracking to keep track of the path. In each call to the helper function, we add the current node i to the path (path.add(i)), and remember to remove it (path.remove(path.size() — 1)) before exiting.\nOne important thing to note is that when adding paths to res, ArrayList is a reference-based structure, meaning it doesn’t create a copy of the path. Therefore, when adding to res, we need to use new ArrayList(path) to create a copy. Otherwise, when we backtrack, it will affect the results in res.\nPython In Python, we can use nested functions, so we don’t need to include res and graph as parameters, which makes the code cleaner. When performing dfs, we can directly create a new list using path + [nxt] . This way, we don’t need to deal with backtracking, and we can directly append path to res without making a separate copy. (Since path + [nxt] creates a new list already.)\nPotential Interview Questions:\n“What are the time and space complexities?” (O(V * 2^V), as each path has a maximum complexity of O(V), and there can be up to O(2^V) paths.)\nSimilar and Extended Topics:\nSpecial thanks to suggestions/corrections from viewers:\n(Welcome to provide feedback to help with corrections~)\nLearn Algorithms from LeetCode — See you next time!\nWant to see more problems? Feel free to check out Article 0 for the topic you want!\nAlso, follow our Facebook page for notifications on new articles:\nLearn with Desolve ","date":"2023-06-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-119-0797-all-paths-from-source-to-target-medium/","title":"Learn Algorithms from LeetCode - 119 (0797. All Paths From Source to Target(Medium))"},{"content":"0797. All Paths From Source to Target (Medium)\n寫在前面 (基礎+進階+面試篇)從 LeetCode 學演算法 + 面試成功指南**\n(3591元 特價中: 2023/06/30 23:59後截止) https://hiskio.com/bundles/eCP23B397?s=tc\n(3990元 長期有效) https://bit.ly/lc2022all\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/lc2022adv\nQuestion Given a directed acyclic graph (DAG ) of n nodes labeled from 0 to n - 1, find all possible paths from node 0 to node n - 1 and return them in any order .\nThe graph is given as follows: graph[i] is a list of all nodes you can visit from node i (i.e., there is a directed edge from node i to node graph[i][j]).\nExample 1 1 2 3 Input: graph = [[1,2],[3],[3],[]] Output: [[0,1,3],[0,2,3]] Explanation: There are two paths: 0 -\u0026gt; 1 -\u0026gt; 3 and 0 -\u0026gt; 2 -\u0026gt; 3. Example 2 1 2 Input: graph = [[4,3,1],[3,2,4],[3],[4],[]] Output: [[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]] Constraints n == graph.length 2 \u0026lt;= n \u0026lt;= 15 0 \u0026lt;= graph[i][j] \u0026lt; n graph[i][j] != i (i.e., there will be no self-loops). All the elements of graph[i] are unique . The input graph is guaranteed to be a ** DAG**. 分析/解題 給定一個有向無環圖(directed acyclic graph, DAG)，\n當中有n個nodes，分別被標記為0到n - 1，\n找出所有可以從node 0走到node n - 1的路徑，\n並且以任意排序的方式回傳。\ngraph的給定方式如以下敘述：\ngraph[i] 代表所有從node i可以造訪的nodes的串列。\n(直接造訪，也就是指node i到graph[i][j]之間會有一個有方向的edge(邊))\n我們這篇再來談談graph。\n之前我們在第115篇 提到過，\n在graph當中，有方向性的(a -\u0026gt; b和 b -\u0026gt; a被視為不一樣的邊)圖，\n被稱為有向圖(directed graph) ；而如果有向圖中，\n不存在環(cycle，也就是圖上存在一個點a，從點a出發，\n有一條路徑可以再走回點a)的話，\n則稱為有向無環圖 ，簡寫為DAG。\n既然題目保證圖是DAG，那麼我們從任何一個點出發，\n都保證不可能會再回到同一個點，同時也不可能走回頭路，\n也就不存在重複的可能。\n讓我們嘗試列出找尋路徑的步驟：\n首先從i = 0開始，觀察graph[i] 的連接，\n例如像Example 1中0就連到1跟2，\n也就是說會有 0-\u0026gt;1 跟0-\u0026gt;2 這兩條路徑 對於0-\u0026gt;1而言，接下來我們要看1的連接，\n發現它只連接到3，而3剛好是這個graph的最後一個節點，\n因此得到其中一個有效的路徑是0-\u0026gt;1-\u0026gt;3。 同理，對於0-\u0026gt;2而言也剛好只有0-\u0026gt;2-\u0026gt;3。 因此對於這題，我們可以使用DFS從node 0做遞迴往下，\n中途要記住每一步當下走過的路徑，只要有走到終點的路徑，\n就將其放到答案的列表裡，最後再將整個結果回傳即可。\n列出解題步驟如下：\n初始化一個串列res，用以存放結果的路徑 定義一個dfs的函式，輸入為**(i, path)** ，\n當中i為當前走到的node，path為走到node i時經過的路徑(包含i )。 在函式中，首先檢查i是否和graph的長度-1相等，\n如是，代表走到node n-1 的位置了，\n該路徑是答案之一，將其加到res上 。 若3的檢查解果為否，代表要繼續往下走，\n迴圈遍歷graph[i] 中的下一個node nxt，\n並呼叫dfs，將node nxt 和新的path(path加上nxt )代入遞迴。 將**(0, [0])** 代入dfs中開始遞迴。 完成5後，將res回傳即可。 依此，寫成程式碼如下：\nJava 在Java的部分，我們的res顯然是二維的，\n因此我們可以使用ArrayList來放入其中。\n在helper(或dfs)中，因為不能像Python使用子函式，\n這邊參數就需要graph、i、path、res；\n又因為path是反覆遞迴下去利用的，\n我們在記錄時使用backtracking的方式，\n選擇在每次進入helper函式時，將path給加上當前走到的node i，\n在離開時，則要記得將其收回，因此分別會在頭尾做path.add(i) ，\n以及path.remove(path.size()-1) 。\n其他要留意的部分是，由於在放到res的時候，\n對於ArrayList來說是一個指向性質的放置，並不會直接複製一份path，\n所以在res.add的時候，必須要使用new ArrayList(path) 的手法，\n將path複製一份出來才行；不然後面我們在backtracking的時候，\n就會同步影響到res的結果喲！\nPython 在Python的部分由於可以使用子函式，\n我們可以不需要再將res跟graph加到參數，\n就會簡潔一點；\n同時，在進行dfs的時候，我們這邊改成用\npath + [nxt] 的方式，就會直接形成一個新的list。\n這樣一來，path的部分就不需要再回頭處理backtracking的問題，\n同時res也可以直接進行append(path)，不需要另行複製。\n(因為前面path + [nxt]時已經複製完path並形成一個新的list了)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(V * 2^V)，因為單一條最多是O(V)，最多可能有O(2^V)條)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/lc2022base\n","date":"2023-06-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-119-graph-2-dfs-21/","title":"從LeetCode學演算法 - 119 Graph (2) / DFS (21)"},{"content":"該來個改版了! 話說筆者心血來潮搜尋了一下自己的文章，\n發現Medium上按照現有的格式，\n其實subtitle(副標題)的部分根本不會進入到搜尋的Title中，\n這點感覺對於讀者搜尋很不方便XD\n(雖然第0篇都有放連結，老讀者懂得都懂)\n考量過後，將格式調整如下：\nTitlte: 從LeetCode學演算法-120 (0547. Number of Provinces)\nSubtitle: Categories: Graph/Union Find, Level: Medium\n調整過後，讀者可以清晰看見該篇的題號，\n而subtitle會列出題目的種類和難度(就不列是種類的第幾篇了，因為在Medium中沒辦法直接連結搜尋相同個作者的特定tag)。\n另外，因應這個國際化的社會(?)，\n接下來的每一篇文章都會提供英文版本，\n英文版本只會往英語系的Python或Coding相關的FB社團發文 ，\n同時不會列到第0篇文章。\n以上調整，不溯及既往，並且從本篇文章起即刻生效，\n感謝大家的理解與支持XD!\n","date":"2023-06-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-format-change/","title":"從LeetCode學演算法 — 格式變更"},{"content":"0934. Shortest Bridge (Medium)\n寫在前面 (基礎+進階+面試篇)從 LeetCode 學演算法 + 面試成功指南**\n(3591元 特價中: 2023/06/30 23:59後截止) https://hiskio.com/bundles/eCP23B397?s=tc\n(3990元 長期有效) https://bit.ly/lc2022all\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/lc2022adv\nQuestion You are given an n x n binary matrix grid where 1 represents land and 0 represents water.\nAn island is a 4-directionally connected group of 1\u0026rsquo;s not connected to any other 1\u0026rsquo;s. There are ** exactly two islands** in grid.\nYou may change 0\u0026rsquo;s to 1\u0026rsquo;s to connect the two islands to form one island .\nReturn the smallest number of 0\u0026rsquo;s you must flip to connect the two islands.\nExample 1 1 2 Input: grid = [[0,1],[1,0]] Output: 1 Example 2 1 2 Input: grid = [[0,1,0],[0,0,0],[0,0,1]] Output: 2 Example 3 1 2 Input: grid = [[1,1,1,1,1],[1,0,0,0,1],[1,0,1,0,1],[1,0,0,0,1],[1,1,1,1,1]] Output: 1 Constraints n == grid.length == grid[i].length 2 \u0026lt;= n \u0026lt;= 100 grid[i][j] is either 0 or 1. There are exactly two islands in grid. 分析/解題 給定一個 n x n 的 binary 矩陣 grid，當中 1 代表陸地，0 代表水。\n一個 island (島嶼) 的定義是指一組在四個方向和其他的1相連的群組，\n且沒有再和其他1相連(也就是中間經過1的都算是同一塊島嶼)。\n在 grid 中恰好兩塊島嶼。\n你可以將0變成1用來連接兩塊島嶼，以形成一塊島嶼，\n試回傳要翻轉0到1使得兩塊島嶼連接的最少所需的數目。\n好久不見了！\n這題算是比較特別的題目，因為比較好的解法會是DFS和BFS都用上，\n一個用來找到第一整塊島嶼，另一個用來連接。\n就題目而言，從0翻到1，其實就是一個搭橋的概念，\n單就grid上考慮，那麼我們肯定是從兩個島距離最近的點來搭會最好，\n但怎麼知道哪兩個點距離最近呢？\n如果兩塊島嶼都是完整矩形的話，\n或許我們還可以從邊與邊的垂直距離來做文章，\n也還有一些比較簡單的計算方法(比如下圖取兩點的垂直+水平距離)\n(如果水平或垂直方向有重合的話則只計di或dj)\n取最近的兩點垂直距離+水平距離(也有可能其中一個方向不用計)\n但.…..它們並不一定是矩形XD\u0026quot;\n所以有可能出現像這樣子的狀況，然後旁邊可能全是不規則形狀，\n無法用矩形算完：\n看圖會知道算哪個點，但究竟要娶幾個點才能算呢？\n所以既然無法知道兩塊島嶼長什麼樣子，也不知道規不規則，\n那只能回到笨方法了：\n先找到其中一塊島嶼，再從這塊島嶼的邊界往外找(搭橋)。\n我們嘗試來列出解題步驟：\n取得grid的長寬r, c (沒錯，這題其實就算不是正方形的grid應該也可以做) 先遍歷找到grid上任意一個值為1的點(i, j)，\n這個點肯定是其中一塊島上的陸地 從(i, j)開始進行DFS往四方探索陸地，同時將所有途經的陸地標為2\n(標成2的意義是為了可以和另一塊島嶼的陸地區分開來)； 在步驟3的探索中，如果碰到0時，\n把和0相接的陸地座標記到一個queue 裡面\n(代表這是第一塊陸地的臨水的邊界) 完成3, 4後，我們會得到一個queue，當中全是第一個島嶼的臨水的邊界 ，\n作為我們搭橋的出發點，這裡設定我們要求的答案step為0 當queue中有值的時候，持續操作以下步驟： 取得當前queue的長度L，進行一個L次的迴圈： 從queue中取出一組座標(i, j) 從(i, j)往四個方向看，如果沒有超出grid的話，檢查以下可能：\n9-1. 如果值是1，則代表成功接通，這時候直接回傳step作為答案即可\n9-2. 如果值是0，則代表繼續搭橋，將新座標放到queue當中，\n並且將這個位置的值標為-1(代表已經走過了) 步驟7的迴圈結束後，將step遞增1，接下來回到6檢查是否要繼續 雖然題目設定上一直都是找得到解答的，但如果找不到解答的話，\n離開步驟6的迴圈後，則應該要回傳-1，表示找不到能搭建的橋\n(也就是grid可能被給成只有一塊土地) 在上面的解題步驟中，步驟34是DFS ，\n目的在於要找到第一塊島嶼，記錄邊界，\n並將其值改動成2，用來跟第二塊島嶼區別；\n而步驟610則是BFS ，\n用來從邊界開始往外嘗試搭橋，\n因此我們可以在找到連接到第二塊島嶼的時候，\n因為一次是每種可能都走一步的特性，確定最小所需的步數，\n也就是我們所要求的答案。\n依此，寫成程式碼如下。\nPython 為求簡單，這邊我們直接將grid改名為A，避免寫太多次。\n我們可以利用簡單的dirs串列來標定四個方向，\n從而縮減每次寫+1和-1的部分，\n這個小技巧應該常碰到類似題目的同學大多看過。\n另外，我們使用了一個set start，用來幫我們自動化簡加入的座標，\n因為我們有可能加同樣的座標到queue裡面，\n使用set可以有效避免這一點。\n同時請留意到當A[x][y] == 0的時候，要加入的是(i, j)歐!\n因為我們加入的是陸地的邊界(1)，而不是水(0)，\n同理，後面起始的時候因為是從陸地開始起算，\n所以step是從0而非從1開始。\nJava Java的部分則會稍微麻煩一點，\n這邊將大多數的東西放在class variable的位置，\n可以有效避免需要大量的傳遞參數；\nQueue的部份我們使用ArrayDeque來處理，\n那麼對應的取出和放入就會變成poll()和offer()。\n(注意每次放入的時候都要產生一個新的int[]來放入)\n另一方面，由於HashSet在Java當中用起來比較沒有像Python這麼彈性，\n這邊採用visited的方式來處理，\n我們將已經放入過q的(i, j)在visited中設定為true，\n再每次檢查，即可得到相同效果。\n此外，由於Java不接受回傳一個沒有回傳值的function，\n因此27和28行會分成兩行來寫，先進行dfs完，再呼叫return。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n²)/O(n²)，在長和寬均為n的狀況下，最多也就是掃完整個grid)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/lc2022base\n","date":"2023-05-28T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-118-dfs-20-bfs-5-queue-6/","title":"從LeetCode學演算法 - 118 DFS (20) /BFS (5) / Queue (6)"},{"content":"下周二(6/7)開始有從LeetCode學演算法全套組合的優惠~\nhttps://hiskio.com/bundles/eMF22B397?s=tc\n全套組合特惠價3591元！有興趣的朋友可以參考XD\n","date":"2022-06-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-you-hui-zi-xun/","title":"從LeetCode學演算法 - 優惠資訊"},{"content":"0941. Valid Mountain Array (Easy)\n寫在前面 2022/03/09: 配合官方修改格式，各項優惠連結3/14之後會失效，\n這邊更新新版的連結給大家~**\n從 LeetCode 學演算法｜完整解題技巧 + 面試成功指南： https://bit.ly/lc2022all\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/lc2022adv\nQuestion Given an array of integers arr, return true if and only if it is a valid mountain array.\nRecall that arr is a mountain array if and only if:\narr.length \u0026gt;= 3 There exists some i with 0 \u0026lt; i \u0026lt; arr.length - 1 such that: arr[0] \u0026lt; arr[1] \u0026lt; ... \u0026lt; arr[i - 1] \u0026lt; arr[i] arr[i] \u0026gt; arr[i + 1] \u0026gt; ... \u0026gt; arr[arr.length - 1] Example 1 1 2 Input: arr = [2,1] Output: false Example 2 1 2 Input: arr = [3,5,5] Output: false Example 3 1 2 Input: arr = [0,3,2,1] Output: true Constraints 1 \u0026lt;= arr.length \u0026lt;= 104 0 \u0026lt;= arr[i] \u0026lt;= 104 分析/解題 給定一個整數陣列arr，若且唯若它是一個合格的mountain array時，\n回傳true(否則回傳false)。\nmountain array的條件要符合以下幾點:\narr長≥3 存在i，0\u0026lt;i\u0026lt;arr.length-1使得:\narr[0] \u0026lt; arr[1] \u0026lt; … \u0026lt; arr[i-1] \u0026lt; arr[i] 且\narr[i] \u0026gt; arr[i + 1] \u0026gt; … \u0026gt; arr[arr.length-1] 為了避免大家隔太久沒有練習(我也是)，而且快過年了不要讓大家太燒腦，\n今天我們就介紹簡單一點的題目就好XD！\n在LeetCode的題型中，有一些簡單的題目的規格，\n會呈現為只要題目讀得懂，按要求做完就會答對的形式，\n本題就是相當明確的例子之一。\n我們來看看要求：mountain array\n前面必須要嚴格遞增 ，後面必須要嚴格遞減 ，\n中間的arr[i]值為整個陣列的最高點。\n同時限制了長度必須大於等於3，也就是上下坡都必然存在。\n那麼解題方式就很明確了：\n先檢查長度是否≥3，且arr[0]是否小於arr[1]\n(一定要檢查，因為我們希望上下坡都存在 ) 從陣列的開頭開始以i計數，往後沿途比較arr[i]跟arr[i+1]，\n一路遞增到遞減轉折出現為止(也就是第一個arr[i] \u0026gt;arr[i+1]) 在2當中如果出現前後相等 的狀況可直接回傳False，\n同時，如果還沒下坡就已經走到底(i + 1 == arr.length) 的話，\n也要回傳False 。 沿路下坡，一路走到尾端 如果沿途均符合的話(會走到i + 1 == arr.length )，則回傳true；\n如果沿途變平或上坡的話，需在4的位置提早停下，\n這樣子就可以藉由是否走到尾端這點來判斷要回傳true或false。 依此，寫成程式碼如下。\nJava 可以看到我們在上坡的時候使用迴圈，\n每次檢查就做兩件事來確認是否離開迴圈：\n是不是走到底了 -\u0026gt; 走到底的話就不對了，因為還沒下坡 是不是有在走上坡 -\u0026gt; 變平的話不對，只有變下坡可以接受 而下坡時只有一路下坡走到底可以被接受。\nPython Python寫法基本上一致，所以說這題不難，對吧XD！\n關鍵還是在於是否能確切釐清題目要求，\n例如如果沒有寫A[0] ≥ A[1]的檢查的話，\n就有可能碰到只有下坡的陣列，從而讓檢查結果出問題喲！\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，這題最多需要掃完整個陣列，\n且我們只有多使用一個i的變數。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/lc2022base\n","date":"2022-01-30T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-117-array-17/","title":"從LeetCode學演算法 - 117 Array (17)"},{"content":"還在等折價嗎？這不就來了嗎XD\n即日起開始有配合HiSKIO官方的折價活動，\n整包課程活動價只要3591元，\n新的一年，投資自己練功，為自己加值戰力！\n有興趣的朋友可以參考看看~\nhttps://hiskio.com/packages/1AyXD1oyQ\n由於事情比較多的關係，一直打不起精神寫新的文章，真是不好意思QQ\n雜談一下，這段時間以來，大體上就是在了解加密貨幣相關的基本知識(真的很基本的那種)，以及換工作(大誤)，還有做之前鐵人賽得名的從零開始學Python，在博碩文化出版為初學 Python 的第一本書 : 從基本語法到模組應用 ，在天瓏書局或博客來都有販售，當然也有電子書版本，打完折應該都算打到骨折啦，同時也邀請到了葉丙成老師(對，是各位想的那位葉丙成) 做封面推薦，以及HiSKIO的創辦人Adam 來寫序。\n這邊要說一點實話，其實完書後我是覺得還存在一些不足的，儘管我某種程度上很嚴苛地對待第一本出版的著作，但有限的時間內，其實只允許我盡可能將錯字和排版錯誤等問題排除，以及程式碼不要有錯漏的問題，還有增加一些基本的習題，希望能協助新手每個環節都能練習到基本Python使用的方法和觀念。沒記錯的話，跟線上的文章差異應該僅有幾個小節的新增，而沒有大幅度的變化。\n所以如果你問我說：「我想支持你，買一本你的書怎麼樣？」的時候，我會很感激，然後拜託你買課我會賺比較多XD\n當然，畢竟是第一本書，所以真的願意花錢購買支持的讀者，我也是真的相當感謝，希望額外的修改以及適當的排版能幫助你/妳能更好的吸收。\n扣掉這些時間以外，其實說真的我就沒做些什麼事情了，前陣子家裡的貓突然心臟病發作併發肺炎，送醫院進氧氣倉，還沒等到我們轉診送去更專門救治毛小孩心臟病的專科就沒撐過來過世了。哭了一陣然後故作堅強好像是入了社會的人的基本技能，本來還想好結婚的時候一定要讓牠走紅毯當我們的花童的，沒想到牠等不到那天了。世事無常，變化太快，只能且行且珍惜。也請大家要保重身體，以及珍惜和身邊的人相處的時光，不要到最後才後悔。\n扯遠了，拉回來一下。\n總之，如果還沒有購買課的讀者，可以把握這次的優惠，\n相關的介紹會放在下面。之後會盡量找時間繼續寫文章，就再請大家多多支持囉。\n相關介紹：\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-12-08T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-za-tan-ji-cu-xiao-huo-dong-xd/","title":"從LeetCode學演算法 — 雜談及促銷活動XD！"},{"content":"靠免費的BNB跟BTC覺得好難累積嗎？機會來了！\n寫在前面： (基礎+進階+面試篇) 從 LeetCode 學演算法 + 面試成功指南**http://bit.ly/zeroclg\n新書(第一本，不曉得會不會是最後一本XD)開始販售啦！\n初學 Python 的第一本書 : 從基本語法到模組應用（iT邦幫忙鐵人賽系列書） https://www.tenlong.com.tw/products/9789864348503\n這本書主要是針對初學Python的入門讀者，希望能夠提供一個得以從零開始上手，又不會太過冗長的入門學習書。有興趣的話請多多支持！\n如果還沒有註冊的朋友，歡迎使用以下連結：\nhttps://betfury.io/?r=6068fc1e87d77c13a350ba20 介紹文章請參見A bitcoin Faucet網路加密貨幣賺錢-邪惡浣熊BetFury 。\n期望值計算器請參見A bitcoin Faucet-邪惡浣熊BetFury骰子期望值計算器 。\n常見的問題以及一些坑請參見A bitcoin Faucet-邪惡浣熊BetFury常見的坑和經驗法則 。\n邪惡浣熊2周年啦！我們先前介紹過如何領免費的BNB跟BTC，並且幫大家弄了計算期望值的方式，但如果不是有入金或者每天都很認真領的話，可能相對比較難累積到10BFG，從而開始進入每天分紅的階段。沒關係！最近的活動出來了一個新的免費BFG BOX！\n這是一個一系列的活動，詳細內容可以參見：\nhttps://betfury.io/bf-birthday-party\n但先不用管太多，還沒有註冊的朋友請先註冊，註冊後的朋友請點選日常領boxes的地方，就會看到新的BFG BOX了！領的規則也是跟一般的BNB/BTC盒子一樣，但目前觀察它似乎會有遞減的狀況，最初筆者領第一次是1.5 BFG，到目前一次已經下降到0.125 BFG一次了 ，不確定是按時間衰退，還是按照領取的次數衰退，但有得領就快領吧！\n如果是已經有一點累積的用戶，再把視窗往下拉會看到PRE-PARTY BOX 。\n這個是供使用者存入45 BFG，7天總共會給到47.625 BFG的盒子(月化25%)，在過程中會陸續配息，想到就可以按Withdraw，會將當前已經配息的本利給出來。(請留意存進去的部分，在取出來之前是不會參加Staking分紅的，所以不要到最後一天才領，領到的總額是固定的。 )\n機會難得，就算假設按目前為止固定到0.125 BFG，也是不無小補XD\n後續應該還有wager量到100 USDT的轉盤活動，\n有興趣的讀者也可以多多留意囉！\nMay the odds be ever in your favor!\n結尾容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-10-30T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/betfury.webp","permalink":"https://learnwithdesolve.netlify.app/post/a-bitcoin-faucet-betfury-second-birthday-party-free-bfg/","title":"A bitcoin Faucet-邪惡浣熊BetFury兩周年活動免費領BFG！"},{"content":"0814. Binary Tree Pruning (Medium)\n寫在前面 (基礎+進階+面試篇) 從 LeetCode 學演算法 + 面試成功指南**http://bit.ly/zeroclg\n新書(第一本，不曉得會不會是最後一本XD)開始預購啦！\n初學 Python 的第一本書 : 從基本語法到模組應用（iT邦幫忙鐵人賽系列書） https://www.tenlong.com.tw/products/9789864348503\n這本書主要是針對初學Python的入門讀者，希望能夠提供一個得以從零開始上手，又不會太過冗長的入門學習書。有興趣的話請多多支持！\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\nQuestion Given the root of a binary tree, return the same tree where every subtree (of the given tree) not containing a 1 has been removed.\nA subtree of a node node is node plus every node that is a descendant of node.\nExample 1 1 2 3 4 5 Input: root = [1,null,0,0,1] Output: [1,null,0,null,1] Explanation: Only the red nodes satisfy the property \u0026#34;every subtree not containing a 1\u0026#34;. The diagram on the right represents the answer. Example 2 1 2 Input: root = [1,0,1,0,0,0,1] Output: [1,null,1,null,1] Example 3 1 2 Input: root = [1,1,0,1,1,0,1,0] Output: [1,1,0,1,1,null,1] Constraints The number of nodes in the tree is in the range [1, 200]. Node.val is either 0 or 1. 分析/解題 給定一個二元樹的root，將同一棵樹中未含任何1的子樹均去除掉並回傳。\n(限制條件：樹的節點數目在1~200之間，且Node的值只會是0或1)\n如果我們看到範例的話，大致上可以理解要被去掉的部分就是包括自己以及其底下的所有節點值均為0的子樹，這樣才能保證剩下的符合題目要求的條件。\n因此，我們總體要做的就是檢查一棵樹的左子樹及右子樹狀況，\n然後分別決定左子樹/右子樹是否要被去掉，最後將當棵樹的總體狀況往上回傳，因此，設計一個子函數helper如下：\n傳入要檢查的節點n 如果n是空節點，則直接回傳0(因為這代表往下左右沒有其它節點了，也不用繼續檢查) 遞迴檢查左子樹(將n.left代入helper)，取得左子樹含1的節點數量為l 遞迴檢查右子樹(將n.right代入helper)，取得右子樹含1的節點數量為r 若l為0，表示無左子樹或左子樹均無節點值為1的節點，將n.left設為NIL 同理，若r為0，將n.right設為NIL 回傳l+r+n.val 在將root代入helper遞迴結束後，所有root的子樹應該都被清乾淨了，\n除了root自己以外，所以我們要檢查helper得到的最後的值，\n若為0的話，則最終我們應回傳NIL，否則應回傳root。\n依此，寫成程式碼如下：\nJava Java的部分使用三元運算子來處理最後的c，\n其實我們也可以將整個helper的函式使用True/False來處理，\n這樣中間的計算就要改成or來檢查是否至少存在一個節點值為1的節點。\nPython Python的部分使用子函數來簡單處理，其它的部分邏輯一樣。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，N為節點總數，總體的遞迴深度則和樹的高度一致。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-09-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-116-tree-21-dfs-19/","title":"從LeetCode學演算法 - 116 Tree (21) / DFS (19)"},{"content":"你以為機率夠小就不會遇到嗎?\n你以為機率夠小就不會碰到嗎?\n寫在前面： (基礎+進階+面試篇) 從 LeetCode 學演算法 + 面試成功指南**http://bit.ly/zeroclg\n新書(第一本，不曉得會不會是最後一本XD)開始預購啦！\n初學 Python 的第一本書 : 從基本語法到模組應用（iT邦幫忙鐵人賽系列書） https://www.tenlong.com.tw/products/9789864348503\n這本書主要是針對初學Python的入門讀者，希望能夠提供一個得以從零開始上手，又不會太過冗長的入門學習書。有興趣的話請多多支持！\n如果還沒有註冊的朋友，歡迎使用以下連結：\nhttps://betfury.io/?r=6068fc1e87d77c13a350ba20 介紹文章請參見A bitcoin Faucet網路加密貨幣賺錢-邪惡浣熊BetFury 。\n期望值計算器請參見A bitcoin Faucet-邪惡浣熊BetFury骰子期望值計算器 。\n下面提到的全都是經驗法則及筆者個人推論，讀者可以依照自身遇到的狀況進行調整，不構成任何入金或買賣邀約。\n入金以後再度出金會受到基本限制。\n這點很多人會不小心忽略，但當你已經確信自己能玩贏這個遊戲從而入金時，請謹慎考慮，最基本的限制是，入多少金，就必須要wager等額的量才能夠出金。詳細請見https://betfury.io/termsAndConditions.pdf 的 AML Policy ，按官方的說法，這是避免使用者拿這個入金出金的管道來洗錢或從事不法活動(謎：所以在這邊玩過一輪錢就算白了？)。這個限制是看幣種的，也就是今天如果你存入了100 USDT，你就必須要達到100USDT 的wager量，也就是總和下滿100 USDT，才能有提出100USDT的權利(下別的貨幣是沒有用的！存什麼貨幣，就看那個貨幣的wager量) 如果沒有先wager足額的量(X)被浣熊扒皮(O) 就無法領出\n筆者本來考量betfury的手續低廉(USDT甚至不需手續費)，所以最近一次轉錢時先轉到betfury，再轉出時就被卡了XD，這點請各位多加留意。\n但是，下注所獲得的利潤 或refer介紹獲得的利潤 不在此限。(因為已經有明確來源而不是入金)\n請教好自己的下線(如果你有的話)。 betfury的貨幣BFG目前已經上到biswap交易所 了，所以官方設定了一個鎖倉機制，剛挖出來的BFG(透過下注加密貨幣獲得)，將會被鎖在帳號上6個月(準確來說是180天) ，6個月後才能被提出來到如MetaMask錢包進行交易。取得解鎖的BFG的方式有幾種：\na. 上交易所前挖到的BFG 及上交易所後使用者買來放進betfury的BFG ，都算是解鎖的。\nb. 直接使用BFG下注可以增加解鎖的量。(如果不幸輸掉的BFG則會從鎖住的總量中扣掉)\nc. Cashback(賭輸返還) 和Referral(也就是下線) 給你的BFG都直接算是解鎖的。 所以，請珍惜自己的下線，別讓他們輸掉阿阿阿阿阿XD\n(註：筆者撰稿時BFG的價格約略落在0.029~0.03USDT附近，提領BFG最低限制是10BFG且手續費要5BFG，所以有考慮要買BFG進來存定存的話請留意一下這點。)\n分紅的價值會隨每天狀況變化 Betfury的分紅是透過取出每天所有人下注輸掉的量來取出一定比例分配給擁有10BFG以上的人，所以這個量會隨著BFG的總量改變而下修，同時也會跟目前熱門國際體育/電競賽事的時間有關，像之前奧運就有讓熱度上升一段時間，使得分紅上升；另一方面，分紅會以BTC/BNB/ETH/USDT/TRX這五種來發放，所以幣價也會影響取得分紅的價值。 讀者可在Staking-MY PAYOUT看到當前每天分紅(台灣是早上八點)時當下的BFG量，以及分得的貨幣，旁邊有圖示可以點開來估算取得的分紅的價值(USD)。以撰稿時間2021/08/31為例，\n1BFG可得的分紅價值為7.6227e-5 USD，\n要取得每天1USD 需要13,118.64354 BFG，\n約略為等值於388.64 USDT價值的BFG，意即對於當前而言，\n投入BFG的APR(年化報酬率)為91.6%左右。(但別忘了前面講到的，BFG有領出限制，各加密貨幣也是，\n所以想投入的話還要考慮投入的總額是否足夠大，\n得到的分紅對出金手續費而言划不划算)\n4. 骰子遊戲的坑 — 你以為機率夠低就不會遇到嗎？\na. 首先還是提醒，盡量每次開始設定前先按min ，\n避免不小心誤按的狀況發生，因為進入Dice遊戲時，\n預設會是一個相對高的起始下注額 。\nb. 在使用前面的期望值計算機的狀況下，設定為0.9999995的容錯條件下，\n大部分的計算應該都會算到接近的參數，也就是勝率為62%，輸後增幅在173%附近的設定方式。\n在這個條件下，各家電腦效能不同，最快的骰速會有區別；\n估算如果每天如果你的籌碼會增加1% 的話，\n約略1個月 左右會碰到一次爆倉(也就是連敗到無法加注)。\n每天會增加2% 的話，那大約就是半個月 就會遇到一次。\n當然也有例外的，像是筆者的一位朋友，我們使用相同的參數跑，\n他的電腦一天就是大約1%多，筆者的電腦是一天2.1%左右，\n筆者跑了13天左右就爆了(加上其他測試的帳號1個月內爆了5次)，\n他跑了快2個月才爆掉(爆掉以後總體加起來還有賺，超級強運XD)。\n但，不是所有人都是天選之人，所以這邊要教大家一個方法，但不見得能成功，只是一個想法而已，有興趣可以試試：\n就我們所知，其實所謂的機率就是查亂數表，再怎麼公正的機率也就是亂數表產生的結果。因此，當機率是由亂數表得來的時候，理論上小概率事件連續產生在表上的可能性就會下降(因為如果連續發生，就表示不夠亂，而表是事先安排好的)。當然，如果betfury會不斷切換使用的表的話，那可能就沒轍了XD，這個假設是建立在表一直是同一張在跑的狀況。\n如果前面的概念成立，那麼該怎麼做呢？\n很簡單，先正常跑個幾天(比方說5天)，再調整用最低限度跑到爆掉，如果同樣使用62%/173%，這個最小的停損籌碼需求大約是0.034 。跑到爆掉以後，再回復正常的下注量來進行下一個循環(想要更保險的話，也可以先用最低限度跑到爆掉，才開始正常跑)。\n這樣一來，只要你都能規避掉爆掉的那次不要損失過大的話，總體是可以賺的，只是中間就會耗費時間等候小額爆掉就是了。如果讀者是天選之人的話，可能要等很久很久XDDD\nc. 可以多開，但不能重複\n如果你想要同時跑不同的遊戲(比如同時玩Dice和Keno)，在同一個瀏覽器內原則上是無法使用不同加密貨幣的(會跳成相同的加密貨幣並且先跑的遊戲會停下來)，但在不同的瀏覽器登入同一個帳號則不受限於這個問題。\n要留意的一點是，如果所有遊戲都用fast模式跑的話，betfury有機會會認為你跑太快，跳出訊息要你slow down，並停下你的所有遊戲(笑)\n5. BFG挖礦效率 之前有提到過BFG挖的速度是按照wager貨幣的總價值而定的，\n這邊再更具體一點界定，其實它的難度是跟BTC來掛鉤的！\n例如之間比特幣跌價時，USDT的wager甚至到每2.9 USDT 左右的wager就可以得到一顆BFG，但現在需要4.582 USDT 才能挖到一顆。\n所以要看難度的話，可以在Staking頁面中，切換不同的貨幣，就可以看到目前該貨幣的MINING PRICE(每挖一顆BFG所需要的wager量)。而總體難度就看BTC的mining price的上升速度 。\n因此，假如今天讀者想要透過95%的方式快速消耗某個加密貨幣來取得BFG時，請留意一下它的價格波動，或許能找到相對價格比較好的時間點來進行wager消耗。\n6. 最後 如果要入金至betfury的話，請務必審慎考量前面提到的問題，以及清楚了解到如果不是天選之人的話，你總是會有把本金爆掉的風險，再進行入金。會建議可以拿一些加密貨幣水龍頭領到的錢或者是一些網賺平台出出來的小額加密貨幣來嘗試看看，這樣即便輸了也不會太有壓力。\n目前大概只想到這麼多，如果讀者有想到什麼問題或對使用上有什麼疑難雜症，又或者有任何經驗，也歡迎分享。\nMay the odds be ever in your favor!\n結尾容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-08-31T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/betfury.webp","permalink":"https://learnwithdesolve.netlify.app/post/a-bitcoin-faucet-betfury-common-mistakes-and-experiences/","title":"A bitcoin Faucet-邪惡浣熊BetFury常見的坑和經驗法則"},{"content":"0684. Redundant Connection (Medium)\n寫在前面 從 LeetCode 學演算法 + 面試成功指南**http://bit.ly/zeroclg\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\nQuestion In this problem, a tree is an undirected graph that is connected and has no cycles.\nYou are given a graph that started as a tree with n nodes labeled from 1 to n, with one additional edge added. The added edge has two different vertices chosen from 1 to n, and was not an edge that already existed. The graph is represented as an array edges of length n where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the graph.\nReturn an edge that can be removed so that the resulting graph is a tree of n nodes. If there are multiple answers, return the answer that occurs last in the input.\nExample 1 1 2 Input: edges = [[1,2],[1,3],[2,3]] Output: [2,3] Example 2 1 2 Input: edges = [[1,2],[2,3],[3,4],[1,4],[1,5]] Output: [1,4] Constraints n == edges.length 3 \u0026lt;= n \u0026lt;= 1000 edges[i].length == 2 1 \u0026lt;= ai \u0026lt; bi \u0026lt;= edges.length ai != bi There are no repeated edges. The given graph is connected. 分析/解題 在這個問題中，一棵樹是一個無向圖(undirected graph)，且當中沒有環(cycle)。給定一個圖，當中有n個node，標記為從1到n，其中有多一個邊(edge)；多出來的邊是由1到n選出兩個不同的節點(vertices, vertex的複數)所構成的，且並非已經存在的邊。這個圖是由一個長度為n的陣列edges來表示的，其每個元素edges[i]=[ai, bi]表示在圖中，ai和bi兩個節點中間有一個邊連結。\n請回傳一個可以在移除後令這個圖可以形成一棵含有n個節點的樹的邊，如果有多個答案的話，請回傳讓其發生在最後的輸入。\n好的，光翻譯題目就是一個很麻煩的事情，這也是為什麼從之前到現在始終不太想作圖(graph)相關的文章：因為實在太麻煩了，且不好解釋XD\n那我們今天就來挑戰看看吧！希望在看完本篇文章以後，大家還醒著(笑)XD\n在解這題之前，我們應該要先對圖作一點基本介紹：\n圖(graph)是一種描述資料與資料之間的連結(不是人與人之間的)的結構，\n當中最主要會分為兩個主要的元素：vertex(節點)及edge(邊/線段)。\n節點可能擁有自己的一些屬性或值，這個可以依照定義而改變，而節點和節點之間，則是透過邊來連接，因此在同一張圖內，如果有超過一個節點，那它們至少要有能夠相連的邊連結彼此(不然就不會是同一張圖了！)。\n接下來另一個很重要的點是，圖可以分為有向圖(directed graph) 和無向圖(undirected graph) ，什麼意思呢？\n舉例來說，筆者對台北還不夠熟悉的時候，騎著機車在台北附近總是容易繞一大圈才走到自己的目的地，而且回程的時候還容易繞錯路，其中一個原因就是單行道 。單行道表示了今天從A走到B可能可以走XX路，但從B到A可能要走OO路接RR路才行，因為XX路是單向的；換句話說，當從A到B和從B到A無法等價看待的時候，我們會稱這樣的圖為有向圖，因為其關連性不能夠直接反過來也成立。這種圖在繪製上的體現就是節點到節點之間會有箭頭以表示方向 ，對於本題來說，由於給定是無方向的，所以讀者會看到圖形上的連接僅有線條，沒有箭頭。\n接著是環(cycle) ，如果一個圖可以從某個節點出發，經過不重複 的節點(起點除外)，最終又能回到起始的節點，我們稱這個圖具有一個循環。\n圖的表示方式一般有兩種：\nAdjacency Matrix(相鄰矩陣)，也就是如果有N個節點，就開一個NxN的矩陣Mat，當中如果A點跟B點有edge的話，Mat[A][B]=1，否則為0；可以想見，如果某個圖是無向圖的話，這個矩陣應該會沿對角線相對稱(因為Mat[A][B]會和Mat[B][A]等價)。\nAdjacency List(相鄰串列)，也就是對每個節點，都用一個串列來列出跟這個節點有相連的邊的所有節點。\n一般而言，如果總體的edge數量較多的話會使用相鄰矩陣，比較少的話則會使用相鄰串列。\n其它跟圖有關的基礎其實還很多，我們容後有機會再慢慢講。\n回到我們的題目，其實它是一個相對簡單的圖，\n因為要連接n個節點總體只需要n-1個邊，而這個圖有n個邊，\n要讓這個圖不成環，只能將其中一個會構成環的邊給去除掉。\n那麼，我們怎麼知道哪邊會有環成立呢？\n這邊我們可以使用union find的概念來處理。\nunion find其實是在探究併查集( Disjoint-set data structure**)** 的問題。\n用最白話的方式，就是「我們有沒有同一國」的概念。\n什麼意思呢？\n假設一個班級有幾個小團體，這些小團體跟幫派一樣很講17且不能重覆加入，我們現在想知道究竟哪些同學屬於哪個小團體，要怎麼找呢？\n其實很簡單，就是把每個同學叫過來問：「你的老大是誰？」\n舉例來說，如果有一個班級有兩個小團體，它們之間的層級分部是這樣的：\nA\n| B C\n| | DE- F\nG\n|\nH\n|\nI\nD會告訴你他的老大是B；\nE會告訴你他的老大是C；\n然後B、C會告訴你他們的老大是A；\n最後問到A他會說：「我就是老大！」\n於是我們就會發現B、C、D、E這四位其實都是隸屬於A的，\n也就是他們都是同一團體的。而G、H、I則屬於另一個團體。\n因此，我們可以對某個節點找到它最上層的節點，\n用這個節點來定義它所屬的團體，同時在過程中依照新增的邊來合併彼此的老大，這個過程叫作find 。\n那麼，我們換個角度來思考：\n依照上面的概念，每個節點之間的邊，其實就可以代表它們是同一國的，\n那麼，如果在看到這個邊之前，它們就已經有相同的老大了呢？\n比如上面的圖而言，對於E和F來說，由於有A-C-E跟A-C-F，\n因此E跟F都知道自己的老大是A。\n接著我們看到E-F的這條邊連結起來，就意味著這邊構成了一個環 ！\n因為前面E已經可以連到A，F也可以連到A表示EAF之間可以連接起來，\n因此E-F的連接就給這之間構成了一個環。\n因此，我們可以利用這點，來找出構成環的邊，就是我們要的答案了！\n因為節點和邊的總數量我們知道是n，所有節點也只有1~n，\n所以我們可以使用一個陣列或串列來簡單表示某個節點的老大是哪個節點。\n如果它自己就是最大的老大的話，那麼我們就用-1來代表它沒有更上層了。\n因此，我們的解題步驟應該像這樣：\n產生一個root的陣列/串列，其長度為n+1 (比較方便對應1~n)，\n其初始值均為**-1** 。 對於edges中的每個邊edge，使用find 函式找到它們的老大x跟y，\n檢查x和y是否相同；若相同，表示這個邊構成了一個環 ，回傳edge 即可；\n若不同，則須統一老大，將root[x]設定為y (將x這系列的上層往y這邊合併)。 如果檢查完均檢查不到，則在外層回傳空的陣列/串列表示沒找到(但題目表示應該都會存在答案，所以理論上不會走到這邊)。 在find函式 的定義中，輸入應該是root這個陣列跟要被確認的節點i：\n使用迴圈，當root[i]不是-1時，令i = root[i] ，往上找尋更上層的老大。 直到迴圈結束，這時候的i應該是最上層了，就回傳i 即可。 依此，寫成程式碼如下：\nJava Java的部份可以使用Arrays.fill來給定一整組的陣列初始值。\nPython Python的部分則直接用*號來初始化即可，同時使用子函式，\n略去self相關的麻煩寫法。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(如果找尋root的時間沒有到最糟糕狀況的話為O(N)/O(N)，但我們在這個版本的只實作了find，最差狀況下find會一條線接上去，導致find的複雜度達到O(N)，這時候總體時間複雜度就會是O(N^2)。)\n「如果要實作化簡的部份的話？」\n(化簡的概念在於將中間尋找的部分也一併處理，也就是告訴沿路上的所有節點它們最大的老大是誰，要怎麼作才能讓整個路徑更短，可以參見https://en.wikipedia.org/wiki/Disjoint-set_data_structure，或者參考LeetCode的Solution也有提供，原則上是看兩個小團之間的節點數量來進行誰併到誰的決定。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-07-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-115-graph-1-union-find-1/","title":"從LeetCode學演算法 - 115 Graph(1) / Union Find (1)"},{"content":"這世界總是不缺乏會寫程式的人XD\n如果還沒有註冊的朋友，歡迎使用以下連結：\nhttps://betfury.io/?r=6068fc1e87d77c13a350ba20 介紹文章請參見A bitcoin Faucet網路加密貨幣賺錢-邪惡浣熊BetFury 。\n前面的文章介紹過骰子的機制，那麼，要怎麼選擇機率，\n可以得到一個適當的風險和取得較好的賺錢效率呢？\n這款由筆者一位厲害的前同事寫出來的程式便應運而生啦！\n我們可以藉由輸入網址時調整選擇參數，來計算對應的設定建議。\nhttps://cryptic-brook-55628.herokuapp.com/?target_winrate=0.9999995\u0026amp;money=1000 當中：\ntarget_winrate=0.9999995 -\u0026gt; 最後一輪要贏的勝率至少維持在多少以上，建議在99.99995%以上。\n換言之，算出來的下注，最終輸到無法加碼的機率為0.00005% 。\nmoney=1000 -\u0026gt; 起始你有的本金是多少(以1顆貨幣為單位，不是聰數歐！)\n我們以target_winrate=0.9999995, money=1來試算看看：\n勝率/賠率 分別對應到骰子設定的Chance to win/Multiplier ，\n增幅 對應到的是輸後增幅(ON LOSS INCREASE) 的比例，\n回合 是指在這個條件下本金最多可以撐到第幾次骰(該次要贏)，\n例如62%的話，就是前面連輸，最差到第15骰要贏才行\n(否則就沒錢加碼了)。\n真實勝率 是指到最大的容錯狀況下能贏的機會，例如62%的話，就是每一輪骰第1次就贏的機率，到骰到第15次才贏的機率加總起來。\n(這個勝率一定會大於等於我們原先的預設的目標勝率值)\n初始下注 是依照這個設定建議的開始下注量。\n理論爆倉骰數 是按期望值而言，每骰多少次，理論上會出現爆掉的狀況。\n(也就是說數字越大就越安全XD)\n(註：不要看這個數字很大，若以使用62%的狀況而言，如果電腦速度夠快的話(每秒至少超過1骰)，其實大約1個月多一點就有機會碰到1次呦!)\n單骰期望損益 是指每一骰在不要爆掉的狀況下，平均會賺的籌碼量。\n單骰期望wager 是指每一骰在不要爆掉的狀況下，平均會產生的wager量。\n單骰期望穩定損益 是指去除掉過小的機率後(比較難發生的狀況下)，計算不要爆掉的狀況下，平均會賺的籌碼量。\n讀者可以依此來選擇自己的策略(按在欄位上可以進行升冪/降冪的排序)，例如想要籌碼量累積最快的話，依上面的輸入而言，62%勝率/173%輸後增幅，會是累積最快的 。當然，你也可以選擇較低的籌碼累積速度，換取較高的wager量(也就是BFG會累積快一點)，或者換取較大的容錯(將爆倉的風險下降)，歡迎分享自己選擇的策略及實測結果!發現任何bug，或有任何修改意見，也歡迎提出討論呦!\n結尾容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放購買啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n從 LeetCode 學演算法 + 面試成功指南 (基礎+進階+面試篇) http://bit.ly/zeroclg\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-06-15T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/betfury.webp","permalink":"https://learnwithdesolve.netlify.app/post/a-bitcoin-faucet-betfury-dice-expectation-value-calculator/","title":"A bitcoin Faucet-邪惡浣熊BetFury骰子期望值計算器"},{"content":"是時候來複習期望值囉！\n最近筆者除了在認真寫稿外，由於加密貨幣這麼夯，\n也順便研究了一下各項網路賺錢的部分XD\n畢竟加密貨幣的世界吼那個漲跌幅實在是太誇張了，\n有興趣的朋友，不妨可以先從一般的網路賺錢來彙整成一些小收入，\n再慢慢累積經驗後，再行決定是否投入新台幣持有比較大的部位XD\n今天我們要來介紹的平台BetFury，嚴格來說應該算是娛樂城平台，\n原則上不建議自己入金下去賭呦！我們要介紹的是免費的部分XD\niGaming Platform with Bitcoin Daily Payouts - BetFury\n*iGaming Crypto platform with the first BTC Staking pool in industry. 1500+ games, BFG Staking, Daily Payouts in BTC…*betfury.io\n請使用上面的連結進行註冊以後，點選BOXES，可以看到以下畫面：\n當前BetFury提供了兩種免費的BOX(跟一般的網賺的水龍頭概念接近)，一個是BNB(幣安交易所的貨幣，日前1顆BNB的價格曾經來到690美金，截稿日2021/05/21時價格約在380美金左右)，一個是BTC(也就是我們所熟知的比特幣)，每隔20分鐘 就可以來這邊提領，以截稿日而言，目前每20分鐘可以領137聰(10的-8次方)的BNB，以及1.25聰的BTC 。\n接下來請來到左側並點選Staking頁面：\nStaking(抵押) 在加密貨幣的含義是透過持有貨幣(鎖倉)，來獲得加密貨幣的獎勵。BetFury的自有貨幣為BFG ，當使用所有除了BFG以外的加密貨幣 進行遊戲(包含骰子和其它押注的遊戲)，會依據每次下注的貨幣價值 ，來給予使用者BFG，所以依據的是wager(下注) 的總量，而不是下注賺的錢。\n當BFG達到10顆時，Staking機制便會啟動，每天使用者都可以依照所擁有的BFG比例，取得分紅呦！ 以筆者現在為例，21.12顆BFG ，每天會給84聰的BNB，27163聰的USDT(USDT又叫泰達幣，是穩定幣 的一種，其價值等同於1美金)，13聰的ETH(以太幣)，388370聰的TRX(波場幣)，以及1041539聰的BTT(BitTorrent)。至於BTC，因為每天給的已經到小數點的聰數了，所以不會顯示出來XD\n那麼，要怎麼樣才能累積BFG呢？\n其它的遊戲，我研究不深，我們來講講骰子遊戲吧！\n上方的火箭圖案是用來在自動模式中加速用的XD\n在上方選擇All games，分類選擇Dice，\n我們可以看到一個很簡單的賭骰子遊戲，也就是賭大小XD！\n移動中間的點數，我們可以觀察到選擇不同的點數，\n勝率和BetFury給出來的賠率也會隨之改變，\n例如我們將其移動到95時，勝率會是95%，賠率則會被調整為1.0315 。\n計算期望值我們可以發現，下注1單位，即便勝率很高，但結果的期望值是0.95*1.0315=0.979925 ，顯然長時間而言會一路虧下去，但由於會獲得BFG，比特幣一般在各交易所又常需要最小提取量和手續費，所以我們可以利用這點，將BTC燒成BFG！\n在開始之前，必須要提醒各位一個很重要的事情：\n在從頭開始進到頁面，做任何操作之前，請先按Min ，先把籌碼下注量進行縮小到1聰，因為每次進到這個頁面時，邪惡的浣熊都會預設你要All in，千萬不要不小心就按到Start阿！！！ 有不少人都被陰了一把呦！\n在加密貨幣量不夠的時候，要透過燒掉它們取得盡可能多的wager時，\n95%是目前所知最好的辦法了！\n我們來計算一下，假設目前我們有1單位的貨幣，\n那麼可以取得多少單位的wager量呢？\n如果我們很均勻地下注，\n首次下完全部的貨幣後，1單位的貨幣就產生了1單位的wager量，\n同時會剩下1*0.95*1.0315 = 0.979925的貨幣；\n下一輪再下完，會產生0.979925單位的wager量，\n同時會剩下(0.979925)²的貨幣，很顯然這是一個無窮等比級數，\n其和為a/(1-r) = 1/(1-0.979925) = 49.8132 的wager量。\n這個值經過觀察對應每次產生的BFG以後，可以計算出需要多少USDT完整燒完產生的wager量可以得到10 BFG。以本文章初稿截稿時，約略需要正好1 USDT 。(細節這裡就不贅述了)\n(註：因為實際所需要的wager量會依官方調整而定，故請依照Staking頁面上的Mining Price -\u0026gt; In House Games 所顯示的量為基準，2021/06/15的時間點比例約為3.56 USDT wager = 1BFG )\n因此，每次領到一定數量的BTC及BNB，至Dice選擇AUTO，將下注的勝率調到95%，下注量用最小單位，再按下Start將其「燒」完以獲得一定量的BFG。\n或者，如果讀者有足額的籌碼，也可採用博雅法 型態來進行骰子遊戲。\n博雅法的概念在於，每次輸的時候，將籌碼按比例增加，讓下一次如果贏的話可以完全cover掉前面的損失。 最基礎的下法，也就是將ON LOSS的結果設定為Increase 100%，同時透過調整數字讓賠率移動到2倍。 如此一來，下注1單位的話，第一次贏的話，淨賺會是1單位；\n假設第一次輸的話，第二次就會下2單位，這樣贏的時候會淨賺2單位，\n將前面的虧損計入以後，還是淨賺1單位。\n讀者可能會問，這樣子的話不就是必勝法嗎？\n理論上是這樣子沒錯啦，但也要本夠大才行XD\n利用這個概念，我們也可以製造勝率小，賠率大的博雅下法，\n只要確定每次均可覆蓋虧損即可。\n這裡提供從其他水龍頭出金到BetFury，以及從BetFury出金到幣安交易所的證明給大家參考，若讀者有在考慮自己從其他的網賺平台出金加密貨幣到BetFury，但有顧慮到底它能不能提出來的，應該還算可以安心，因為它出金和入金的速度都還算蠻快的。\n選右上角的Deposit可以進行入金，請留意貨幣是否有最低入金限制\n這邊使用筆者之前累積的Express Crypto上的TRX進行出金\n出金TRX則至少需求0.1 TRX，這邊測試出到幣安1顆TRX\n一般進入確認以後過不久就會到帳啦！\n提示一下，當自行推導博雅法時，容錯範圍請盡量抓N次中至少一次骰贏的機會為99.9999%以上 ，小數點後沒有4位以上的9機率的狀況，在實務上均有機會碰到。在本夠大的狀況下，是可以讓整體籌碼穩步提升，同時又可以累積BFG的呦！\n如果不清楚入金後該怎麼做，又或者是有其它問題，或讀者也想要知道別的網賺管道來相對快速累積到足夠的金額入到BetFury的話，歡迎用上面的連結註冊後，截圖referral的地方的My Inviter是”User953170\u0026quot; 當做證明，寄信到我的信箱或附圖留言詢問我呦！大家一起來滾出被動收入吧XD！\n最後請留意到，BetFury在使用骰子進行快速骰(將火箭點起來，可以加速骰子運行)的時候，有不明原因會快速消耗到系統的CPU資源，筆者是推測它也是有可能使用部份的網頁挖礦，但目前並沒有證據(歡迎厲害的朋友來檢查看看到底有沒有這回事)。但這也合理啦，不然憑什麼我們領免費的，花免費的，它還要給我們發錢呢XD？題外話，若真的覺得它佔用太高的CPU資源的話，可以考慮使用CPU Balancer 之類的軟體對其使用率進行適度的抑制。\n最後，幫大家做個整理：\nBetFury是一個線上娛樂城，但它提供每20分鐘免費的BNB跟BTC 可領。 耗費其自有貨幣BFG以外的加密貨幣 ，可以依下注的貨幣價值 獲得BFG。 BFG ≥10顆 時，每天可領加密貨幣的分紅。 初期可以依靠燒掉BTC/BNB(使用95% 的方法)快速累積BFG。 進階方式可從別的地方入金，並用博雅法的方式同時累積籌碼和BFG。 當前入金出金看起來都沒有問題！ 歡迎使用我的連結 註冊XD！ 預祝大家都能夠成功建立一個穩定的迷你被動收入管道XD！\n結尾容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放購買啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的優惠～\n從 LeetCode 學演算法 + 面試成功指南 (基礎+進階+面試篇) http://bit.ly/zeroclg\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-05-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/betfury.webp","permalink":"https://learnwithdesolve.netlify.app/post/a-bitcoin-faucet-betfury/","title":"A bitcoin Faucet-網路加密貨幣賺錢！邪惡浣熊BetFury"},{"content":"0946. Validate Stack Sequences (Medium)\n寫在前面 目前0元挑戰賽 的活動已經開始囉！\n只要修課後三個月內完課且成功錄取新工作並撰寫心得，\n課程就會全額退費喲！請使用下面連結看更詳細的規則說明：\n(目前只剩一般的套組優惠~）\n零元求職挑戰賽 Python 組｜從 LeetCode 學演算法 + 面試成功指南 http://bit.ly/zeroclg\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\nQuestion Given two sequences pushed and popped with distinct values , return true if and only if this could have been the result of a sequence of push and pop operations on an initially empty stack.\nExample 1 1 2 3 4 5 Input: pushed = [1,2,3,4,5], popped = [4,5,3,2,1] Output: true Explanation: We might do the following sequence: push(1), push(2), push(3), push(4), pop() -\u0026gt; 4, push(5), pop() -\u0026gt; 5, pop() -\u0026gt; 3, pop() -\u0026gt; 2, pop() -\u0026gt; 1 Example 2 1 2 3 Input: pushed = [1,2,3,4,5], popped = [4,3,5,1,2] Output: false Explanation: 1 cannot be popped before 2. Constraints 0 \u0026lt;= pushed.length == popped.length \u0026lt;= 1000 0 \u0026lt;= pushed[i], popped[i] \u0026lt; 1000 pushed is a permutation of popped. pushed and popped have distinct values. 分析/解題 給定兩個序列pushed跟poped，\n序列當中的每個值都是獨特的(也就是每個值會不同)，\n如果對於一個空的stack進行push和pop的操作，\n能夠完全符合pushed和poped列出來的順序的話，\n就回傳true，否則回傳false。\n這個問題乍看之下或許有點不夠清楚，\n簡單來說呢，就是不管如何，推入的順序一定是pushed，\n也就是放入的時候的順序是固定的，只是選擇在什麼時候poped而已，\n例如[1, 2, 3, 4, 5]，\n如果我們push兩次，pop一次，再push三次，pop四次 ，\n那麼我們所得到的結果會是:\n1 2 3 4 5 stack poped 1, 2 1 2 1, 3, 4, 5 2 2, 5, 4, 3, 1 再多做一些嘗試，就會知道pop的時間點會影響到poped最終的順序結果。\n因此，我們可以試想一下幾個情況：\n當stack裡面沒有東西 -\u0026gt; 沒辦法pop東西出來，必須要先push進去才行。\n當stack裡面有東西 -\u0026gt; 要pop出來嗎？由於每個值都相異，所以這邊出現過的數字，後面就不能出現了！因此我們應該看現在poped的順序走到哪裡 ，去檢查現在stack最上面 是否和poped對應的數字一樣 ，這樣才代表需要做pop的操作。\n依照上面的想法，我們做的順序應該像這樣：\n開一個新的Stack，這邊稱為st。 宣告一個變數i並初始化為0，用來記錄下一個poped所在的index 。 使用迴圈，依序每次從pushed取出一個num：\n3–1. 將num推入st中\n3–2. 當st還有值在內，且最上層剛好和poped[i]相同 時，進行迴圈，\n對st進行一次pop，並遞增i (代表往下一個值來看)\n(不相同的話，就代表這個值不該在這邊被pop出來) 大迴圈結束後，若st剛好清空，代表這個順序是OK的，\n因此st是空的時候回傳true，否則回傳false 。 依此，寫成程式碼如下：\nJava Java的部分，檢查stack是否為空要用isEmpty函式，\n看stack最上層可以使用peek ，也就是先偷看一下，\n避免使用pop，因為我們還沒有篤定要將其移出stack外。\nPython Python的部分，我們可以直接使用list做為stack來使用 ，\n可以使用append/pop，看最上層就直接利用st[-1] 即可。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，N為pushed/popped的長度)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-02-27T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-114-stack-3/","title":"從LeetCode學演算法 - 114 Stack (3)"},{"content":"1091. Shortest Path in Binary Matrix (Medium)\n寫在前面 目前0元挑戰賽 的活動已經開始囉！\n只要修課後三個月內完課且成功錄取新工作並撰寫心得，\n課程就會全額退費喲！請使用下面連結看更詳細的規則說明：\n(新年優惠套組已截止囉！）\n零元求職挑戰賽 Python 組｜從 LeetCode 學演算法 + 面試成功指南 http://bit.ly/zeroclg\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\nQuestion In an N by N square grid, each cell is either empty (0) or blocked (1).\nA clear path from top-left to bottom-right has length k if and only if it is composed of cells C_1, C_2, ..., C_k such that:\nAdjacent cells C_i and C_{i+1} are connected 8-directionally (ie., they are different and share an edge or corner) C_1 is at location (0, 0) (ie. has value grid[0][0]) C_k is at location (N-1, N-1) (ie. has value grid[N-1][N-1]) If C_i is located at (r, c), then grid[r][c] is empty (ie. grid[r][c] == 0). Return the length of the shortest such clear path from top-left to bottom-right. If such a path does not exist, return -1.\nExample 1 1 Input: [[0,1],[1,0]] 1 Output: 2 Example 2 1 Input: [[0,0,0],[1,1,0],[1,1,0]] 1 Output: 4 Note:\n1 \u0026lt;= grid.length == grid[0].length \u0026lt;= 100 grid[r][c] is 0 or 1 分析/解題 在一個N x N的平方格子裡，每個格子可能是空的(0)，\n不然就是阻塞住的(1)。\n一個乾淨的路徑從左上到右下的長度為k，如果路徑上的格子都是8方向(也就是九宮格的對應)相連，且開頭是(0, 0)，結尾是(N-1, N-1)，且每一格都是空的(0)。請回傳從左上到右下最短的乾淨路徑長，若不存在則回傳-1。\n這個題目其實可以有很多種不同的解決方式，\n不過我們好久沒有使用到BFS了，就來試試看BFS的解法吧！\n根據題目的定義，我們要找的是最短路徑，\n所以可以從(0, 0)開始嘗試每次往8個方向各走一步，\n並且將計數+1及標記已經走過，當在某步碰到了(N-1, N-1)時，\n即表示我們找到了最短路徑(因為所有路線都是每次同時走一步)。\n因此，我們需要一個Queue來記錄當前所有走到的點，\n然後每次再將Queue的點取出，\n找到8個方向的新的一步的點，加入到Queue中。\n(不能超出邊界，不能已經走過，也不能被阻擋住)\n那麼我們怎麼知道同一層的要做到哪裡呢？\n很簡單，在這層開始之前，我們先記錄下當前Queue的長度，\n這樣子同一層只要做完這麼多個點就可以啦！\n依此，寫成程式碼如下：\n(下面的程式碼中，我們直接把走過的路徑給標成block了，\n這點相對較節省空間也較方便，但其實不是很正規，\n如果面試時沒有說你可以動grid，請開出一個N x N的visited格子，\n用來記錄有經過的點會比較好呦！)\nJava Java的部分，首先我們先檢查grid的狀況，\n以及左上右下是否有阻擋住的狀況，有的話就直接回傳-1。\n接著使用LinkedList作為我們的Queue，\n可以使用add或者offer來加入新的元素。\n當queue不為空時，每次取出一個點，往對應的8個方向取點並檢查：\n走到右下角的話代表走完，直接回傳cnt。 如果點是合法的點的話，就將那格標記為1並加入queue中。 每輪做完別忘記將cnt遞增。 全部做完還沒有碰到右下角，代表沒有解，回傳-1。\nPython Python的部分則使用deque來操作，\n留意到這個題目其實也可以擴展成矩形，\n這邊示範使用r, c的方式來記錄，但其實區別不大。\n但對deque來說，取出記得是使用popleft，請不要誤用成pop了！\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N²)/O(N²)，最糟糕的狀況是擴散的很開的時候，\nqueue所需要的空間會很大，這個問題其實可以使用bi-directional的BFS來降低擴散的程度，可以再參考leetcode上別人的解法。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-02-16T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-113-bfs-4-queue-5/","title":"從LeetCode學演算法 - 113 BFS (4) / Queue (5)"},{"content":"0367. Valid Perfect Square (Easy)\n寫在前面 目前0元挑戰賽 的活動已經開始囉！\n只要修課後三個月內完課且成功錄取新工作並撰寫心得，\n課程就會全額退費喲！請使用下面連結看更詳細的規則說明：\n同時，還有限時更便宜的套組3490 (再便宜500呦！限額10名！)\n新年限量組合🎁 零元求職挑戰賽 Python 組｜從 LeetCode 學演算法https://hiskio.com/packages/ZXwe2p9yv\n零元求職挑戰賽 Python 組｜從 LeetCode 學演算法 + 面試成功指南 http://bit.ly/zeroclg\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\nQuestion Given a positive integer num, write a function which returns True if num is a perfect square else False.\nFollow up: ** Do not** use any built-in library function such as sqrt.\nExample 1 1 2 Input: num = 16 Output: true Example 2 1 2 Input: num = 14 Output: false Constraints 1 \u0026lt;= num \u0026lt;= 2^31 - 1 分析/解題 給定一個正整數num，試檢驗num是否為完全平方數(也就是可以分解成兩個完全相等的數相乘)。\n請不要使用內建的sqrt或類似的函式。\n雖然被封印了平方根函數，但已經看到標題的讀者應該不難猜想到，\n我們可以運用一般的二分逼近法，\n去將目標(我們先稱之為x)的範圍縮小。\n當找到 x² 和num相等時，就表示num是完全平方數(回傳True)，\n否則一路找到兩個邊界交叉時，表示num不存在整數平方根，\n我們就可以回傳False。\n那麼，有沒有再更厲害一點的方法呢？\n這邊來介紹一下一個著名的方法，名為牛頓法(Newton’s Method)。\n我們在求x² = num當中的x，(下面方便起見，將num寫成n)\n其實相當於求 y = f(x) = x² - n在y = 0時的正根。\n假定r是這個根，我們先取一個任意一個比較大的值x0，\n那麼它對應到的座標應該是(x0, f(x0))。\n對於這個點做曲線的切線的話，應該可以得到切線方程式：\ny = f(x0) + f\u0026rsquo;(x0) (x-x0) 也就是y = ax +b嘛! a就是在x0上的切線斜率，\n而x代入x0的話可以驗證y = f(x0)，\n所以這個方程式可以表達該切線沒錯。\n我們將這個切線叫做L，\n那麼L和x軸的交點的x座標，應該就和r更近囉！\n(想像一下拋物線的斜度會越來越平，所以切線和x軸的交點，\n比起拋物線和x軸的交點來說應該會大一點)\n我們將後面和x軸的交點位置叫做x1 ，\n那麼就可以計算其斜率為 f(x0) / (x0-x1) = (x0²-n)/(x0-x1) ，\n同時也等於f(x)的導數(就是對其微分)f’(x) = 2x 。\n因此，2x0 = (x0²-n)/(x0-x1) -\u0026gt; 2x0(x0-x1) = x0²-n\n繼續化簡：\n-\u0026gt; 2x0²-2x0x1=x0²-n\n-\u0026gt; x0²+n = 2x0x1\n-\u0026gt; x1 = (x0 + n/x0) / 2\n每次取得一個更接近的x來逼近r的位置\n我們可以再用這個x1再取得在f(x)上的點，接下來再畫切線，\n重復上面的動作。\n當我們每次用前面這個算式迭代，就可以取得一個新的x，\n理論上它會更接近於r。(x1, x2, x3, …)\n由於要取的是整數，所以我們在計算的時候，\n就將所有的算式中的除法都取整數，\n這樣算出來的狀況，就會變得有機會更小。\n所以在運用到實際的計算時，\n我們可以設定一個迴圈，將x直接先定為num，\n當x² \u0026gt; num時，就持續迴圈，\n那麼在x持續縮小的狀況下，\n最終要嘛縮小到剛好得到一個正整數的平方根，\n要嘛就是x²已經小於num了，我們就不用繼續往下做啦！\n依此，寫成程式碼如下：\nJava Java的部分，請留意到大小問題，我們應該要使用long來宣告變數。 Python Python部分則請不要忘記整數除法是”//”。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(時間複雜度難以界定，最差應該是O(num)，(但二分法也是)\n平均應該優於O(log(num))，這可能也取決於初始值的取法；\n空間複雜度則為O(1))\n相似及延伸：\n本題還有其他的解法可以參考以下連結https://leetcode.com/problems/valid-perfect-square/discuss/130010/Python-4-Methods-with-time-testing\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-02-01T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-112-binary-search-6-newton-s-method/","title":"從LeetCode學演算法 - 112 Binary Search (6) / Newton’s Method"},{"content":"0784. Letter Case Permutation (Medium)\n寫在前面 目前0元挑戰賽 的活動已經開始囉！\n只要修課後三個月內完課且成功錄取新工作並撰寫心得，\n課程就會全額退費喲！請使用下面連結看更詳細的規則說明：\n零元求職挑戰賽 Python 組｜從 LeetCode 學演算法 + 面試成功指南 http://bit.ly/zeroclg\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\nQuestion Given a string S, we can transform every letter individually to be lowercase or uppercase to create another string.\nReturn a list of all possible strings we could create. You can return the output in any order .\nExample 1 1 2 Input: S = \u0026#34;a1b2\u0026#34; Output: [\u0026#34;a1b2\u0026#34;,\u0026#34;a1B2\u0026#34;,\u0026#34;A1b2\u0026#34;,\u0026#34;A1B2\u0026#34;] Example 2 1 2 Input: S = \u0026#34;3z4\u0026#34; Output: [\u0026#34;3z4\u0026#34;,\u0026#34;3Z4\u0026#34;] Example 3 1 2 Input: S = \u0026#34;12345\u0026#34; Output: [\u0026#34;12345\u0026#34;] Example 4 1 2 Input: S = \u0026#34;0\u0026#34; Output: [\u0026#34;0\u0026#34;] Constraints S will be a string with length between 1 and 12. S will consist only of letters or digits. 分析/解題 給定一個字串S，\n我們可以任意將其中的單一字母轉換成小寫或大寫，\n以創造出另一個字串。\n回傳一個列表，當中包含所有我們可以創造出來的字串。\n(回傳的字串順序可以不同)\n(限制：S的長度會在1~12之間，且S只會有字母或數字)\n這個題目實際上並不是很難想，\n從直觀上來說，就是找出所有字母的地方(因為只有字母可以變)，\n讓它是小寫或大寫這兩種可能，會產生不一樣的字串，\n因此如果當中存在L個字母的話，\n其變化就會有2^L種。\n那麼，我們怎麼樣處理這樣子的產生的過程呢？\n這就要回頭複習一下回溯法的概念了！\n以前我們提到過，回溯法就是當走到一段，無法再往下走時，\n回到上一步並還原前面的痕跡，再往下一條路走的做法。\n因此，我們來看待這題會變成這樣：\n先將整個字串轉成小寫 (要都轉成大寫也可以) 從index 0 開始往下走(將現在的位置定為pos )，\n當順著往下走都不改變 時，\n最後應該會走到底部，此時pos == 整個字串長 ，\n這會是其中一個字串變化，可記錄到結果(res)中 。 接著，回到上一步時，\n我們可以檢查pos位置是否為字母 ，\n是的話 ，我們可以改成將該位置的字母轉為大寫 ，\n再重新往下走一次(因為這樣子變化又不一樣了) 走到底回到上一層時，再將字母轉回小寫(回溯法的復原) 最終，全數走完時，res 即會紀錄所有的答案。 所以在使用DFS和回溯法時，\n讀者請切記兩個要點：\n1. 走到死路(結束時該回頭)的條件要設定好\n2. 被更改的東西，在這條路線結束後，記得復原\n依此，寫成程式碼如下：\nJava Java的部分，使用toLowerCase()和toCharArray()，\n將字串轉換成全小寫 的字元陣列，方便修改；\n我們用helper函數來進行DFS+Backtracking。\n在轉換上，使用new String(a)可以從一個字元陣列生成一個字串。\n可能\nPython Python的部分，使用list() 來拆成串列，\n同時組成字串是使用**’’.join()** 來處理的，\n檢查字母是使用isalpha() 函式；\n同時請留意**.upper()和.lower()並不直接對原來的東西做修改** ，\n而是會回傳新的str ，所以請將其輸入回a[pos]裡，\n才會真正修改到。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(2^L)/O(len(S)), L為字串中字母的數量)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-01-20T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-111-dfs-18-backtracking-8/","title":"從LeetCode學演算法 - 111 DFS (18) / Backtracking (8)"},{"content":"0881. Boats to Save People (Medium)\n寫在前面 目前0元挑戰賽 的活動已經開始囉！\n只要修課後三個月內完課且成功錄取新工作並撰寫心得，\n課程就會全額退費喲！請使用下面連結看更詳細的規則說明：\n零元求職挑戰賽 Python 組｜從 LeetCode 學演算法 + 面試成功指南 http://bit.ly/zeroclg\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\nQuestion The i-th person has weight people[i], and each boat can carry a maximum weight of limit.\nEach boat carries at most 2 people at the same time, provided the sum of the weight of those people is at most limit.\nReturn the minimum number of boats to carry every given person. (It is guaranteed each person can be carried by a boat.)\nExample 1 1 2 3 Input: people = [1,2], limit = 3 Output: 1 Explanation: 1 boat (1, 2) Example 2 1 2 3 Input: people = [3,2,2,1], limit = 3 Output: 3 Explanation: 3 boats (1, 2), (2) and (3) Example 3 1 2 3 Input: people = [3,5,3,4], limit = 5 Output: 4 Explanation: 4 boats (3), (3), (4), (5) Note :\n1 \u0026lt;= people.length \u0026lt;= 50000 1 \u0026lt;= people[i] \u0026lt;= limit \u0026lt;= 30000 分析/解題 有一群人people，當中第i個人的重量是people[i]，\n且每艘船最重可以載重limit，同時最多只能乘載2個人，\n乘載的重量最多為limit(剛好的話也可以)\n試計算並回傳最少所需裝載所有人的船的數量。\n乍看之下，這題是不是有點像以前的Two Sum?\n但再仔細想想，就會發現，\n由於我們並不一定要每艘船都裝載到limit的重量，\n所以並不能夠形成相加等於特定和的關係。\n那麼該怎麼處理呢？\n如果這群人是由小到大排列的話，\n不管如何最重的那些人都還是要上船，\n所以我們先挑最右邊的(最重的人)上船。\n接下來這艘船還能不能帶人呢？\n我們就再幫忙找最左邊的(最輕的人)看能不能湊一組，\n可以湊就沒問題，不能湊也無法強求，就只好讓這個人自己一條船囉！\n這樣搭配下，我們就可以盡可能先幫較重的人找看看能不能組起來，\n因此會是所需求的船隻數量會是最小的。\n上面這樣子的概念，被稱為貪婪演算法(Greedy Algorithm) 。\n貪婪演算法的核心精神，在於先找到一個方法，\n使得每次盡可能都處理所有可以操作的單位，\n再依序往下做處理，這樣的方法是對總體來說也是最佳 的時候，\n就符合貪婪演算法的特性。\n請讀者務必留意，\n如果像是動態規劃(Dynamic Programming) 這類型的問題，\n就顯然不會符合 貪婪演算法的作法，\n因為局部的最佳解，不見得會是全局的最佳解 。\n所以對這題來說，當我們排序完這群人以後，\n從最重的開始盡可能幫其安排組合，對總體來說就會是最好的。\n因此，我們的大體解法應該如下：\n先將people由小到大排序 令l = 0, r = people.length - 1, res = 0 (用來記錄需要幾艘船) 使用一個迴圈，當 l ≤ r 時，進行以下操作：\n3–1. 如果 people[l]+people[r]\u0026lt;= limit 時，\n代表可以捎上index l 的人，此時將** l遞增。\n3–2. 由於所有人的重量都一定小於limit** ，(題目說的)\n所以people[r]一定可以占一艘船 (不管people[l]有沒有上船)，\n所以我們將r遞減 ，並且將res遞增 ，這艘船我們就處理完囉！ 回傳res 即為答案。 讀者可能會問：咦？那l和r重疊 的話怎麼辦？\n問得好！重疊的話，由於不論怎麼樣r都會遞減，\n所以重疊的時候，事實上就是相當於3–1沒有任何作用 ，\n但並沒有影響到我們要計算的res，對吧XD？\n依此，寫成程式碼如下：\nJava Java的話使用Arrays.sort()，\n其他部分應該相當直觀。\n這裡提供LeetCode的另一種解法，\n由於有limit的限制，所以我們可以利用長度為limit+1的陣列，\n來達到排序的效果(這相當於O(limit)的空間去換取時間複雜度降低)\nPython Python的排序則直接對串列進行.sort()即可，\n讀者請記得sorted()函式是產生一個新的排序的串列，別搞混喲！\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(NlogN)/O(1)，N為people的長度。\n如果是使用Java附上的參考解的話則是O(limit)/O(limit))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-01-17T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-110-array-16-greedy-algorithm-1/","title":"從LeetCode學演算法 - 110 Array (16) / Greedy Algorithm (1)"},{"content":"1640. Check Array Formation Through Concatenation (Easy)\n寫在前面 好久不見！筆者最近剛換了工作，\n所以比較忙一點XD 之後1月中會有HiSKIO 技術年貨節的活動，\n歡迎大家拿著折價券來修從LeetCode學演算法的課程喲！\n如果預算不夠，相信這108篇也還是很夠讀者練習的啦XDD\n在更之後還有規劃0元挑戰賽的部分，\n只要修課後一定時間內成功錄取新工作 ，\n課程就會全額退費喲！ 這部分再請留意官方那邊的公告，\n如果有開始的話，文章中也會再提醒各位。\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\nQuestion You are given an array of distinct integers arr and an array of integer arrays pieces, where the integers in pieces are ** distinct**. Your goal is to form arr by concatenating the arrays in pieces ** in any order**. However, you are ** not** allowed to reorder the integers in each array pieces[i].\nReturn true if it is possible to form the array arr from pieces. Otherwise, return false.\nExample 1 1 2 Input: arr = [85], pieces = [[85]] Output: true Example 2 1 2 3 Input: arr = [15,88], pieces = [[88],[15]] Output: true Explanation: Concatenate [15] then [88] Example 3 1 2 3 Input: arr = [49,18,16], pieces = [[16,18,49]] Output: false Explanation: Even though the numbers match, we cannot reorder pieces[0]. Example 4 1 2 3 Input: arr = [91,4,64,78], pieces = [[78],[4,64],[91]] Output: true Explanation: Concatenate [91] then [4,64] then [78] Example 5 1 2 Input: arr = [1,3,5,7], pieces = [[2,4,6,8]] Output: false Constraints 1 \u0026lt;= pieces.length \u0026lt;= arr.length \u0026lt;= 100 sum(pieces[i].length) == arr.length 1 \u0026lt;= pieces[i].length \u0026lt;= arr.length 1 \u0026lt;= arr[i], pieces[i][j] \u0026lt;= 100 The integers in arr are distinct . The integers in pieces are distinct (i.e., If we flatten pieces in a 1D array, all the integers in this array are distinct). 分析/解題 給定一個陣列arr，當中有不同的整數們，\n以及另一個整數陣列的陣列pieces(好饒口XD)，\n當中所有的pieces中的整數也都是相異的，\n我們的目標就是要將pieces拼接成arr，\n但pieces中要怎麼接順序都沒關係，\n但每一個pieces中的子陣列中的順序不可以被調換 。\n(例如arr = [15,88], pieces = [[88],[15]]，\n可以先拚[15]再拚[88]從而組出arr，可回傳true；\n但arr = [49,18,16], pieces = [[16,18,49]]的話，\n因為[16,18,49]內不能夠調換順序，所以只能回傳false)\n如果拚得起來就回傳true，否則回傳false。\n條件限制：\narr的長度和pieces的長度均為1~100之間(後者小於前者)。 pieces的所有子陣列長度總和，和arr陣列長度相等。 arr和pieces的所有子陣列中的元素值均在1~100之間。 arr中的所有整數均為相異。 pieces中的所有整數均為相異。 根據條件限制的部分，我們可以簡單得到，\n反正要能對上的話，因為總個數剛好相等，\n所以不存在第二種對應方式 ！\n既然不存在第二種對應的方式，\n那麼我們在arr中看到一個開頭時，\n我們應該只要在pieces中找那個值 ，\n就知道該對上pieces中的那一個子陣列囉！\n那麼，我們該怎麼樣去找對應呢？\n每次都掃過一輪去找，時間複雜度感覺會很糟糕，\n那麼，想要迅速的找到對應的位置，\n我們就會想到利用HashTable的概念。\n因此，在Java使用HashMap，Python中則使用dictionary，\n就可以讓我們使用O(1)的複雜度進行存取(不過前面要先花O(N)來存喲！)\n這邊我們可以選擇將每個(pieces[i][0], i)的對應存入，\n這樣在搜尋時，我們就知道接下來要拚入哪一組子陣列囉！\n接著我們需要遍歷整個arr，\n每次先拿第一個值去搜尋到對應的pieces，\n接著依序一個一個去對照兩邊的值是否相等。\n如果找不到對應或者是值不相等，就表示無法對應成功囉！\n(可以直接回傳false)\n如果全數拚完都沒問題，自然就可以回傳true。\n依此，寫成程式碼如下：\nJava Java的部分，我們使用HashMap來記錄， 記得使用put(key, value) 的形式！\n(因為沒有重複的問題，所以也不需要檢查)\n接著我們利用cnt來進行遍歷的紀錄，\n這邊不要忘記先檢查 能不能找到arr[cnt]啊！\n(因為有可能找不到，直接用get會有exception的！)\n另外，由於get出來是Integer，\n這邊我們使用(int)來將其轉型回一般的int 。\n其他就依序處理即可。\nPython Python的部分，字典和list的操作方式差不多，\n不過還是不要忘記先檢查喲！\n另外對初學的讀者提醒一下，\nPython中沒有++或\u0026ndash;這種方便的遞增/遞減方式 ，\n所以請乖乖使用cnt += 1或cnt = cnt + 1 。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(pieces的子陣列個數，最大為N))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-01-08T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-109-array-15-hash-table-11/","title":"從LeetCode學演算法 - 109 Array (15) / Hash Table (11)"},{"content":"1379. Find a Corresponding Node of a Binary Tree in a Clone of That Tree (Medium)\n寫在前面 好久不見！筆者最近剛換了工作，\n所以比較忙一點XD 之後1月中會有HiSKIO 技術年貨節的活動，\n歡迎大家拿著折價券來修從LeetCode學演算法的課程喲！\n如果預算不夠，相信這108篇也還是很夠讀者練習的啦XDD\n在更之後還有規劃0元挑戰賽的部分，\n只要修課後一定時間內成功錄取新工作 ，\n課程就會全額退費喲！ 這部分再請留意官方那邊的公告，\n如果有開始的話，文章中也會再提醒各位。\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\nQuestion Given two binary trees original and cloned and given a reference to a node target in the original tree.\nThe cloned tree is a copy of the original tree.\nReturn a reference to the same node in the cloned tree.\nNote that you are ** not allowed** to change any of the two trees or the target node and the answer ** must be** a reference to a node in the cloned tree.\nFollow up: Solve the problem if repeated values on the tree are allowed.\nExample 1 1 2 3 Input: tree = [7,4,3,null,null,6,19], target = 3 Output: 3 Explanation: In all examples the original and cloned trees are shown. The target node is a green node from the original tree. The answer is the yellow node from the cloned tree. Example 2 1 2 Input: tree = [7], target = 7 Output: 7 Example 3 1 2 Input: tree = [8,null,6,null,5,null,4,null,3,null,2,null,1], target = 4 Output: 4 Example 4 1 2 Input: tree = [1,2,3,4,5,6,7,8,9,10], target = 5 Output: 5 Example 5 1 2 Input: tree = [1,2,null,3], target = 2 Output: 2 Constraints The number of nodes in the tree is in the range [1, 10^4]. The values of the nodes of the tree are unique. target node is a node from the original tree and is not null. 分析/解題 給定兩個二元樹 original 跟 cloned ，\n並給定一個 originl 樹上的參考節點 target，\n當中，cloned是original的完全複製，\n請找到 cloned 上和 target 相對應的相同節點回傳。\n留意兩棵樹上的節點都不允許被改變，\n且答案必須要是cloned這棵樹上的對應節點。\n(而不是original上的或新作出來的節點)\n條件限制：\n樹上的總節點數量範圍在1到10⁴之間。 樹上的各節點值均為獨一無二 的。 target是original這棵樹上的節點，且不為null。 後續：如果重複值可被允許，嘗試在這個條件下解決問題。\n這題雖然標為Medium，但說實在的不難XD\n看完題目以後，已經經歷過前面各種難題的讀者，\n應該會直覺想到使用DFS來解決。\n那麼，由於題目一開始已經給定說值是全部獨一無二。\n如果先不計較Follow up的部分，\n其實我們可以直接比較值就可以了！\n我們可以直接將target的值當作目標，\n並且對於cloned這棵樹進行dfs，只要比較到相同的值，\n就可以進行回傳啦！\n由於1的關係，我們不用擔心使用遞迴會超過call stack限制，\n使用一個helper函式，當遇到null/None時，\n回傳null/None，接著檢查所在節點值是否和target的值相同 ；\n接著分別dfs往左邊和往右邊的樹進行尋找 。\n當左邊已經找到時，我們可以不用再檢查右邊的部分 ，\n直接回傳得到的節點；否則當右邊有找到時，回傳右邊得到的節點 ；\n當右邊也沒有找到時，則回傳null/None 。\n那麼，如果節點值不一定獨一無二呢？\n那麼我們就要同時也將original一起進行遞迴，\n這時候檢查的就是original上歷經的節點是否是target節點，\n在檢查到的時候同時去回傳cloned的對應節點。\n這時候我們用來檢查相等的就是記憶體位址，而非節點值 。\n因為唯有記憶體位址相同時，能保證這個節點是對應位置的那個節點。\n(而非只有裡面的值相同)\n依此，我們寫成程式碼如下：\nJava Java的部分我們額外提供了LeetCode上Follow Up的解法在註解，\n使用相同的做法，應該也可以寫出Python的方法，\n讀者可以自行嘗試看看。\nPython Python的部分，請讀者留意，\n對Python而言，我們寫n: TreeNode, v: int這樣的格式，\n是寫給人看的 XD，讀者也可以完全都不寫，一樣可以執行。\n而且對於使用者來說，就算你將v代成不是int的東西，\n也不會直接被Python視為錯誤，\n並不像Java或其他程式語言那樣對這邊有型別檢查，\n這點請務必留意喲！\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，基本上最差的狀況要遍歷整棵樹，\n而空間上要計較Call Stack的話，則會跟樹的深度成正比，\n除此以外沒有其他額外和N相關的部分)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2021-01-03T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-108-tree-20-dfs-17/","title":"從LeetCode學演算法 - 108 Tree (20) / DFS (17)"},{"content":"1544. Make The String Great (Easy)\n好久不見啦！最近筆者比較忙碌，還請多多見諒XD\n寫在前面 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\nQuestion Given a string s of lower and upper case English letters.\nA good string is a string which doesn’t have two adjacent characters s[i] and s[i + 1] where:\n0 \u0026lt;= i \u0026lt;= s.length - 2 s[i] is a lower-case letter and s[i + 1] is the same letter but in upper-case or vice-versa . To make the string good, you can choose two adjacent characters that make the string bad and remove them. You can keep doing this until the string becomes good.\nReturn the string after making it good. The answer is guaranteed to be unique under the given constraints.\nNotice that an empty string is also good.\nExample 1 1 2 3 Input: s = \u0026#34;leEeetcode\u0026#34; Output: \u0026#34;leetcode\u0026#34; Explanation: In the first step, either you choose i = 1 or i = 2, both will result \u0026#34;leEeetcode\u0026#34; to be reduced to \u0026#34;leetcode\u0026#34;. Example 2 1 2 3 4 5 Input: s = \u0026#34;abBAcC\u0026#34; Output: \u0026#34;\u0026#34; Explanation: We have many possible scenarios, and all lead to the same answer. For example: \u0026#34;abBAcC\u0026#34; --\u0026gt; \u0026#34;aAcC\u0026#34; --\u0026gt; \u0026#34;cC\u0026#34; --\u0026gt; \u0026#34;\u0026#34; \u0026#34;abBAcC\u0026#34; --\u0026gt; \u0026#34;abBA\u0026#34; --\u0026gt; \u0026#34;aA\u0026#34; --\u0026gt; \u0026#34;\u0026#34; Example 3 1 2 Input: s = \u0026#34;s\u0026#34; Output: \u0026#34;s\u0026#34; Constraints 1 \u0026lt;= s.length \u0026lt;= 100 s contains only lower and upper case English letters. 分析/解題 給定一個字串s，當中含有大小寫的英文字母，\n一個好的字串被定義為對於 0 ≤ i ≤ s.length - 2 來說，\n兩個相鄰的字元s[i]和s[i+1]不會含有相同字母但大小寫相反的狀況，\n例如aA, Cc這種型式。\n要讓字串變好，可以透過每次拿掉兩個相鄰且讓字串變壞的字元達到，\n最終得到一個好的字串。\n題目表示給定的題目一定有答案且必然是唯一的。\n(空字串也是好的字串)\n說起來這題的標題不禁讓人想到美國總統大選，\n不過到現在恐怕已經大勢底定了就是，\n這句話恐怕就要成為絕響了吧XD\n扯遠了，我們來看看這題。\n由於它已經保證會有唯一解，\n那麼相鄰字元的移除順序理論上並不會影響結果，\n所以直觀上好像可以每次掃過一遍字串，\n將大小寫相鄰的相同字母移掉就解決了\u0026hellip;\u0026hellip;嗎？\n但這麼做的話，我們會不知道要掃過幾次字串才能夠將所有問題移除完，\n因為比如碰到abBA 這樣子的字串，我們要將**’bB’** 移除掉，\n才會在下一次發現**’aA’** 可以移除。\n所以為求簡單起見，\n我們可以使用一個Stack 來存放已經檢查過的部分，\n每次放一個字元到Stack中，存放前將Stack最上面的那個字元，\n跟準備要放的字元做比較：\n兩者是相同字母且大小寫相反-\u0026gt;將Stack中最上面的字元pop掉\n兩者不需相消-\u0026gt;放入Stack\n這麼一來，我們就只會放沒有讓字串變壞的字元進到Stack，\n同時每次都會拿新的字元跟前面的比對，以排除掉應該移除的部分。\n那麼，怎麼算大小寫相反呢？\n除了用upper/lower case相關的函式外，\n在 ASCII Code 中，相同大小寫的字母的對應碼會恰巧差32。\n為什麼不是26? 因為中間還有帶一些標點符號。 Python中我們可以使用ord()來對一個字元取其ASCII Code值，\n而在Java中，我們可以視char為一個數字來進行加減運算，\n所以直接相加減就可以了。\n可能有讀者會問：\n「那我記不住32這個數字怎麼辦？」\n在寫的過程中，我們也可以用’a’和’A’的位置差算出來，\n注意**’a’對應的值是比較大** 的呦！\n所以可以將其寫成：\u0026lsquo;a\u0026rsquo; - \u0026lsquo;A\u0026rsquo; (Java)或 ord(‘a’)- ord(‘A’) (Python)\n你再問：\n「那我記不住哪個在前面怎麼辦？」\n呃……那你只好再加個絕對值 了！\n使用Math.abs() (Java) 或 abs() (Python)就可以囉！\n因此，流程大體如下：\n建立一個stack名為st 從字串s當中依序取出字元c，進行迴圈：\n2-1. 當st不為空，且最上面的值和c的值相差32 時，就對st進行pop\n2-2. 否則表示不需消除，將c推入st中(push) 完成迴圈後，將st的所有字元連起來得到的字串即為答案 依此，寫成程式碼如下：\nJava Java的部分，由於Java的Stack固定從尾端取出，\n最終使用StringBuilder進行組合完以後，toString之前記得要reverse，\n不然答案就會反掉囉XD！\n當然，也可以採用ArrayDeque來做，\n這樣就可以從頭排列到尾而不需要反轉。\n使用peek()可以幫助我們確認stack的最上面一個值是什麼，\n而不會將其取出，同時因不確定大小寫誰在前面，\n所以檢查時要記得取絕對值！\nPython Python這邊多加了一條判斷，但其實不影響，\n只是s的長度是1或0時都可以直接回傳就是了XD\n我們可以看到對於Python來說好處就是可以直接拿list當stack來使用，\n同時，使用join函式可以簡單地將list組成字串。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，N為字串長度。Java也可以使用CharAt(i)的型式來處理取出字元的部分，但不影響空間複雜度，因為後面還有其他要組的部分XD)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n想看看其他題目嗎？\n歡迎從第零篇 找你想要的！\n同時追蹤粉專以獲得更多新文章的通知：\n跟著Desolve學程式 另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-12-12T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-107-string-7-stack-2/","title":"從LeetCode學演算法 - 107 String (7) / Stack (2)"},{"content":"0563. Binary Tree Tilt (Easy)\n寫在前面 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\nQuestion Given the root of a binary tree, return the sum of every tree node\u0026rsquo;s *tilt *.\nThe tilt of a tree node is the ** absolute difference** between the sum of all left subtree node ** values** and all right subtree node ** values**. If a node does not have a left child, then the sum of the left subtree node ** values** is treated as 0. The rule is similar if there the node does not have a right child.\nExample 1 1 2 3 4 5 6 7 Input: root = [1,2,3] Output: 1 Explanation: Tilt of node 2 : |0-0| = 0 (no children) Tilt of node 3 : |0-0| = 0 (no children) Tile of node 1 : |2-3| = 1 (left subtree is just left child, so sum is 2; right subtree is just right child, so sum is 3) Sum of every tilt : 0 + 0 + 1 = 1 Example 2 1 2 3 4 5 6 7 8 9 10 Input: root = [4,2,9,3,5,null,7] Output: 15 Explanation: Tilt of node 3 : |0-0| = 0 (no children) Tilt of node 5 : |0-0| = 0 (no children) Tilt of node 7 : |0-0| = 0 (no children) Tilt of node 2 : |3-5| = 2 (left subtree is just left child, so sum is 3; right subtree is just right child, so sum is 5) Tilt of node 9 : |0-7| = 7 (no left child, so sum is 0; right subtree is just right child, so sum is 7) Tilt of node 4 : |(3+5+2)-(9+7)| = |10-16| = 6 (left subtree values are 3, 5, and 2, which sums to 10; right subtree values are 9 and 7, which sums to 16) Sum of every tilt : 0 + 0 + 0 + 2 + 7 + 6 = 15 Example 3 1 2 Input: root = [21,7,14,1,1,2,2,3,3] Output: 9 Constraints The number of nodes in the tree is in the range [0, 104]. -1000 \u0026lt;= Node.val \u0026lt;= 1000 分析/解題 給定一個二元樹，試計算二元樹的每個節點的tilt(坡度)和。\n什麼是tilt呢?\n題目告訴我們，對於一個節點，\n其左子樹的和以及右子樹的和相減的絕對值，\n就稱為它的坡度(tilt)，當子樹不存在時，和則視為0。\n另外由於整個樹的總節點數已經被限定在0~104之間了，\n表示我們可以放心的用遞迴！\n那麼，我們該怎麼對每個節點算坡度呢？\n對於一個節點n，如果它不存在的話(NIL)，\n其坡度自然為0，且總和同樣為0 ；\n存在的話，我們必須先算出左子樹(n.left為根節點的子樹)和，\n以及右子樹(n.right為根節點的子樹)和，將兩者相減取絕對值，\n就是n的坡度。\n因此，我們可以使用一個dfs的函式來同時處理算子樹和，\n以及坡度的部分，整個dfs的概念應該會如下：\n若n為NIL，回傳0 將n.left代入dfs中，取得n.left的子樹和l 將n.right代入dfs中，取得n.right子樹和r 將|l-r|加到物件變數的答案res中 回傳l+r+n.val 留意到我們使用dfs的回傳一直都是回傳以n為根節點的子樹和，\n這個和我們要計算的坡度不同，所以必須要用一個res變數來儲存。\n在寫出dfs函式後，我們只需要初始化res，\n並且在主函式中呼叫dfs後，回傳res即可。\n依此，寫成程式碼如下：\nJava 對於Java而言abs在java.lang.Math函式庫中， 如果不是在LeetCode的編輯器的話，不要忘記自行import。\nPython Python的部分和Java大同小異，\n這邊採用將dfs寫成一個子函式，別忘記要宣告以後才能夠使用呦！\n此外，__init__並非一定要這樣使用，在class Solution中直接定義也沒問題。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(樹的深度)，最差則為O(N))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-11-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-106-tree-19-dfs-16/","title":"從LeetCode學演算法 - 106 Tree (19) / DFS (16)"},{"content":"Day 30 結語：少年啊，要忍耐，撐過熬過總算苦盡甘來 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247306\n終於是最後一天了！！！\n又來到了輕鬆聊的時間。\n坦白說這次的30天過得並不輕鬆，\n除了一些外務需要處理外，一開始也是從沒有存稿的狀態下開始的。\n每天被進度追著打的感覺實在是很累XD！\n寫這一系列文章的初衷，\n最初是因為看到自己的學生們，\n因為從LeetCode學演算法系列文章 找到了我，\n但很多卻是想要轉職但對Python不熟的同學。\n不，應該是說對於整個程式語言該從哪裡開始都不清楚。\n通常這樣的狀況下，我們會從各種巨X電腦、O成電腦，\n或各種線上學院開始先學基本的程式語言。\n問題來了：\n就算是同一家電腦甚至是資策會，\n一來學費挺貴的，二來師資有所落差，風格也各有不一，\n沒有人能保證自己一開始遇到的老師就是最適合自己的。\n所以，建構一個基礎 的系列文章教學，\n內容不要像X者歸來那樣子又厚又重，\n並且範例不要千篇一律讓讀者容易失去興趣，\n是一件非常重要的事情。\n如果拿這一系列文章和書籍相比，\n讀者可能會發現，有很多東西是被筆者略過的：\n例如我們沒有講到匿名函式(lambda function) ，\n也沒有講到namedtuple ；\n沒有講到pdf和xls的檔案處理，以及另一個數據分析的好用工具pandas ；\n沒有講到OpenCV (可能比PIL更容易被用到，而且支援跨平台)；\n沒有講到網路連線相關的模組 ；\n也沒有講到多執行緒/多處理程序(multi-threading/multi-processing) 。\n並不是它們不重要，而是筆者認為，\n對於初學者而言，重點不是每一個都聽過摸過，\n而是能先使用既有基本的東西，並且從它們當中，\n組合出自己想要的程式。\n在這個過程中，有遇到任何問題，\n就去查資料、文件檔，或者向人請教提問，\n將自己需要的知識不斷補足完善，這才是筆者希望看到的。\n讓我們簡單回顧一下這三十天學了什麼，\n以及再深入的話，可以再往哪個方向了解：\n1. Python的安裝 ，除了本文提到的方式外，\n另外還有Anaconda/pipenv等，\n對於需要架構乾淨的多個執行環境而言蠻重要的，\n同時也可以建構jupyter notebook，\n使用iPython的以方格為單位的執行。\n2. 變數、型態、運算子的部分，\n其實還有很多跟位元運算有關的處理以及技巧，\n如果在寫題目遇到跟bit相關的東西的時候會很常用；\n字串也帶有許多好用的方法可以運用，\n同時還有使用正規表達式(regular expression)來搜尋字串 的方法，\n這個比較易學難精，有興趣可以再深入了解。\n3. 進階的資料型態 ，記得我們的炸蝦嗎XD?\n字典、串列、集合、元組的應用相當廣泛，\n有一些東西和方法可能沒有詳列上去，\n讀者可以遇到狀況時先查查有沒有可以用的對應內建方法呦！\n4. 程式結構及語法 ，包含了if, for, while等，\n應該算是最基礎的東西了，這當中應該唯有搭配Except的部分比較特殊，\n再請多加留意。\n5. 例外處理和遞迴 ，有關遞迴的處理速度和記憶體問題，\n文章有更新一位在「程式人雜誌」社團的讀者提供的深入探討，\n讀者可以再行參閱。\n6. 模組與套件 ，關於其讀取的部分，其實有一些更細部的規則，\n若想要建構比較嚴謹的大型程式的話，請再搜尋相關的文章。\n7. 標準程式庫 ，其實還有很多很多很多XD，\n建議讀者可以參照著Python的官方文件，\n可以針對需求看有沒有自己需要的東西。\n8. 物件與類別，\n是所有物件導向程式語言(OOP, Object-Oriented Programming)\n當中很重要的一環，當中的概念請務必好好理解清楚，\n在使用時才不容易混淆。\n9. 檔案讀寫，\n除了一般文字檔、CSV、JSON外，\nXML/YAML也是常用的格式；除此之外，了解HTML的格式，\n將有利於有志朝網頁爬蟲相關技巧學習的讀者。\n若以爬蟲而言，beautifulsoup, scrapy, request, selenium 可能是重要的關鍵字。\n10. 日期時間、圖形處理、GUI介面等，\n都算是Python內建好用的模組，尤其對於Tkinter而言，\n也有很多其他的模組可以取代或者讓它變更好用。\n11. 其他常用的資料結構相關模組 ，可以搭配著演算法學習，\n效果會更好，最好搭配筆者的從LeetCode學演算法系列XD\n12. 科學運算、繪圖及深度學習，\n是走向AI/資料科學的敲門磚，後續還有更多更深入的東西可以玩的，\n有興趣的讀者若想要走AI相關領域，\n建議可以從吳恩達/李宏毅/林軒田等大師的機器學習課程開始，\n如果想要先了解一點基礎簡單的深度學習框架，\n閱讀莫煩Python的系列教學也不錯！\n13. 其他沒有提到的如Python+Flask(前端)，\nPython+SQLite/MongoDB/Redis(後端)等，\n如果讀者扎扎實實地經過這三十天的練習，\n應該會擁有進一步透過網路文章資源來學習這些的能力，\n就再請大家針對需求去搜尋囉！\n除此以外，每天的副標題 ，\n其實都跟當天要講的內容有關聯性，\n並不單純只是梗或者是歌詞而已，\n若讀者可以有效地將文章內容和副標題連結上 ，\n相信能更理解文章所要表達的內容。\n最後，不免幫自己工商一下：\n筆者目前除了從LeetCode學演算法的線上課程外，\n也和幾位朋友成立一個團隊，名為Chill Cat(去憂貓) ，\n當前正在鑽研AI輔助心理諮商 的部分；\n同時我們也有經營有關AI智能化交易指標 的研究，\n(可以是MetaTrader ，也可以是別的XD)\n以及協助企業評估/導入AI或自動化 的可能。\n歡迎有興趣合作或委託開發的諮商師、心理師，\n以及公司行號和我聯絡。\n來信請寄：bbsc.aiteam@gmail.com 。\n平常的時候，若對於LeetCode解題感興趣，\n還是可以在FB的Python Taiwan社團 ，\n或我的Medium上看到我！\n也可以來追蹤我的粉專：跟著Desolve學程式，\n裡面會不定時分享一些程式相關的文章或資訊呦！\n感謝大家的收看，那我們明年……\n等一下，先不要，先不要XD\n我再考慮看看啦XDDD!\n就這樣，掰掰~\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\n","date":"2020-10-15T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-30-epilog/","title":"從零開始學Python (30) — 結語：少年啊，要忍耐，撐過熬過總算苦盡甘來"},{"content":"Day 29 打包安裝PyInstaller：誰把誰的靈魂，裝進誰的身體 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247305\n因為按照慣例，第三十天主要會講比較偏向結論性質的東西，\n包含接下來可能的學習方向以及建議，\n所以讓我們今天用PyInstaller來做技術方面的最後一章，\n恭喜各位讀者，這系列如果都有扎實的跟上的話，\n應該能對Python有一些基本的認識。\nPyInstaller是一個用來打包安裝Python檔案的函式庫，\n一般狀況下，使用pip可以輕鬆將其安裝：\n1 pip install pyinstaller 為什麼我們會需要PyInstaller呢?\n一般狀況下有幾個可能：\n你不想直接讓別人看到程式碼(註：但會破解的還是做得到XD) 你在開發過程中用了一些函式庫，\n這些函式庫並非內建的，從而別人要用你的.py檔執行的話，\n會需要進行其它的pip install或準備工作。\n這樣很麻煩很不方便，\n你希望拿到的人最好可以滑鼠點兩下就可以執行才對XD 這時候使用PyInstaller就可以達成這樣的目的，\n除了可以給定簡單的加密外(防君子的那種)，\n它還可以將整個程式連同用到的函式庫一起打包成執行檔！\n我們這邊使用前面的tkinter的範例，\n讀者應該會用到的檔案就是fromzero.py和unicorn.ico，\n還沒做過的同學，請參照Day 22的範例及Day 23的修改部分。\n為了測試，\n我們再手動加上一個其實我們沒有在這個範例使用的numpy，\n請在fromzero.py中額外加入這行：\n(因為它是額外pip安裝的，藉此我們可以觀察一下差異)\n1 import numpy as np PyInstaller的使用方式是直接在命令提示字元下指令，\n使用pyinstaller -h可以查看help提示：\n1 2 pyinstaller -h ...密密麻麻的一大堆XD 我們簡單介紹一下幾個常用的參數部分：\n(前面和後面是相同的效果，只是使用縮寫)\n-h, — help ：顯示help提示說明各參數用法\n-F, — onefile ：打包成單一一個執行檔\n-D, — onedir (預設) ：打包成一個資料夾，內含一個執行檔\n-y, — noconfirm ：\n— clean ：清空前面打包時產生的暫存檔案\n-n NAME, — name NAME ：將NAME做為app名字並命名到執行檔\n(預設會是主程式原先的主檔名 )\n— add-data \u0026lt;SRC;DEST or SRC:DEST\u0026gt; ：\n將非二進位檔案加到打包中，\nSRC對應原先的檔案，DEST對應打包後放的相對資料夾位置\n-p DIR, — paths DIR ：如果有額外需要import的函式庫時，\n告訴pyinstaller可以去DIR這個位置搜尋\n— key KEY ：用key來加密Python的bytecode\n-w, — windowed, — noconsole ：在Windows執行時隱藏命令提示字元的視窗\n那麼，我們先試試看最基本的打包：\n1 2 C:\\Users\\Desolve\\utils\u0026gt;pyinstaller --noconfirm fromzero.py ...底下會開始打包 在預設的狀況下，會產生幾個目錄：\npycache(主程式編譯的bytecode檔),\nbuild(編譯過程中產生的檔案),\ndist(最終執行所需要的執行檔及其他資料)\n我們切換到dist\\fromzero的資料夾以後，\n應該可以看到fromzero.exe，以及其它的一些檔案及資料夾，\n當中就包含了tk和numpy，\n顯然pyinstaller自動幫我們評估將函式庫給包進來了！\n那麼，在命令提示字元打fromzero.exe，\n或者在資料夾中連點兩下就可以執行了……咦？\n1 2 3 4 5 6 C:\\Users\\Desolve\\utils\\dist\\fromzero\u0026gt;fromzero.exe Traceback (most recent call last): File \u0026#34;fromzero.py\u0026#34;, line 41, in \u0026lt;module\u0026gt; File \u0026#34;tkinter\\__init__.py\u0026#34;, line 2071, in wm_iconbitmap _tkinter.TclError: bitmap \u0026#34;unicorn.ico\u0026#34; not defined [12564] Failed to execute script fromzero 顯然我們的獨角獸並沒有被包進去，\n由於前面我們讀取檔案時，是在和.py相同的資料夾，\n所以我們可以將unicorn.ico複製到dist\\fromzero的資料夾 ，\n就可以正常執行了。\n當然這顯然不是很理想，所以讓我們回到上一步，\n處理一下圖片的部分。\n我們先用以下的方式，將unicorn.ico轉成二進位制，\n再存到一個.py檔做為變數img：\n(註：參考自CSDN blog)\n(如果是一般檔案，則可以使用 — add-data=’SRC;DEST’的方式即可)\n1 2 3 4 5 6 7 8 9 \u0026gt;\u0026gt;\u0026gt; import base64　# base64可以將binary檔案轉成unicode格式 \u0026gt;\u0026gt;\u0026gt; icon = open(\u0026#39;unicorn.ico\u0026#39;, \u0026#39;rb\u0026#39;) # 使用binary的格式讀入icon \u0026gt;\u0026gt;\u0026gt; b64str = base64.b64encode(icon.read()) # 轉成unicode格式 \u0026gt;\u0026gt;\u0026gt; icon.close() \u0026gt;\u0026gt;\u0026gt; write = \u0026#39;img = %s\u0026#39; % b64str # 放到名為img的變數 \u0026gt;\u0026gt;\u0026gt; f = open(\u0026#39;icon.py\u0026#39;, \u0026#39;w+\u0026#39;) # 寫到icon.py中 \u0026gt;\u0026gt;\u0026gt; f.write(write) 6097 \u0026gt;\u0026gt;\u0026gt; f.close() 此時資料夾中會多出一個icon.py，\n裡面就是img=”……”的格式。\n接著我們要修改我們的fromzero.py，\n從讀取原本的icon，改成從icon.py取得變數：\n1 2 3 4 5 6 7 8 9 10 11 12 13 from icon import img # 從icon.py中取得img變數 import base64 # 同樣需要base64函式庫 # 主視窗生成 win = tk.Tk() win.title(\u0026#39;從零開始學Python：第二件X折？\u0026#39;) win.geometry(\u0026#39;800x220\u0026#39;) win.resizable(False, False) # 加上icon ico = open(\u0026#39;unicorn.ico\u0026#39;, \u0026#39;wb+\u0026#39;) ico.write(base64.b64decode(img)) # 寫一個icon出來 ico.close() win.iconbitmap(\u0026#39;unicorn.ico\u0026#39;) # 將icon嵌上視窗 os.remove(\u0026#39;unicorn.ico\u0026#39;) # 把剛剛用完的檔案刪掉 我們在重新下一次指令：\n1 C:\\Users\\Desolve\\utils\u0026gt;pyinstaller fromzero.py -F -y -w 這時候應該同樣可以在dist資料夾看到fromzero.exe，\n且由於我們下了-w，所以執行時後面不會出現命令提示字元了！\n如果要進行簡單加密的話，\npyinstaller預設是使用tinyaes：\n1 pip install tinyaes 安裝後，打包時額外加上 — key=”(16個字元的字串)”即可，\n少掉的字元會補0。\n例如：\n1 2 3 4 5 6 7 8 9 10 11 C:\\Users\\Desolve\\utils\u0026gt;pyinstaller fromzero.py -F -y -w --key=\u0026#34;XDDD3096\u0026#34; 61 INFO: PyInstaller: 4.0 62 INFO: Python: 3.8.5 62 INFO: Platform: Windows-7-6.1.7601-SP1 64 INFO: wrote C:\\Users\\Desolve\\utils\\fromzero.spec 66 INFO: UPX is not available. 68 INFO: Extending PYTHONPATH with paths [\u0026#39;C:\\\\Users\\\\Desolve\\\\utils\u0026#39;, \u0026#39;C:\\\\Users\\\\Desolve\\\\utils\u0026#39;] 77 INFO: Will encrypt Python bytecode with key: 00000000XDDD3096 77 INFO: checking Analysis ...(以下省略) 如果你覺得這樣子還不夠放心，\n可以再透過obfuscator或PyArmor之類的軟體，\n將主程式進行混淆以後再打包，\n效果會更好呦XD！\n最後要留意一點，\n如果想要編譯出能在32位元的電腦運行的程式，\n則需要使用32位元版本的Python才可以。\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\n","date":"2020-10-14T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-29-packaging-installation-pyinstaller/","title":"從零開始學Python (29) — 打包安裝PyInstaller：誰把誰的靈魂，裝進誰的身體"},{"content":"Day 28 深度學習Keras：如果你能預知這條路的陷阱，我想你依然錯得很過癮 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247304\n接下來讓我們來聊聊Python在深度學習的部分。\n事實上很多iT邦幫忙的神人們在AI \u0026amp; Data組應該都有介紹到深度學習，\n可能是使用Tensorflow, PyTorch或Keras。\n本篇的重點不是要一篇打各路大神們的三十篇，\n而是要簡單介紹一下AI及深度學習的概念，\n給大家做一個入門，後續要再深入的話，就可以再去參考更多其它的學習資源。\n那麼，我們先聊聊什麼是AI。\n人工智慧(Artificial Intelligence)，\n過往是源自於一些根本的假設以及傳說所揉合而成。\n人類對於機器人有一些想像，想像我們可以做出人造人，\n這樣的機器人具備自我思考的能力，因而可以透過不斷的思考和選擇達到進化；\n同時加上了中古時期對於鍊金術的想像：將意識賦予至無生命的物質當中。\n綜合以上，因而我們對於一個AI的想法，\n大體上不外乎是以「它會思考」這個角度來出發。\n那麼，怎麼樣才算是會思考呢？\n有一位電腦科學家圖靈(Alan Mathison Turing)，\n提出了一個著名的測試方式：圖靈測試。\n圖靈測試簡單來說，就是讓一個人(A)，\n分別去跟兩個不同的對象(B、C)交談，\n過程中只透過文字，\nA不會看到B、C的模樣或聽到聲音；\n最終交談完畢以後，\n由A來判斷B、C是否有實質的不同，或者說誰更像是人。\n如果有一個機器比另一個人讓A更覺得它像人的話，\n即通過圖靈測試。\n這樣子的測試後來衍生出很多很有趣的例子，\n例如有個名為Eliza的聊天機器人，\n會將對方講出來的句子分析其主詞及關連性，\n針對當中的關鍵字詞來回答；\n或者它也會做一些重組，再拿你講過的話來回答你XD！\n而這種模式和人互動下，反而很多人會以為Eliza懂他/她，\n殊不知完全掉入了程式設計師的陷阱XD\n扯遠了，讓我們拉回來談AI。\n我們近幾十年在拿AI這個詞來描述事物時，\n其概念和範圍其實也是不斷在變動的。\n以比較之前的看法來說，AI通常會被當做是：\n使用確定的規則判斷，使得機器得以按照這個規則去運作，\n從而在某些方面表現出像是人類在做思考判斷一樣。\n比如電腦遊戲中玩家操縱的角色跟NPC對話時，\nNPC會依照它的「人設」(也就是遊戲開發者原先對其的設定)，\n以及當前的一些條件狀況，對玩家做出回應。\n當然，我們可以很輕易地看出這是寫好的規則判斷，\n原因就是這個NPC可能講沒幾句話就重複循環，\n或者是一直要你去打10隻母雞回來交任務XD\n再比方說過往的圍棋或象棋軟體，\n甚至打敗過西洋棋棋王的電腦「深藍」，\n也都脫離不開使用寫好的規則來計算下一步的範疇，\n這樣子的AI，我們將其稱為rule-based AI。\n按規則走的優點是，\n當事情是確定的，且符合過往能歸納的範疇，\n那麼機器處理的能力就會非常好。\n缺點當然就是一旦遇上沒有被界定的情況，\n那機器就會不知道該怎麼辦了XD!\nAI在經歷過幾次興起以及幾次寒冬以後，\n得益於GPU性能的提升，能加速大量的平行化運算的矩陣運算的原因，\n深度學習(Deep Learning)在近年來興起了。\n深度學習所建立的AI，和以往以規則為出發的AI不同，\n它主要是透過所謂的人工神經網路(Artificial Neural Network, ANN)，\n在建立起一個結構以後，透過不斷地輸入資料，\n輸出結果，檢查結果與正確答案的差距，再對神經網路各自的權重(weight)做修正，\n最終讓每次的輸入所得到的輸出結果，能接近正確答案。\n舉例來說：\n假設讀者的面前有一棵樹，\nrule-based的做法會是：\n「這邊有樹枝，這邊有樹葉，中間有枝幹連接，\n它們的顏色在XX~OO之間，所以這是一棵樹」\n深度學習的做法則是：\n「反正這就是一棵樹就對了！不知道？沒關係，\n我多帶你看幾個：A這個是樹，B這個不是樹，\n……好，那你這樣應該可以分辨樹了對吧？」\n深度學習在神經網路的類型的這塊，\n相對比較像人類的小孩子在學習一樣，\n透過不斷的歸納，最終小孩子在心裡面產生一套分辨方式，\n這個分辨方式可能說得出來，可能說不出來，\n但最終他/她就是會講得出「這是一棵樹，這是車車」這樣子的分類。\n上面提到的深度學習的方式，\n在具體到人工神經網路上狀態又是怎麼樣的呢？\n比較粗略的來說，\n人工神經網路是由神經元(neurons)彼此以突觸連接而成的，\n不同的突觸，傳遞相同的訊號時會產生不同的強弱變化，\n通常我們稱之為權重(weights)。\n如同剛剛所說的，\n我們會透過檢查正確答案和目前機器輸出的答案的差距，\n來修正權重，最常見的方式，\n就是使用反向傳播(backpropagation, BP) ，\n加上梯度下降法(gradient descent)或其他算法 ，\n來盡力收斂和正確答案的差距。\n這個改善神經網路的過程我們通常稱之為模型訓練(model training)\n那麼，接下來談談Keras。\nKeras原本是一個用於快速開發深度神經網路的框架，\n立基於各項比較常見的框架之上，\n例如TensorFlow(Google Brain團隊所開發), Theano, PlaidML等。\n但近年來最主要的支援是放到了TensorFlow上面，\n同時TensorFlow也主動將Keras的函式庫納入到其中，\n我們接下來的範例會基於TensorFlow上的Keras來操作。\n如果在自己的電腦上想安裝TensorFlow/Keras的話，\n可以參考官網：\nhttps://www.tensorflow.org/install/pip?hl=zh_tw\n請留意，如果是要用到gpu的話，\n你必須要安裝的是tensorflow-gpu。\n由於不是每個人的家裡的GPU都很精良，\n所以下面我們主要會介紹如何跟著TensorFlow上的官網提供的colab範例來做。\n下面我們會一步步帶各位走過最基本的範例：Fashion MNIST的分類，\n請從Basic classification: Classify images of clothing\n找到Run in Google Colab 並將其打開。\n在Colab的網頁中，\n當看到”[ ]”的格子時，\n代表一組可以執行的程式碼，\n滑鼠移動到上面，會顯現播放鍵，\n只要按下去就會執行一次。\n執行完後顯示的數字代表它已經被執行過了，\n且是第幾個被執行的格子。\n首先我們看到前導的部分：\n我們要使用到的一般會有tensorflow本身以及keras，\n所以要進行import，同時，前面我們提過的numpy以及matplolib也都會用到，\n讓我們一起導進來。\n1 2 3 # TensorFlow and tf.keras import tensorflow as tf from tensorflow import keras 1 2 3 # Helper libraries import numpy as np import matplotlib.pyplot as plt 1 print(tf.__version__) # 印出當前tensorflow的版本，目前是2.3.0 再來，我們要匯入一組資料集(dataset)。\n資料集一般是指針對特定目標或種類收集整理而成的資料，\n一些比較代表性的資料集如Cifar-10, MNIST, ImageNet等，\n依照使用的狀況不同，有些會被拿來當成基本教學範例，\n有些則是會被拿來當成評估訓練方法好不好的標準。\n以Fashion MNIST來說，\n就是一個在MNIST(手寫0~9的圖形資料集)被用到太無聊的狀況下，\n可能打算換換口味才換過來的資料集XD。\nFashion MNIST當中有7萬張灰階圖，\n內容是10種不同的服飾，如鞋子、包包、衣服、褲子等。\n以這個範例來說，我們的目的，\n就是訓練出一個能夠良好地辨認出一張圖片是哪個種類的服飾的模型。\n我們要將Fashion MNIST下載後，分為用來訓練的資料，以及用來測試用的資料 ：\n為什麼要分呢？因為如果全部都拿來訓練的話，\n那麼在測試這個訓練結果時，我們怎麼知道說，\n這個模型(model)回答的好，是因為它真的懂了，\n還是是因為背熟考古題呢XD？\n畢竟我們是希望它找出一個自己能夠辨別的標準，\n而不是背答案。\n這邊的label(標籤)，指的是該張圖片，是屬於這個資料集的第幾類，\n這樣到時候訓練時才能夠知道模型有沒有找錯。\n1 fashion_mnist = keras.datasets.fashion_mnist 1 (train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data() 在這個資料集中，我們標記為0的是T-shirt/top，\n1的是Trouser, 以此類推，將每個類別的名稱記錄下來。\n1 2 class_names = [\u0026#39;T-shirt/top\u0026#39;, \u0026#39;Trouser\u0026#39;, \u0026#39;Pullover\u0026#39;, \u0026#39;Dress\u0026#39;, \u0026#39;Coat\u0026#39;, \u0026#39;Sandal\u0026#39;, \u0026#39;Shirt\u0026#39;, \u0026#39;Sneaker\u0026#39;, \u0026#39;Bag\u0026#39;, \u0026#39;Ankle boot\u0026#39;] 接著檢查一下剛剛拿到的資料：\n1 2 3 4 5 train_images.shape # (60000, 28, 28) -\u0026gt; 60000張，每張像素是28x28 len(train_labels) # 60000 -\u0026gt; 對應的標籤當然就也是60000張 train_labels # array([9, 0, 0, ..., 3, 0, 5], dtype=uint8) -\u0026gt; 0~9的種類，共10種 test_images.shape # (10000, 28, 28) -\u0026gt; 10000張用來做為測試的圖像 len(test_labels) # 10000 -\u0026gt; 對應的標籤當然是10000 接著我們來預先處理一下資料，\n使用plt.imshow()可以將進行圖像繪製，\n我們就拿train_images[0]這張來看看：\n1 2 3 4 5 plt.figure() plt.imshow(train_images[0]) plt.colorbar() # 用來顯示灰階影像(0-255) plt.grid(False) plt.show() 通常我們要處理資料時，\n我們要將其標準化到01的範圍，\n這樣子才不會因為不同的資料的尺度(scale)不同，\n影響到模型的訓練或它們對於結果影響的比例。\n由於灰階影像的值是0255，所以我們可以選擇全數除以255.0來等比例縮小，\n接著再取前25張圖來檢查處理過的資料是否正常仍可顯示：\n1 2 train_images = train_images / 255.0 test_images = test_images / 255.0 1 2 3 4 5 6 7 8 9 plt.figure(figsize=(10,10)) for i in range(25): plt.subplot(5,5,i+1) # 5*5的排列方式 plt.xticks([]) plt.yticks([]) plt.grid(False) plt.imshow(train_images[i], cmap=plt.cm.binary) # 範圍0~1時要選binary plt.xlabel(class_names[train_labels[i]]) # 在x軸的位置顯現分類名 plt.show() 接下來是模型的部分。\n要訓練模型之前，首先我們要先將模型的神經網路建構起來，\n通常狀態下神經網路是以層(layer)為單位，\n層與層彼此之間進行連接，多個層最終構成一個神經網路。\nSequential: 代表前面的往後面的承接\nFlatten: 代表將輸入的東西攤平成一維(28*28=784)\nDense: Dense layer又稱全連接層，也就是像握手一樣，\n上一層的每個神經元和這層的神經元的每一個組合都有連接到\nactivation: 激勵函式(activation function)，簡單來說，\n就是一個讓整個神經連接呈現不是線性的狀態。\n因為若是一個模型可以用很簡單的公式或者線性可表達的函數算出來，\n這樣子的狀態不是深度學習所要的，因為如果一般的方式可以算的話，\n深度學習並沒有比較具備優勢。\n(其它目的還有避免過擬合或節省部分計算的考量，我們暫且不深入探討)\n1 2 3 4 5 6 # 最後一層是10個神經元，目的就是剛好分成10類 model = keras.Sequential([ keras.layers.Flatten(input_shape=(28, 28)), keras.layers.Dense(128, activation=\u0026#39;relu\u0026#39;), keras.layers.Dense(10) ]) 完成一個模型後，我們要進行compile的動作，\n將其它附帶的條件給加上。\nLoss function(損失函數)：用來評估說模型現在給出的答案和正確答案的差距的函式，\n這個可以有很多種類，這裡用的是用來衡量分類的SparseCategoricalentropy。\nOptimizer(優化器)：我們在修正時，不會直接將Loss給出來的差直接處理掉，\n而是會有一個評估要往哪個方向修正多少的方法做為基準。\n(因為這個點完全相等並不能代表另一個會表現好)\n除了adam以外，sgd, adagrad等都是常見的優化器。\nMetrics(指標)：在訓練的過程中我們會想看的中途狀況，\naccuracy是計算每次有正確被分類的圖片的比例。\n1 2 model.compile(optimizer=\u0026#39;adam\u0026#39;, loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=[\u0026#39;accuracy\u0026#39;]) 接下來就要開始訓練啦!\nKeras中是使用model.fit指令，意思是這個模型要盡力去符合實際的正確標準。\nepochs是代表以前面60000張圖片做為一整組的話，\n我們想要讓同一個組讓機器訓練過幾次。\n指令下了以後就會在下方看到進度條跑動，\n以這次訓練來說，\n目前訓練的準確度在最後一次是0.9100，也就是91%。\n1 model.fit(train_images, train_labels, epochs=10) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Epoch 1/10 1875/1875 [==============================] - 4s 2ms/step - loss: 0.5019 - accuracy: 0.8236 Epoch 2/10 1875/1875 [==============================] - 4s 2ms/step - loss: 0.3788 - accuracy: 0.8633 Epoch 3/10 1875/1875 [==============================] - 4s 2ms/step - loss: 0.3425 - accuracy: 0.8743 Epoch 4/10 1875/1875 [==============================] - 4s 2ms/step - loss: 0.3169 - accuracy: 0.8840 Epoch 5/10 1875/1875 [==============================] - 3s 2ms/step - loss: 0.2985 - accuracy: 0.8910 Epoch 6/10 1875/1875 [==============================] - 3s 2ms/step - loss: 0.2821 - accuracy: 0.8957 Epoch 7/10 1875/1875 [==============================] - 3s 2ms/step - loss: 0.2713 - accuracy: 0.8996 Epoch 8/10 1875/1875 [==============================] - 3s 2ms/step - loss: 0.2594 - accuracy: 0.9035 Epoch 9/10 1875/1875 [==============================] - 3s 2ms/step - loss: 0.2499 - accuracy: 0.9067 Epoch 10/10 1875/1875 [==============================] - 3s 2ms/step - loss: 0.2429 - accuracy: 0.9100 \u0026lt;tensorflow.python.keras.callbacks.History at 0x7f88189846a0\u0026gt; 但只會做考古題不算真本事，我們還得看看，\n這個模型測試沒看過的圖片時，準確度會是怎麼樣：\n我們將最終使用test的圖片來檢驗的動作稱之為evaluate(評定)。\n1 2 test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2) print(\u0026#39;\\nTest accuracy:\u0026#39;, test_acc) 1 2 # 結果是88.3%左右 313/313 - 0s - loss: 0.3400 - accuracy: 0.8827 1 Test accuracy: 0.8827000260353088 訓練好的模型，當然不應該只拿來檢查準確度，\n也要可以用來檢視新的圖片：\n一般狀況下，我們會使用一個softmax層來處理。\nsoftmax層能將一群輸入的值，按照一個分配方式壓縮，\n最終所有值都在0~1之間，且加總起來會剛好等於1，\n我們就拿這個輸出來做為判斷某個輸入的圖是什麼種類的機率有多少。\n1 2 3 4 5 6 # 連接softmax層 probability_model = tf.keras.Sequential([model, tf.keras.layers.Softmax()]) # 用predict方法來進行推論(inference) predictions = probability_model.predict(test_images) # 每一個predictions的元素當中包含了預測這個圖分別是種類0~9的機率值 predictions[0] 1 2 3 4 5 6 7 8 9 array([2.3251364e-07, 1.5796850e-08, 5.2541566e-07, 9.3214476e-09, 7.9444156e-08, 1.8098523e-03, 5.7661474e-08, 8.4252998e-02, 1.4421660e-07, 9.1393608e-01], dtype=float32) # 我們要取機率最高的當做是我們判斷它是哪一種類型 # 使用np.argmax，其結果看起來跟實際上的答案一致，代表有答對XD np.argmax(predictions[0]) 9 test_labels[0] 9 下面colab的範例也提供了兩個函式來提供視覺化的判斷，\n在此就不一一解釋：\n我們可以看到模型也是有答錯的時候XD：\n後面還有畫一整群圖片檢驗的對照圖，就請讀者自行參閱。\n最後，範例有提到說，因為前面的示範是一次放入10000張下去做predict，\n如果今天有一張單張的28x28灰階圖片，\n其實同樣可以拿來做predict呦！\n唯一的不同，就只是你要將這”一張”圖片，擴展成”一組”圖片，\n而這一組裡面就只有一張圖片的格式。\n1 2 3 4 5 6 img = test_images[1] # 拿第二張 print(img.shape) # (28, 28) img = (np.expand_dims(img,0)) # 擴展一個維度，讓它變成\u0026#34;一組\u0026#34; print(img.shape) # (1, 28, 28) predictions_single = probability_model.predict(img) # 現在可以predict了 print(predictions_single) 1 2 [[5.1490115e-05 9.7672521e-14 9.9936408e-01 2.5379993e-12 1.0796214e-04 6.6310263e-10 4.7655238e-04 2.3014628e-11 2.8894394e-08 5.6684479e-12]] 最終結果順利預測出該圖片是Pullover(套頭衫)。\n雖然從上到下講得相當長，\n但其實只是很粗淺的示範了一下最基礎的範例而已，\n深度學習除了圖像分類以外，\n從圖片到文字，再到聲音，各種應用可以說是包山包海；\n更不用說還有不同的模型建立方式與架構，\n今天的介紹連冰山一角都稱不上XD\n若讀者有更深入的興趣的話，可能就要從更基本的機器學習部分出發了！\n除此以外，若要自己進行深度學習的訓練的話，\n架構一個環境還是很有必要的，\n就再請讀者閱讀一下其他大大們的教學呦！\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-13T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-28-deep-learning-keras/","title":"從零開始學Python (28) — 深度學習Keras：如果你能預知這條路的陷阱，我想你依然錯得很過癮"},{"content":"Day 27 科學繪圖Matplotlib：畫著你，畫不出你的骨骼 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247303\n今天我們要來介紹的是Matplotlib，\n對於Python來說，是一套非常常用於科學繪圖的繪圖程式庫，\n同時也相當良好地支援了NumPy的陣列，\n此外，通常狀況下，只要設定恰當，\n也可以很順利地在一些帶有視窗運作的Python執行環境，\n如IPython, Jupyter Notebook, colab等直接內嵌繪製圖片，\n可以說是相當的方便！\n由於最初的目的是提供如同Matlab軟體的繪圖方式，\n所以常用Matlab的人可能會覺得很多東西似曾相識XD\n要使用matplotlib時，官方有提供pylab ，\n將matplotlib的pyplot和numpy合併在一起，\n但還是建議numpy歸numpy，pyplot歸pyplot 。\n同樣的，如果電腦還沒有matplotlib套件的話，\n請先使用pip install進行安裝。\n1 pip install matplotlib 接下來讓我們來介紹一些基本的功能。\n首先，我們要先將numpy和matplotlib的pyplot給import進來：\n1 2 import numpy as np import matplotlib.pyplot as plt 記得上一篇我們做過一個隨積分布的陣列嗎？\n如果我們想將其使用直方圖(Histogram)來表現出點的分布數量的話，\n可以使用plt.hist()，將陣列輸入給plt；\n同時，plt在繪製以後，要經過plt.show()的方法才會顯示出來。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 \u0026gt;\u0026gt;\u0026gt; mu, sigma = 0, 0.1 \u0026gt;\u0026gt;\u0026gt; s = np.random.normal(mu, sigma, 1000) \u0026gt;\u0026gt;\u0026gt; plt.hist(s) # 繪製直方圖，預設分成10組 (array([ 10., 32., 91., 164., 238., 216., 147., 71., 25., 6.]), array([-0. 30285466, -0.2403016 , -0.17774855, -0.1151955 , -0.05264245, 0.0099106 , 0.07246365, 0.1350167 , 0.19756975, 0.2601228 , 0.32267585]), \u0026lt;BarContainer object of 10 artists\u0026gt;) \u0026gt;\u0026gt;\u0026gt; plt.show() # 在直譯器的話可以按Ctrl+C回來或按X關掉plt視窗 \u0026gt;\u0026gt;\u0026gt; plt.hist(s, 30) # 第二個參數為30, 代表將值的範圍切分成30等份(預設則為10) (array([ 1., 4., 5., 8., 9., 15., 19., 25., 47., 46., 49., 69., 71., 79., 88., 87., 76., 53., 55., 55., 37., 40., 16., 15., 9., 9., 7., 4., 1., 1.]), array([-0.30285466, -0.28200364, -0.26115262, -0.24 03016 , -0.21945059, -0.19859957, -0.17774855, -0.15689754, -0.13604652, -0.1151955 , -0.09434449, -0.07349347, -0.05264245, -0.03179144, -0.01094042, 0.0099106 , 0.03076161, 0.05161263, 0.07246365, 0.09331467, 0.11416568, 0.1350167 , 0.15586772, 0.17671873, 0.19756975, 0.21842077, 0.23927178, 0.2601228 , 0.28097382, 0.30182483, 0.32267585]), \u0026lt;BarContainer object of 30 artists\u0026gt;) \u0026gt;\u0026gt;\u0026gt; plt.show() 應該可以看到接近如下的圖(前面是分10組，後面是分30組)：\n我們在繪圖時，如果一般使用畫線按座標的話，\n通常是以plt.plot(x, y, linewidth)的型式，\n此時就要剛好每個x的元素都對應到y的元素：\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; x = np.arange(1, 9, 2) \u0026gt;\u0026gt;\u0026gt; y = 2 * x \u0026gt;\u0026gt;\u0026gt; plt.plot(x, y, linewidth=1.5) # 這樣應該是y=2x的樣子 [\u0026lt;matplotlib.lines.Line2D object at 0x000000000BCCB220\u0026gt;] \u0026gt;\u0026gt;\u0026gt; plt.show() 請留意一點，由於Python的陣列預設從0開始，所以當我們只給一段座標時，\n會被當成y座標，且x會從0開始起算，以整數遞增：\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; plt.plot([1,2,3,4]) \u0026gt;\u0026gt;\u0026gt; plt.show() \u0026gt;\u0026gt;\u0026gt; plt.plot([1,2,3,4], [1,2,3,4]) # 留意X座標的變化! \u0026gt;\u0026gt;\u0026gt; plt.show() 以plt.plot的方式繪圖時，畫上去的圖被稱為figure，\nfigure的軸則是axes，可以用add_subplot(1,1,1)方法取用到，\n如果同時放多張子圖的話(1,1,1)代表第一張。\n(這不是很好解釋，如果一次只畫一張圖的話就不管它啦！)\n我們可以在繪製完圖以後再做額外的事情：\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; fig = plt.figure() \u0026gt;\u0026gt;\u0026gt; ax = fig.add_subplot(1,1,1) \u0026gt;\u0026gt;\u0026gt; ax.plot([1,2,3,4], [1,2,3,4]) [\u0026lt;matplotlib.lines.Line2D object at 0x000000000B540B80\u0026gt;] \u0026gt;\u0026gt;\u0026gt; ax.set_title(\u0026#39;Title\u0026#39;) # 表題 Text(0.5, 1.0, \u0026#39;Title\u0026#39;) \u0026gt;\u0026gt;\u0026gt; ax.set_xlabel(\u0026#34;label: x\u0026#34;) # X軸文字 Text(0.5, 0, \u0026#39;label: x\u0026#39;) \u0026gt;\u0026gt;\u0026gt; ax.set_ylabel(\u0026#34;label: y\u0026#34;) # Y軸文字 Text(0, 0.5, \u0026#39;label: y\u0026#39;) \u0026gt;\u0026gt;\u0026gt; fig.suptitle(\u0026#39;Sup Title\u0026#39;, fontsize=20, fontweight=\u0026#39;bold\u0026#39;) # Text(0.5, 0.98, \u0026#39;Sup Title\u0026#39;) 在plt.plot輸入陣列後加上一個格式字串可以用來代表畫線的樣式，\n指定linewidth可以修改畫線的粗細。\n1 2 3 4 5 6 7 8 9 10 11 12 13 # r代表紅色，x代表用\u0026#39;x\u0026#39;來表示點，且不畫線 \u0026gt;\u0026gt;\u0026gt; plt.plot([1,2,3,4], [3,5,15,18], \u0026#39;rx\u0026#39;) [\u0026lt;matplotlib.lines.Line2D object at 0x000000000B856C10\u0026gt;] # b代表藍色，\u0026#39;.\u0026#39;代表用單個小點表示一個點，\u0026#39;--\u0026#39;表示用虛線(dashed line)來畫線 \u0026gt;\u0026gt;\u0026gt; plt.plot([1,2,3,4], [3,9,1,6], \u0026#39;b.--\u0026#39;) [\u0026lt;matplotlib.lines.Line2D object at 0x000000000B866310\u0026gt;] # g代表綠色，o代表實心圓，linewidth表示粗度修為3 \u0026gt;\u0026gt;\u0026gt; plt.plot([1,2,3,4], [1,4,9,16], \u0026#39;go-\u0026#39;, linewidth=3) [\u0026lt;matplotlib.lines.Line2D object at 0x000000000B856F40\u0026gt;] \u0026gt;\u0026gt;\u0026gt; plt.legend((\u0026#39;red\u0026#39;, \u0026#39;blue\u0026#39;, \u0026#39;green\u0026#39;), loc=\u0026#39;upper left\u0026#39;) # 畫圖例及決定位置 \u0026lt;matplotlib.legend.Legend object at 0x000000000B757730\u0026gt; \u0026gt;\u0026gt;\u0026gt; plt.grid(True) # 畫出網格 \u0026gt;\u0026gt;\u0026gt; plt.show() 其結果應如下所示：\n在處理過後可畫線的圖以後，如果我們的資料是零散的點，\n不需要畫線的話，我們可以用散點圖(scatter)來進行繪製：\n1 2 3 4 5 6 7 \u0026gt;\u0026gt;\u0026gt; np.random.random(5) array([0.22612501, 0.34256502, 0.21559228, 0.17675453, 0.1082928 ]) \u0026gt;\u0026gt;\u0026gt; x = np.random.random(500) \u0026gt;\u0026gt;\u0026gt; y = np.random.random(500) \u0026gt;\u0026gt;\u0026gt; plt.scatter(x, y)　# 其實用plt.plot(x, y, \u0026#39;o\u0026#39;)也可以啦！ \u0026lt;matplotlib.collections.PathCollection object at 0x000000000B566580\u0026gt; \u0026gt;\u0026gt;\u0026gt; plt.show() 如果要繪製3D的圖的話，要利用plt.axes()，\n將其projection設為’3d’。\n同時由於有三維座標，所以要使用ax.scatter3D(x, y, z, color)。\n1 2 3 4 5 6 \u0026gt;\u0026gt;\u0026gt; z = np.random.normal(0, 0.2, 500) \u0026gt;\u0026gt;\u0026gt; fig = plt.figure() \u0026gt;\u0026gt;\u0026gt; ax = plt.axes(projection=\u0026#39;3d\u0026#39;) \u0026gt;\u0026gt;\u0026gt; ax.scatter3D(x, y, z, color=\u0026#39;blue\u0026#39;) \u0026lt;mpl_toolkits.mplot3d.art3d.Path3DCollection object at 0x000000000C00A1F0\u0026gt; \u0026gt;\u0026gt;\u0026gt; plt.show() 最後我們會得到一個3D散點圖，其介面是可以按滑鼠左鍵拖曳旋轉的呦！\n讀者可以自己嘗試看看～\n其他其實還有相當多的內容，有興趣的話可以看看官方文件的說明。\n像是各種不同種類的圖形、標記方式、標籤等等，\n如果使用者想更進一步的話，可以試試看找一些如繪製股票線形的教學範例，\n跟著操作看看，相信會更有收穫！\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-12T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-27-science-drawing-matplotlib/","title":"從零開始學Python (27) — 科學繪圖Matplotlib：畫著你，畫不出你的骨骼"},{"content":"Day 26 科學運算NumPy：人間用多少滄桑，換多少人的瘋狂 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247302\n我們今天要來介紹一下NumPy。\n一般來說，讀者可能常常會聽到有些人說Python的執行效率相對比較低，\n這是真的，因為動態語言會比妥善先編譯過的語言執行速度還慢，\n因而我們會看到在像是LeetCode的答案繳交時，\n用C/C++/Java可能是執行5 ms(毫秒)的時間，\n用Python寫相同邏輯的答案可能要30~100ms。\n既然這樣，為什麼現在Python會成為機器學習或AI發展的主流語言呢？\n原因就是Python有很多方便的程式庫，\n尤其科學運算方面，有不少經過最佳化以及妥善編譯後的程式庫，\n使用起來的效率相當的好，NumPy就是其中一個。\n通常狀況下NumPy會搭配到後面的Matplotlib及Keras(TensorFlow)，\n用來輸入大量的矩陣及陣列，可以迅速進行運算。\n如果讀者沒有使用其他如Anaconda的方式安裝的話，\n要安裝numpy最簡單的方式就是使用pip。\n1 2 3 4 # 一般安裝指令 pip install numpy # 如果發生安裝不起來的狀況，可以嘗試看看使用--user pip install --user 我們先來介紹NumPy的最基本單位：陣列。\n在Python中我們一般使用串列，也有陣列的模組，但一般不會用。\nNumPy的陣列叫做ndarray，\n它是一系列的相同資料型態的元素組成的，和串列不同，\n串列可以這個放字串，另一個放int，但ndarray不允許這麼做喲!\nnd是n-dimension(n維)的意思，\nNumpy會將維度稱為rank。\n單維的陣列就像一個row一樣；\n二維的話就像Excel的表格有row/column；\n三維就會像一個立方體(但不一定要正立方體)！\nndarray這麼設定是因為，\n當我們在計算資料時，會用到一些矩陣運算或一些其他的科學運算方式，\n在這當中會容易同時處理到多個資料，\n因此使用比較方整的格式及固定資料型態，\n可以讓配置每個元素的記憶體大小比較固定，\n同時也便於取用和運算。\n(所以會比list和Tuple等效率來得好)\n接下來我們簡單介紹一下numpy的幾個基本指令：\nnp.array()：產生一個ndarray\nndim ：維度數 (rank)\nshape ：每個維度的元素個數 (以Tuple型式呈現)\nsize ：總個數\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \u0026gt;\u0026gt;\u0026gt; import numpy as np # 大家習慣的縮寫方式 \u0026gt;\u0026gt;\u0026gt; a = np.array([1, 5, 3, -1]) # 一維陣列 \u0026gt;\u0026gt;\u0026gt; a array([1, 5, 3, -1]) \u0026gt;\u0026gt;\u0026gt; a.ndim # rank 1 \u0026gt;\u0026gt;\u0026gt; a.size # 陣列的元素總個數 4 \u0026gt;\u0026gt;\u0026gt; a.shape # 回傳每個rank有幾個值 (4,) \u0026gt;\u0026gt;\u0026gt; b = np.array([[1, 3, 2, 4], [5, 4, 3]]) # 長度要符合阿大大！ \u0026lt;stdin\u0026gt;:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify \u0026#39;dtype=object\u0026#39; when creating the ndarray \u0026gt;\u0026gt;\u0026gt; b = np.array([[1, 3, 2, 4], [5, 4, 3, 3]]) # 正確的二維陣列 \u0026gt;\u0026gt;\u0026gt; b.ndim, b.size, b.shape # 所以我們會看到一個二維陣列，總數8個，2個rows，4個columns (2, 8, (2, 4)) 再來我們介紹另一個產生陣列的方式arange()：\narange基本上很像range()的用法，\n舉例來說：\nnp.arange(10) -\u0026gt; 生成一個一維陣列，元素從09\nnp.arange(5, 10) -\u0026gt; 生成一個一維陣列，元素從59\nnp.arange(5, 11, 2) -\u0026gt; 生成一個一維陣列，元素為5, 7, 9\n此外，還有比較特別的是，它可以接受帶小數點的輸入。\n1 2 \u0026gt;\u0026gt;\u0026gt; np.arange(2, 8.8, 1.3) array([2. , 3.3, 4.6, 5.9, 7.2, 8.5]) 除此以外，也可以用以下幾個來初始化陣列：\nzeros() -\u0026gt; 建立全是0的陣列\n1 2 3 4 5 6 7 8 9 10 11 \u0026gt;\u0026gt;\u0026gt; import numpy as np \u0026gt;\u0026gt;\u0026gt; np.zeros((3)) array([0., 0., 0.]) \u0026gt;\u0026gt;\u0026gt; np.zeros((3,)) # 因為傳入是Tuple，所以多寫一個逗號主要是提醒不要把外面的括號省略 array([0., 0., 0.]) \u0026gt;\u0026gt;\u0026gt; np.zeros((1, 5)) array([[0., 0., 0., 0., 0.]]) \u0026gt;\u0026gt;\u0026gt; np.zeros((3, 4)) array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]) ones() -\u0026gt; 建立全是1的陣列\n(範例就不浪費大家字數了，意思一樣)\nrandom.random() -\u0026gt; 從0.0~1.0的隨機值來建立一個陣列(每個元素都是獨立的隨機值)\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; np.random.random((2,6)) array([[0.01287523, 0.53233704, 0.79855996, 0.74661588, 0.53556373, 0.01158943], [0.69197322, 0.90871892, 0.24175071, 0.73861581, 0.90259941, 0.74164385]]) np.random這個系列底下其實也有很多常用的東西，\n比如說如果我們想要一個最常見的常態分布的陣列，\n我們可以使用random.normal()，\n用法是np.random.normal(平均值, 標準差, size) ：\n1 2 3 4 5 6 7 \u0026gt;\u0026gt;\u0026gt; mu, sigma = 0, 0.2 \u0026gt;\u0026gt;\u0026gt; c = np.random.normal(mu, sigma, (2, 8)) \u0026gt;\u0026gt;\u0026gt; c array([[ 0.00521883, -0.04220576, 0.00590997, -0.06231083, 0.07088372, 0.16073115, 0.30269475, -0.02136197], [-0.2599142 , -0.03247713, -0.00156353, -0.43750613, -0.01930995, -0.00546659, 0.18611712, 0.12076204]]) 後續怎麼畫出來呢？讓我們留待到下一篇再告訴大家吧XD！\n在介紹完初始化陣列後，\n我們來講一個numpy的特異功能：reshape() 。\nreshape顧名思義，就是將陣列重新捏成你想要的形狀。\n比如假設我們做了一個一維的陣列，其size為9。\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; s = np.random.normal(mu, sigma, 9) \u0026gt;\u0026gt;\u0026gt; s array([ 0.04298177, -0.14931128, 0.01522315, 0.10384426, 0.06392715, -0.02892813, 0.22175294, 0.06630997, -0.09279769]) 使用reshape的方式，就是直接指定維度形狀，\n只要reshape前後的size算起來是一致即可。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 \u0026gt;\u0026gt;\u0026gt; s.reshape(3, 3) # reshape完後若沒有回頭存起來，並不會修改到s呦! array([[ 0.04298177, -0.14931128, 0.01522315], [ 0.10384426, 0.06392715, -0.02892813], [ 0.22175294, 0.06630997, -0.09279769]]) \u0026gt;\u0026gt;\u0026gt; s.reshape(1, 9) array([[ 0.04298177, -0.14931128, 0.01522315, 0.10384426, 0.06392715, -0.02892813, 0.22175294, 0.06630997, -0.09279769]]) \u0026gt;\u0026gt;\u0026gt; s.reshape(9, 1) array([[ 0.04298177], [-0.14931128], [ 0.01522315], [ 0.10384426], [ 0.06392715], [-0.02892813], [ 0.22175294], [ 0.06630997], [-0.09279769]]) \u0026gt;\u0026gt;\u0026gt; s.shape = (3, 3) # 直接對shape使用Tuple指定也可以呦！ \u0026gt;\u0026gt;\u0026gt; s array([[ 0.04298177, -0.14931128, 0.01522315], [ 0.10384426, 0.06392715, -0.02892813], [ 0.22175294, 0.06630997, -0.09279769]]) 在取得單一或範圍元素的時候，\n陣列基本上跟串列蠻像的：\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; d = np.arange(24) \u0026gt;\u0026gt;\u0026gt; d array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]) \u0026gt;\u0026gt;\u0026gt; d[7] 7 \u0026gt;\u0026gt;\u0026gt; d[-1] 23 \u0026gt;\u0026gt;\u0026gt; d[10:18] array([10, 11, 12, 13, 14, 15, 16, 17]) \u0026gt;\u0026gt;\u0026gt; d[10:18:2] array([10, 12, 14, 16]) 但如果是多維陣列的話，則必須要用逗號分隔不同的維度：\n(Python的串列則是用中括號分隔)\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; d.shape = 3,2,4 \u0026gt;\u0026gt;\u0026gt; d array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], 1 2 [[ 8, 9, 10, 11], [12, 13, 14, 15]], 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [[16, 17, 18, 19], [20, 21, 22, 23]]]) \u0026gt;\u0026gt;\u0026gt; d[1] array([[ 8, 9, 10, 11], [12, 13, 14, 15]]) \u0026gt;\u0026gt;\u0026gt; d[1:,1, 3] array([15, 23]) \u0026gt;\u0026gt;\u0026gt; d[1:,1, 3:] array([[15], [23]]) \u0026gt;\u0026gt;\u0026gt; d[1, 1] array([12, 13, 14, 15]) \u0026gt;\u0026gt;\u0026gt; d[1, 1, 2:] array([14, 15]) 另一個功能是可以將值給定到陣列指定的範圍：\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; d[1, 1, 2:] = 99999 # 將指定範圍的值全數換成99999 \u0026gt;\u0026gt;\u0026gt; d array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], 1 2 [[ 8, 9, 10, 11], [ 12, 13, 99999, 99999]], 1 2 [[ 16, 17, 18, 19], [ 20, 21, 22, 23]]]) 在陣列計算時，我們使用陣列對數字加減乘除時，\n可以將其一口氣全部作相同的事情：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; d + 1 array([[[ 1, 2, 3, 4], [ 5, 6, 7, 8]], 1 2 [[ 9, 10, 11, 12], [ 13, 14, 100000, 100000]], 1 2 3 4 5 [[ 17, 18, 19, 20], [ 21, 22, 23, 24]]]) \u0026gt;\u0026gt;\u0026gt; d * 3 + 2 array([[[ 2, 5, 8, 11], [ 14, 17, 20, 23]], 1 2 [[ 26, 29, 32, 35], [ 38, 41, 299999, 299999]], 1 2 3 4 5 [[ 50, 53, 56, 59], [ 62, 65, 68, 71]]]) \u0026gt;\u0026gt;\u0026gt; d / 3 + 2 array([[[2.00000000e+00, 2.33333333e+00, 2.66666667e+00, 3.00000000e+00], [3.33333333e+00, 3.66666667e+00, 4.00000000e+00, 4.33333333e+00]], 1 2 [[4.66666667e+00, 5.00000000e+00, 5.33333333e+00, 5.66666667e+00], [6.00000000e+00, 6.33333333e+00, 3.33350000e+04, 3.33350000e+04]], 1 2 [[7.33333333e+00, 7.66666667e+00, 8.00000000e+00, 8.33333333e+00], [8.66666667e+00, 9.00000000e+00, 9.33333333e+00, 9.66666667e+00]]]) 除此以外，常用的矩陣運算numpy也都有所支援，\n舉例來說，假設想要算兩個二維矩陣的相乘(內積)，\n可以使用np.dot(x, y)或x.dot(y)：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \u0026gt;\u0026gt;\u0026gt; x = np.arange(1, 5) \u0026gt;\u0026gt;\u0026gt; x.shape=2,2 \u0026gt;\u0026gt;\u0026gt; y = np.arange(5, 9) \u0026gt;\u0026gt;\u0026gt; y.shape=2,2 \u0026gt;\u0026gt;\u0026gt; x array([[1, 2], [3, 4]]) \u0026gt;\u0026gt;\u0026gt; y array([[5, 6], [7, 8]]) \u0026gt;\u0026gt;\u0026gt; x.dot(y) array([[19, 22], [43, 50]]) \u0026gt;\u0026gt;\u0026gt; np.dot(x,y) # 跟x.dot(y)意思是一樣的 array([[19, 22], [43, 50]]) (註：如果是算外積的話，則要用outer())\n如果是想要對應的位置兩兩相乘，則要用np.multiply()：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; np.multiply(x, y) array([[ 5, 12], [21, 32]]) 以上簡單介紹了一下numpy的用法，\n當然只是蠻簡略的部分，\n如果有更多對於詳細函式需求理解的部分，可以直接參考看看numpy的官方文件：\nhttps://numpy.org/doc\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-11T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-26-science-computation-numpy/","title":"從零開始學Python (26) — 科學運算NumPy：人間用多少滄桑，換多少人的瘋狂"},{"content":"Day 25 二元搜尋法模組bisect：我走回從前你往未來飛，遇見對的人錯過交叉點 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247301\n接下來，我們來談談二元搜尋法模組bisect。\n在談bisect模組之前，我們先來談談二元搜尋法(binary search) 。\n二元搜尋法的原則是，\n當有一串排列好的陣列/串列時，\n我們可以透過每次去掉一半來迅速找到目標。\n為什麼可以做到這點呢？\n假定我們有一個串列lt，其長度為n，\n由於是已經排列好的(由小排到大)，\n我們想要找到一個值target在lt中是否存在，\n存在時所在的位置及不存在時應該插入的位置；\n所以當我們取l=0, r=n-1的中間位置mid=(l+r)//2時，會有幾個可能：\nlt[mid] \u0026gt; target =\u0026gt; 代表target在mid左邊的位置，所以要搜尋的範圍就會變成0~mid-1\nlt[mid] == target =\u0026gt; ** 代表target在mid位置上，可以直接回傳結果**\nlt[mid] \u0026lt; target =\u0026gt; ** 代表target在mid右邊的位置，**\n所以要搜尋的範圍就會變成mid+1~r\n因此，在尚未找到目標的狀況下，每次所需搜尋的範圍都會折半，\n這也就是為什麼會被稱為二元或二分搜尋法的原因。\n二元搜尋法的進一步實作是蠻基本的題目，\n如果要嘗試不使用模組來處理的話，\n可以參照\n[Day 7] 從LeetCode學演算法 — 0035. Search Insert Position (Easy)。\n在其他狀況下，如果題目重點不是考二元搜尋法，\n或者在日常使用的話，則可以考慮使用bisect模組。\n在使用bisect模組對某個list進行處理前，\n需留意bisect已經預設這個list是排序過的狀態了 ！\n類似前一篇提到的heapq，\n如果必要的話，請先對list進行一般排序的動作。\nbisect的常見用法如下：(import bisect)\nbisect_left/bisect_right/bisect：\n取得應該插入的位置 ，當中left/right則代表如果碰到相同的值，\n會當成要插入在所有相同的值的左邊或右邊 (不給定則預設為右邊 )\ninsort_left/insort_right/insort：\n取得對應的bisect回傳index後，使用這個index來進行插入的動作。\n上述所有函式的參數都是(串列名a, 要插入的值x, lo=0, hi=len(a))，\n沒有特別指定的話就會當作使用整個串列考慮插入的問題。\n1 2 3 4 5 6 7 8 9 10 11 \u0026gt;\u0026gt;\u0026gt; import bisect \u0026gt;\u0026gt;\u0026gt; lt = [1,3,3,3,5,8,9] \u0026gt;\u0026gt;\u0026gt; bisect.bisect_left(lt, 3) # 同值的最左邊 1 \u0026gt;\u0026gt;\u0026gt; bisect.bisect_right(lt, 3) # 同值的最右邊 4 \u0026gt;\u0026gt;\u0026gt; bisect.bisect(lt, 3) # 預設相當於right 4 \u0026gt;\u0026gt;\u0026gt; bisect.insort(lt, 3) # 實際插入 \u0026gt;\u0026gt;\u0026gt; lt [1, 3, 3, 3, 3, 5, 8, 9] 順帶一提，使用bisect查找的速度，\n扣除掉重覆值找到最左邊/最右邊外，\n其時間複雜度為O(logN) 。(log這邊是以2為底的)\n讀者可能會問：\n「什麼是複雜度呢？」\n簡單來說，複雜度就是用來評估程式作一件事情，\n其所需的時間/空間和輸入的資料大小(通常會用N表示)之間，\n大致的量級關係。\n以list來說，我們使用index()函式取得某個值的所在位置的話，\n其時間會是線性的(linear)，\n也就是和list的長度成正比，我們會寫作O(N)。\n對比起bisect而言，顯然有利用排序這點，\n和沒有利用到這點會有根本性的差距，因為一個一個找，\n和每次折半找，誰比較省時間就顯而易見了！\n建議讀者有時間的話，\n可以再進一步去查找一下關於基礎的複雜度分析，\n因為有關程式複雜度分析，對於不論是實務上判斷不同方法之間的優劣，\n或是面試的時候，回答考官你的解法的時候，\n通常也都要回答關於時間複雜度及空間複雜度的問題，\n所以有空的話可以先為自己打個底。\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-10T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-25-binary-search-bisect/","title":"從零開始學Python (25) — 二元搜尋法模組bisect：我走回從前你往未來飛，遇見對的人錯過交叉點"},{"content":"Day 24 資料結構模組heapq：除了前幾名以外，在座的各位都是垃圾 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247299\n昨天的題目，請參見下面的解法：\nhttps://ithelp.ithome.com.tw/articles/10213277\n接下來我們要來談談一個也算是蠻重要的資料結構：\n堆積(heap)，以及在Python中對應的模組heapq 。\n什麼是heap呢?\nHeap是一種特別的完全二元樹。\n這時候讀者又會問了：\n那什麼是完全二元樹？\n簡單來說，就是一棵二元樹直到最後一層之前，\n由左往右都是填滿節點的狀態，中途沒有空缺，\n唯有最後一層的右側會缺節點而已。\n那麼，heap是怎麼個特別法呢？\n當取一棵完全二元樹中的任何一個節點，\n對應父(母)節點的值永遠小於等於子節點的值 (就是越上面越小)，\n我們就會將其稱為最小堆積(min heap) ；\n反之，如果父(母)節點的值永遠大於等於子節點的值 ，\n我們就會稱為最大堆積(max heap) 。\n如果上面兩個狀況都不符合的話就不是堆積囉！\n也因此我們會得到一個特性：\n最大堆積的最大的節點値 永遠會在根節點 ；\n最小堆積的最小的節點値 永遠會在根節點 。\nPython中的heapq的部分呢？\n它是使用串列來實作出heap的資料結構的，\n且是一個最小堆積 。\n由於本篇以初學為導向，我們就不討論heap在二元樹上，\n怎麼去處理新增/修改/刪除等操作了，\n把焦點著重擺在heapq提供的可行操作上！\n首先，Python可以將list輸入給heapq來排成heap的形狀，\n透過heapq.heapify()函式 ：\n1 2 3 4 5 6 7 \u0026gt;\u0026gt;\u0026gt; import heapq \u0026gt;\u0026gt;\u0026gt; lt = [2,7,4,1,8,1] \u0026gt;\u0026gt;\u0026gt; heapq.heapify(lt) # 直接將lt排成heap的形狀 # 在這個狀態下heap[k] \u0026lt;= heap[2*k+1] 且 heap[k] \u0026lt;= heap[2*k+2] # 上面的k對於0或正整數均滿足(只要index存在) \u0026gt;\u0026gt;\u0026gt; lt # 已經完成了，但並不是排序，所以看起來不會由小到大是正常的 [1, 1, 2, 7, 8, 4] 此外，由於現在lt已經是一個heap了，\n要插入新的值或要處理其他操作的話，\n要使用heapq提供的函式來處理，\n常用的操作如下：\nheapify (將一個list轉為heap)\nheappush/heappop/heappushpop (放入/取出/先放入後取出)\nnlargest/nsmallest (取前n大/前n小的元素)\n當中我們只要只使用這些操作來處理，\n就可以保證每次做取出(heappop)的時候，其値都會是最小的！\n在這邊請留意幾點：\n當使用append或者del (也就是用list的方式來動到lt)時，\n會影響heap的狀態，若要復原只能重新heapify 由於這個heap是min heap，\n所以nsmallest(取前n小元素)速度會比較快 ，較有效率，\nnlargest(取前n大元素)是較沒有效率的，\n官方會建議要這樣取不如直接先排序。 對於2來說，其實也有解法，\n就是當需要用到max heap時，\n我們手動將每個元素加上一個負號代入 ，\n如此一來就可以將min heap當max heap來用啦！ 我們拿LeetCode的1046題來當例子：\nhttps://leetcode.com/problems/last-stone-weight/\n題目大意是，\n有一堆石頭，石頭重量均為正整數(阿不然是會有負的嗎？)。\n每次我們拿最重的兩個石頭x, y(x \u0026lt;= y)相撞，\n結果會有兩種：\nx == y 的時候，兩顆石頭都會毀掉消失 x != y 的時候，只會剩下一顆石頭，重量為y — x\n撞到最後，最多只會剩下1顆石頭，請問石頭的重量是多少？\n(沒有石頭的話答案就視為0) 依照這個題目，我們會發現，\n只要我們能建立一個max heap，\n一切都會變得很輕鬆！\n為什麼呢？\n因為每次我們要拿兩個最重的相撞，\n也就是每一輪要從heap當中取出兩個最大的值，\n相減過後還有剩的，再放入heap中，\n直到heap空掉，或者只剩1個值為止。\n因此，我們可以如前面所提到的那樣，\n先將石頭的重量加上負號並生成一個list，\n再用heapq來對其處理。\n我們直接來上程式碼，請對照註解來了解整個思路。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution: def lastStoneWeight(self, stones: List[int]) -\u0026gt; int: import heapq h = [-x for x in stones] # list comprehension heapq.heapify(h) # 生成最小堆積 while len(h) \u0026gt; 1: # 堆積內還有超過1顆的石頭 y = heapq.heappop(h) # 取第一顆，重量應該是-y x = heapq.heappop(h) # 取第二顆，重量應該是-x if y != x: # 兩顆沒有一起毀掉 # 差值應該是-y+x，但為了放入heap中，要再加上一個負號 heapq.heappush(h, y - x) # 再放入heap中 if len(h) == 0: # 全部石頭都毀掉了，回傳0 return 0 else: return -h[0] # 回傳剩下的石頭的值，別忘了要負負得正 除了上述的需求外，\nheap類型也適用於限縮個數的狀況。\n比如說今天想要找一個班級的最強的前5名，\n我們可以讓heap在個數尚未達到5個時使用heappush() ；\n而達到5個後呢？就使用heappushpop() ，\n先放入值，再將最弱的取出來丟掉。\n所以當碰到”除了前5名以外，在座的各位都是垃圾”類型 的情況，\n特別適合使用heap來進行操作，可以有效降低需要保留的元素個數。\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-24-data-structure-heapq/","title":"從零開始學Python (24) — 資料結構模組heapq：除了前幾名以外，在座的各位都是垃圾"},{"content":"Day 23 資料結構模組deque：旁人來來去去像行雲流水 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247295\n先來解一下上次的練習吧！ 我們唯一需要動的應該只有calculate的函式，\n當 p1 \u0026lt; p2 時，將兩個值交換即可。\n別忘了交換應該要連同Entry裡面的值都一起換(price1/price2)。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ### calculate函式用來接受按鈕事件，取得商品價格及折扣方式，計算後輸出 def calculate(): # 每次要計算時，都讓按鈕顯示計算哪一個折扣法 btnstr.set(\u0026#39;計算\u0026#39; + radiostr.get() + \u0026#39;中\u0026#39;) # 用try...except...的方式來避免掉輸入的不是數字 try: choice = radiostr.get() # radiobutton的選擇項 p1 = int(price1.get()) p2 = int(price2.get()) if p1 \u0026lt;= 0 or p2 \u0026lt;= 0: # 如果輸入\u0026lt;=0的數字也當成例外處理 raise Exception() if p1 \u0026lt; p2: p1, p2 = p2, p1 price1.set(str(p1)) price2.set(str(p2)) ...(下面沒有變動XD) 我們今天要來談談deque的應用，\n我們前面已經在第十一篇的部分提到過deque的用法，這篇主要要來補充deque作為queue時的常見狀況。\n一般我們提到兩種資料結構：\nqueue(佇列)或stack(堆疊)的概念，\n其實就是先進先出(FIFO, First-In-First-Out)或\n先進後出(First-In-Last-Out)的區別。\nqueue就好像排隊一樣，當然是先排的先被服務到(除非有人插隊XD)；\nstack則像是一疊文件一樣，假設你都拿最上面的，\n當老闆又往上放新的文件(工作)給你的時候，\n你再拿就會拿到最新放上去的囉！\n這兩者在不同的程式語言有時候會有不同的稱呼和變形，\n但本質是不變的。\n那麼，什麼狀況下我們寫程式會容易用到queue(deque)呢?\n最常見的狀況是遇到一個Tree(樹)的問題的時候！\n那，什麼是樹呢？\n好問題！這個問題應該要用比較長的篇幅解釋，\n所以請讀者參閱拙作從LeetCode學演算法的第十四篇，\n下面我們再繼續。\n不囉嗦，我們直接上一道題目作為範例吧！\n上面的連結應該已經介紹過二元樹了，\n最簡單來說，一棵二元樹就是由根節點(root)，\n及左子樹(left tree)/右子樹(right tree)所構成。\n每個節點上有可能連結左右節點，\n也可能沒有連接，稱為NIL，在Python為None。\n如果我們今天想要按照一層一層順序來走遍整個樹，\n並分層記錄的話，該怎麼做呢？\n這個問題通常被稱為Level-order Traversal。(層序遍歷)\n讀者可以前往LeetCode的題目看更詳細的描述。\nhttps://leetcode.com/problems/binary-tree-level-order-traversal/\n我們可以先走第一層，再走第二層，以此類推，\n那麼這中間走完第一層時，怎麼知道第二層有哪些節點呢？\n按順序的話，我們應該將第一層的每個節點的左節點/右節點，\n放入到一個可以按照放入的順序處理的資料結構，\n接著再從這個資料結構裡一個一個拿出來(這時候是第二層了!)，\n找每一個的左右節點，再放進去……\n咦？這個資料結構不就是queue嗎XD？\n我們在解題和寫程式的時候，\n可以先把要怎麼做大略寫出來，\n再根據這個概念和做法，寫出具體的程式。\n以這個問題來說，\n題目應該會給出這個二元樹的根節點root，\n接著要做的事情就如上面說的一樣，但我們需要一些細部的東西：\n開一個res(result)作為存放答案用的串列。 我們先檢查root是否存在，有些題目壞壞的會給None，\n如果不存在就直接回傳空的答案給它! 將root放入我們檢查的資料結構(因為它是第一層)，我們先叫它q吧! 開始一個迴圈，當q裡面還有節點時，代表還要繼續。 我們先記下q裡面的個數(命名為cnt)，後面放進去q的都是下一層的節點。 接著先設定一個level變數，用以記錄這層的節點值們。 在裡面再開一個迴圈，這次直接指定跑cnt次，\n這樣所有這層的節點都會被我們取出來。 內層迴圈中，每次從q取出一個節點(popleft)，\n將節點值(.value)append到level中， 檢查左節點，如果不是None的話就將節點放到q裡。 檢查右節點，做相同的事情XD 內層迴圈結束後，這時候我們拿到一整層的節點值，\n我們應該要將其append到res這個結果裡。 最後全部處理完後，可以將res回傳。 好啦!經過上面的步驟，有沒有發現我們其實已經把程式寫完了呢？\n只要按著順序對照，應該可以順利寫出答案。\n那麼，我們就來看看實際的做法：\n1 2 3 4 5 6 # Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None 1 from collections import deque 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution: def levelOrder(self, root: TreeNode) -\u0026gt; List[List[int]]: res = [] # result，用以記錄結果 if not root: return res # 我們有提過，if not可以用來檢查東西是不是空的 q = deque([root]) # deque的初始化，要以list的形式放入 while q: # 當q還有節點(同樣這相當於檢查是不是空的) cnt = len(q) # deque支援len的操作(取長度) level = [] # 記錄每層的節點值 for _ in range(cnt): # _沒有特別意思，通常是當沒有要在迴圈內用到時可以使用 n = q.popleft() # popleft等於從deque的左邊取出，也就是queue的用法 level.append(n.val) # 取值 if n.left: q.append(n.left) # 將左節點放入q if n.right: q.append(n.right) # 將右節點放入q res.append(level) # 每層完成後，要將一整層的節點值list放到res中 return res # 回傳，結束！ 應該不算太難(吧)…?\n請務必要看完樹的那篇定義再來看這篇喲！\n總言之，deque作為queue使用時，主要會用popleft()跟append()來操作，\n同時它會適合按先後順序放入及取出的情況。\n練習題目的話，\n讀者可以再嘗試看看LeetCode的另一題：\n101. Symmetric Tree\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-08T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-23-data-structure-deque/","title":"從零開始學Python (23) — 資料結構模組deque：旁人來來去去像行雲流水"},{"content":"Day 22 圖形化使用者介面Tkinter：直到現在，我還默默的等待 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247294\n上次的練習我們就不驗收了，相信大家應該可以做得好的XD!\n今天我們來聊聊Python的圖形化使用者介面。\n如果讀者手上有一些Python的入門書，\n相信在這個單元之前，常常會看到一個烏龜的範例(Turtle模組)，\n那就是一種會顯示圖形化的介面其中一種。\n通常我們會將有圖形化的互動介面稱為GUI(Graphical User Interface)介面，\n在Python當中如果算上其他的GUI介面的話，\n其實相當多種，最常見的有Tkinter/PyQT/WxPython/Kivy 等，\n如果就一般人而言，沒有特殊需求的話，\n使用內建的Tkinter模組作為開頭應該就很足夠囉！\n每個tkinter的主體會先由tkinter.Tk()的物件生成，\n通常讀者們應該會看到大部分的範例會將tkinter縮寫成tk ，\n並將生成的物件命名為window或win (代表這個視窗介面)，\n後續的操作也都跟其息息相關。\n1 2 3 4 5 6 7 8 9 10 11 \u0026gt;\u0026gt;\u0026gt; import tkinter as tk \u0026gt;\u0026gt;\u0026gt; win = tk.Tk() # 如果使用直譯器的話，在這行Enter後就會先看到一個視窗了！ \u0026gt;\u0026gt;\u0026gt; win.title(\u0026#39;從零開始學Python：第二件X折？\u0026#39;) # 更改視窗的標題 \u0026#39;\u0026#39; \u0026gt;\u0026gt;\u0026gt; win.geometry(\u0026#39;800x400\u0026#39;) # 修改視窗大小(寬x高) \u0026#39;\u0026#39; \u0026gt;\u0026gt;\u0026gt; win.resizable(False, False) # 如果不想讓使用者能調整視窗大小的話就均設為False \u0026#39;\u0026#39; \u0026gt;\u0026gt;\u0026gt; win.iconbitmap(\u0026#39;unicorn.ico\u0026#39;) # 更改左上角的icon圖示 \u0026#39;\u0026#39; \u0026gt;\u0026gt;\u0026gt; win.mainloop() # 在一般python xxx.py的執行方式中，呼叫mainloop()才算正式啟動 (註：下面的操作我們都先在直譯器中嘗試，請先不要下mainloop()以免無法再輸入指令)\n我們在上面的示範中使用了一個icon檔，是一隻打瞌睡的獨角獸：\nhttps://www.flaticon.com/free-icon/unicorn_3468081\n但下載下來的時候是png檔，而使用圖示只會接受icon bitmap 的格式，\n使用者可以利用上一篇教的PIL來進行轉換：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; from PIL import Image \u0026gt;\u0026gt;\u0026gt; img = Image.open(\u0026#39;unicorn.png\u0026#39;) \u0026gt;\u0026gt;\u0026gt; img.save(\u0026#39;unicorn.ico\u0026#39;) 或者，也可以用另一個iconphoto()方法 ，\n它可以接受一些其他類型的圖片(png可以，但jpg不行)\n1 \u0026gt;\u0026gt;\u0026gt; win.iconphoto(True, tk.PhotoImage(file=\u0026#39;./unicorn.png\u0026#39;)) 接下來讓我們介紹Frame。Frame可以想成是一個區塊 ，\n用來切分視窗以方便進行排版，\n舉例來說，如果我們想要在上面塞一個寬度800，高度為100的Frame：\n1 2 3 # bg可以用顏色名稱，或者使用\u0026#39;#FF0000\u0026#39;的RGB形式來給定 \u0026gt;\u0026gt;\u0026gt; fm = tk.Frame(win, bg=\u0026#39;violet\u0026#39;, width=800, height=100) \u0026gt;\u0026gt;\u0026gt; fm.pack() # 設定Frame的排版方法，這行完成後才會在視窗上顯現 (註：排版方法有pack(), grid(), place()三種 ，\n若讀者有興趣可再自行深入研究。)\n再來是按鈕Button 的部分，值得注意的是，\n我們可以運用textvariable的參數來給定tk.StringVar變數 ，\n用來讓我們可以動態調整按鈕上的字的變化。\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; def calculate(): ... btnstr.set(\u0026#39;計算中...\u0026#39;) ... \u0026gt;\u0026gt;\u0026gt; btnstr = tk.StringVar() # 初始化tk的字串變數 \u0026gt;\u0026gt;\u0026gt; btnstr.set(\u0026#39;按我計算\u0026#39;) \u0026gt;\u0026gt;\u0026gt; btn = tk.Button(win, bg=\u0026#39;violet\u0026#39;, fg=\u0026#39;white\u0026#39;, textvariable=btnstr, font=(\u0026#39;微 軟正黑體\u0026#39;, 20), command=calculate) \u0026gt;\u0026gt;\u0026gt; btn.pack() 在上面的例子中，我們初始化了一個btnstr的變數，\n並且將其在開一個Button變數時，作為文字變數(StringVar)給定進去；\n同時，當按鈕被按下時，calculate這個函式將被呼叫，\n從而將按鈕上的字進行改變。\ntk的變數有StringVar, IntVar, DoubleVar 等三種，\n其使用方式是set()用以設定變數，get()用以取得變數內容 。\n如果我們單純想要顯示文字，不想被使用者修改的話，\n應該要使用文字標籤(Label) ；\n如果是要被輸入的文字方塊的話，\n則可以使用文字輸入欄(Entry) ；\n想要使用單選的選項的話，\n則可以使用單選按鈕(Radiobutton) ；\n想要跳出提示方塊的話，\n就要使用對話框(Messagebox) 。\n由於這當中嘗試一些排版和顏色太過複雜，\n我們直接上最後的程式碼給讀者，\n請一段一段沿著往下讀，\n每一段可以先貼到直譯器上跑，\n可以看到對應的元件生成的樣貌，\n這樣會更為清楚每一段在作什麼呦！\n1 2 import tkinter as tk import tkinter.messagebox as msg # messagebox要另行匯入，否則會出錯。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 ### calculate函式用來接受按鈕事件，取得商品價格及折扣方式，計算後輸出 def calculate(): # 每次要計算時，都讓按鈕顯示計算哪一個折扣法 btnstr.set(\u0026#39;計算\u0026#39; + radiostr.get() + \u0026#39;中\u0026#39;) # 用try...except...的方式來避免掉輸入的不是數字 try: choice = radiostr.get() # radiobutton的選擇項 p1 = int(price1.get()) p2 = int(price2.get()) if p1 \u0026lt;= 0 or p2 \u0026lt;= 0: # 如果輸入\u0026lt;=0的數字也當成例外處理 raise Exception() if choice == \u0026#39;一\u0026#39;: # 買二件88折 p = 0.88 * (p1 + p2) elif choice == \u0026#39;二\u0026#39;: # 第二件6折 p = p1 + p2 * 0.6 else: # 第二件半價 p = p1 + p2 * 0.5 total.set(str(int(p))) # 顯示總額 except: # 例外處理：先全部歸0，再跳提示視窗 price1.set(\u0026#39;0\u0026#39;) price2.set(\u0026#39;0\u0026#39;) total.set(\u0026#39;0\u0026#39;) msg.showerror(\u0026#39;輸入錯誤!\u0026#39;, \u0026#39;請輸入正確的數字!\u0026#39;) btnstr.set(\u0026#39;算選項\u0026#39; + radiostr.get()) 1 2 3 4 ### select會在選中了某個折扣的時候被呼叫，此時會再呼叫calculate快速計算比較方便 def select(): btnstr.set(\u0026#39;算選項\u0026#39; + radiostr.get()) calculate() 1 2 3 4 5 6 #### 主視窗生成 win = tk.Tk() win.title(\u0026#39;從零開始學Python：第二件X折？\u0026#39;) win.geometry(\u0026#39;800x220\u0026#39;) win.resizable(False, False) win.iconbitmap(\u0026#39;unicorn.ico\u0026#39;) 1 2 3 4 ### Frame fm_cal: 放計算按鈕、\u0026#34;總額\u0026#34;文字label、總額金額顯示label fm_cal = tk.Frame(win, bg=\u0026#39;skyblue\u0026#39;, width=800, height=100) # fill表示沒填滿的部分是否填滿，BOTH表示xy方向都填滿，讀者可以試試看去掉的差別 fm_cal.pack(fill=tk.BOTH) 1 2 3 4 5 btnstr = tk.StringVar() # 初始化tk的字串變數 btnstr.set(\u0026#39;按我計算\u0026#39;) btn = tk.Button(fm_cal, bg=\u0026#39;#71C973\u0026#39;, fg=\u0026#39;white\u0026#39;, textvariable=btnstr, font=(\u0026#39;微軟正黑體\u0026#39;, 20), command=calculate, pady=10) # pad是指兩個元件之間空出多少距離 # side代表排版對齊時跟上個元件從哪個方向開始對齊 btn.pack(side=tk.LEFT, padx=10, pady=10) # padx/pady分別就是x方向跟y方向 1 2 3 4 lbl_text = tk.Label(fm_cal, bg=\u0026#39;#F95E62\u0026#39;, fg=\u0026#39;white\u0026#39;, text=\u0026#39;總額：\u0026#39;, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=10, pady=10) lbl_text.pack(side=tk.LEFT, padx=108) 1 2 3 4 5 6 total = tk.StringVar() # 初始化tk的字串變數 total.set(\u0026#39;0\u0026#39;) lbl_total = tk.Label(fm_cal, bg=\u0026#39;#F95E62\u0026#39;, fg=\u0026#39;white\u0026#39;, text=\u0026#39;0\u0026#39;, textvariable=total, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=10, pady=10) lbl_total.pack(side=tk.LEFT, padx=57, pady=10) 1 2 3 ### Frame fm_lbl: 放標籤及Radiobutton(折數) fm_lbl = tk.Frame(win, bg=\u0026#39;#FF9955\u0026#39;, width=800, height=150) fm_lbl.pack(side=tk.TOP, fill=tk.BOTH) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 lbl1 = tk.Label(fm_lbl, bg=\u0026#39;#F95E62\u0026#39;, fg=\u0026#39;white\u0026#39;, text=\u0026#39;第一件價格\u0026#39;, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=10, pady=10) lbl1.pack(side=tk.LEFT, padx=10, pady=10) lbl_plus = tk.Label(fm_lbl, bg=\u0026#39;#FF9955\u0026#39;, fg=\u0026#39;black\u0026#39;, text=\u0026#39;及\u0026#39;, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=10, pady=10) lbl_plus.pack(side=tk.LEFT, padx=10) lbl2 = tk.Label(fm_lbl, bg=\u0026#39;#F95E62\u0026#39;, fg=\u0026#39;white\u0026#39;, text=\u0026#39;第二件價格\u0026#39;, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=10, pady=10) lbl2.pack(side=tk.LEFT, padx=10) lbl_plus2 = tk.Label(fm_lbl, bg=\u0026#39;#FF9955\u0026#39;, fg=\u0026#39;black\u0026#39;, text=\u0026#39;及\u0026#39;, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=10, pady=10) lbl_plus2.pack(side=tk.LEFT, padx=10) lbl_coupon = tk.Label(fm_lbl, bg=\u0026#39;#F95E62\u0026#39;, fg=\u0026#39;white\u0026#39;, text=\u0026#39;折扣\u0026#39;, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=10, pady=10) lbl_coupon.pack(side=tk.LEFT, padx=10) 1 2 3 ### Frame fm_rad: 放Radiobutton(框一組自己對齊) fm_rad = tk.Frame(fm_lbl, bg=\u0026#39;#FF9955\u0026#39;, width=150, height=150, padx=30) fm_rad.pack(side=tk.LEFT, fill=tk.BOTH) 1 2 3 4 5 6 7 8 9 # StringVar的初始化值在第二個參數，第一個要填None radiostr = tk.StringVar(None, \u0026#39;一\u0026#39;) # command會對應到選取時呼叫的函式，同時當選擇到它，value的值會放入variable的變數 r1 = tk.Radiobutton(fm_rad, bg=\u0026#39;#FF9955\u0026#39;, text=\u0026#39;買兩件88折\u0026#39;, variable=radiostr, value=\u0026#39;一\u0026#39;, command=select) r1.pack(anchor=tk.W) # 另一個對齊方式，由上而下，但上下之間是靠左對齊 r2 = tk.Radiobutton(fm_rad, bg=\u0026#39;#FF9955\u0026#39;, text=\u0026#39;第二件6折\u0026#39;, variable=radiostr, value=\u0026#39;二\u0026#39;, command=select) r2.pack(anchor=tk.W) r3 = tk.Radiobutton(fm_rad, bg=\u0026#39;#FF9955\u0026#39;, text=\u0026#39;第二件半價\u0026#39;, variable=radiostr, value=\u0026#39;三\u0026#39;, command=select) r3.pack(anchor=tk.W) 1 2 3 ### Frame fm_ent: 放entry(輸入兩件商品分別的價格) fm_ent = tk.Frame(win, width=800, height=200) fm_ent.pack(side=tk.TOP, fill=tk.BOTH) 1 2 3 4 # ent1對應到price1 price1 = tk.StringVar(None, \u0026#39;0\u0026#39;) ent1 = tk.Entry(fm_ent, width=20, justify=\u0026#39;center\u0026#39;, textvariable=price1) ent1.pack(side=tk.LEFT, padx=17, pady=7, fill=tk.Y) 1 2 3 4 5 # 為了排版增加的空白label lbl_empty = tk.Label(fm_ent, text=\u0026#39;　\u0026#39;, font=(\u0026#39;微軟正黑體\u0026#39;, 20), padx=20) lbl_empty.pack(side=tk.LEFT) 1 2 3 4 # ent1對應到price2 price2 = tk.StringVar(None, \u0026#39;0\u0026#39;) ent2 = tk.Entry(fm_ent, width=20, justify=\u0026#39;center\u0026#39;, textvariable=price2) ent2.pack(side=tk.LEFT, padx=17, pady=7, fill=tk.Y) 1 2 # 開始整個主程式 win.mainloop() 最後的成果大概像這樣子：\n輸入錯誤時的對話框：\n這當中其實還有很多沒有講到的東西和元件，\n像是Listbox/Scrollbar等。\n但實在太多可以用的了，所以我們就先不管啦!\n有興趣的讀者可以再行深入玩玩看其他的元件呦XD!\n那麼今天也來一點簡單的練習吧！ 我們知道其實這個程式可能存在一些漏洞，\n最顯眼的應該就是在屈X氏的第二件O折這種事情，\n第二件一般都應該要取價低者計算才對。\n請想辦法修改上面的程式，使得當使用者有正常輸入數字，\n碰到上述狀況時，主動將價格排列正確，\n並同樣計算出正確的結果。 (Optional，可以不做)事實上，\ntkinter也有人撰寫可以在GUI界面拉出整個排版的程式，\n請有興趣的讀者在GitHub(https://github.com/)上進行搜尋，\n(例如”tkinter gui”)\n並找到一個適合你使用的介面，嘗試操作看看。 那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-07T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-22-gui-interface-tkinter/","title":"從零開始學Python (22) — 圖形化使用者介面Tkinter：直到現在，我還默默的等待"},{"content":"Day 21 基本圖形處理Pillow：花下是誰對影成雙 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。https://ithelp.ithome.com.tw/articles/10247292\n我們先來解昨天的練習吧！ 我們整理一下三種解的寫法，並且分別改名成cs1, cs2, cs3，\n那麼計算時要注意的有：\n為了確保有在運行，我們多加一個print()，可以自行拿掉。 cs2記得要給起始的字典，當然也可以直接在(n, dic)這邊給入也行。 記得下globals=globals()。 1 import timeit 1 2 3 4 5 6 7 8 9 10 def cs1(n): if n == 1 or n == 2: return n return cs1(n-1) + cs1(n-2) def cs2(n, dic): if n in dic: return dic[n] dic[n] = cs2(n-1, dic) + cs2(n-2, dic) return dic[n] 1 # dic = {1 : 1, 2 : 2} # 這個應該要放到setup裡 1 2 3 4 5 6 import functools @functools.lru_cache(maxsize=None) def cs3(n): if n == 1 or n == 2: return n return cs3(n-1) + cs3(n-2) 1 2 3 4 5 print(timeit.timeit(\u0026#39;print(cs1(35))\u0026#39;, globals=globals(), number=10)) print() print(timeit.timeit(\u0026#39;print(cs2(35, dic))\u0026#39;, setup=\u0026#39;dic = {1 : 1, 2 : 2}\u0026#39;, globals=globals(), number=10)) print() print(timeit.timeit(\u0026#39;print(cs3(35))\u0026#39;, setup=\u0026#39;import functools\u0026#39;, globals=globals(), number=10)) 接下來我們來講基本的影像處理。\nPIL(Python Imaging Library)是一套影像處理的模組，\n可以做到一些常見的影像處理和操作，\n比如裁切、平移、旋轉、縮放，\n調整亮度、色調，套用濾鏡等等，\n雖然是沒有專業的Photoshop(免費的有GIMP)等軟體厲害，\n但勝在可以在Python中用程式的方式來處理。\n但原本的PIL早在Python 2.7後就斷更了，\n但後來有一群好心人在這個基礎上開了一個新的版本，\n並命名為Pillow，除了支援Python 3.x的版本外，\n也加入了一些特性，所以我們這裡只需要安裝Pillow就行啦！\n由於不是內建函式庫，請利用安裝Python時，\n所附帶pip套件管理程式來安裝Pillow：\n1 pip install Pillow 我們下面使用從pixabay取得的免費圖片，\n進行接下來的操作(請下載後將圖片放置執行程式的位置)：\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; from PIL import Image \u0026gt;\u0026gt;\u0026gt; img = Image.open(\u0026#39;flower.jpg\u0026#39;) # 讀檔 \u0026gt;\u0026gt;\u0026gt; img.format, img.size, img.mode # 圖片格式，寬高，RGB彩色 (\u0026#39;JPEG\u0026#39;, (1920, 1280), \u0026#39;RGB\u0026#39;) \u0026gt;\u0026gt;\u0026gt; img.show() # 會將圖片顯示在螢幕上 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \u0026gt;\u0026gt;\u0026gt; img_rotate = img.rotate(180) # 將圖片順時針轉180度 \u0026gt;\u0026gt;\u0026gt; img_rotate.show() # 再顯示，應該會看到倒過來的花瓶 # 要裁切請用crop, 並且必須傳入Tuple，4個數分別代表左上(x1, y1)/右下(x2, y2) # 在一般程式的圖形處理中，原點(0, 0)在左上角 # 往右代表x增加，往下代表y增加，留意和一般座標的定法不同！ \u0026gt;\u0026gt;\u0026gt; img_crop = img_rotate.crop((960, 50, 1920, 1080)) \u0026gt;\u0026gt;\u0026gt; img_crop.show() # 將旁邊的空白修掉了一點，再來看看結果 # 按照決定的寬高來縮放調整圖片大小，同樣需要以Tuple表示 \u0026gt;\u0026gt;\u0026gt; img_resize = img_crop.resize((240, 250)) \u0026gt;\u0026gt;\u0026gt; img_crop.save(\u0026#39;crop.jpg\u0026#39;) \u0026gt;\u0026gt;\u0026gt; img_res = img_resize.rotate(180) # 再轉過來 \u0026gt;\u0026gt;\u0026gt; img_res.save(\u0026#39;res.bmp\u0026#39;) # 存到檔案，格式依照副檔名決定。 # 將img_res的內容貼到img_rotate上，並合成一張(當然還是要save過後才能看到改變) \u0026gt;\u0026gt;\u0026gt; img_rotate.paste(img_res, (0, 0)) \u0026gt;\u0026gt;\u0026gt; img_rotate.show() \u0026gt;\u0026gt;\u0026gt; img_rotate.save(\u0026#39;combination.png\u0026#39;) 最後的結果應該如下：\n上面我們簡單的使用了幾個屬性和方法：\nformat/size/mode(顯示格式/大小/色彩模式)\nshow/rotate/crop/paste/save(顯示圖片/旋轉/裁切/貼上/存檔)\n其他還有像是filter(濾鏡，在ImageFilter模組裡)可以作一些基本的特效，\n讀者有興趣可以再查找相關的方法嘗試。\n接下來，我們再來看看其他有趣的功能。\n假設今天我們想要製作簡單的長輩圖，\n(以原來的flower.jpg為例，其寬高為1920及1280)\n那我們需要Pillow裡面關於繪圖的模組來進行操作，\n該模組名為ImageDraw，\n可以用來處理繪製各種常見圖形，以及文字的方法。\n同時，由於一般的文字字型會有不能處理中文的問題，\n我們這邊會直接引入truetype的中文字型，\n讀者可以從C:\\Windows\\Fonts選擇一個喜歡的字型，\n並將其複製到你所使用的資料夾以利操作。\n我們下面會以複製”微軟正黑體”為例，\n複製到資料夾後會看到三個變形的字體，\n分別是msjh.ttc, msjhl.ttc, msjhbd.ttc，\n我們接下來選擇當中的msjhbd.ttc(粗體字型)進行操作。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 \u0026gt;\u0026gt;\u0026gt; from PIL import Image, ImageDraw, ImageFont # 如果要用空白畫布來繪製，可以用Image.new(\u0026#34;RGB\u0026#34;, (400,300))的形式建立。 \u0026gt;\u0026gt;\u0026gt; img = Image.open(\u0026#39;flower.jpg\u0026#39;) # copy可以用來複製一個Image物件，先備份一下，不行就拿它來蓋掉img \u0026gt;\u0026gt;\u0026gt; backup_img = img.copy() \u0026gt;\u0026gt;\u0026gt; backup_img.show() # 建立一個Draw物件，接下來draw所有的操作都會影響到img上面。 \u0026gt;\u0026gt;\u0026gt; draw = ImageDraw.Draw(img) \u0026gt;\u0026gt;\u0026gt; font = ImageFont.truetype(\u0026#39;./msjhbd.ttc\u0026#39;, 100) # 給定字型及大小 \u0026gt;\u0026gt;\u0026gt; text = \u0026#39;霹靂卡霹靂拉拉 波波力那貝貝魯多\u0026#39; \u0026gt;\u0026gt;\u0026gt; draw.text( (960, 320), text, font=font) # 好像太大了? \u0026gt;\u0026gt;\u0026gt; img.show() \u0026gt;\u0026gt;\u0026gt; font = ImageFont.truetype(\u0026#39;./msjhbd.ttc\u0026#39;, 50) # 改一下大小 \u0026gt;\u0026gt;\u0026gt; draw.text( (960, 320), text, font=font) # 再畫一次(應該會重複) \u0026gt;\u0026gt;\u0026gt; img.show() \u0026gt;\u0026gt;\u0026gt; img = backup_img.copy() # 洗掉吧！ \u0026gt;\u0026gt;\u0026gt; draw = ImageDraw.Draw(img) # 蓋回來會影響到draw跟img的連結，所以要重置 \u0026gt;\u0026gt;\u0026gt; draw.ink = 0xff0000 # 我們可以更改要使用的顏色(0x代表16進位) \u0026gt;\u0026gt;\u0026gt; draw.text( (960, 320), text, font=font) \u0026gt;\u0026gt;\u0026gt; img.show() # 看起來應該是藍色 # 也可以使用fill參數代入，順序是RGBA，也就是紅、綠、藍、透明度(alpha) \u0026gt;\u0026gt;\u0026gt; draw.text( (1060, 960), \u0026#39;認同請分享\u0026#39;, font=font, fill=(255,0,0,128)) \u0026gt;\u0026gt;\u0026gt; img.show() # 正式來囉！關於顏色的選擇可以使用如htmlcolorcodes等網站來取得色碼 \u0026gt;\u0026gt;\u0026gt; img = backup_img.copy() \u0026gt;\u0026gt;\u0026gt; draw = ImageDraw.Draw(img) \u0026gt;\u0026gt;\u0026gt; font = ImageFont.truetype(\u0026#39;./msjhbd.ttc\u0026#39;, 60) \u0026gt;\u0026gt;\u0026gt; draw.ink=0xF39C12 # draw.text()可以多行 \u0026gt;\u0026gt;\u0026gt; text = \u0026#39;請常唸\\n\\n　霹靂卡霹靂拉拉\\n　波波力那貝貝魯多\\n\\n唸時\\n須心無雜念 專注 便可心想事成\u0026#39; \u0026gt;\u0026gt;\u0026gt; draw.text( (1000, 300), text, font=font) \u0026gt;\u0026gt;\u0026gt; font = ImageFont.truetype(\u0026#39;./msjhbd.ttc\u0026#39;, 70) \u0026gt;\u0026gt;\u0026gt; draw.text( (1520, 960), \u0026#39;認同請分享\u0026#39;, font=font, fill=(165, 105, 189, 0)) \u0026gt;\u0026gt;\u0026gt; img.show() \u0026gt;\u0026gt;\u0026gt; img.save(\u0026#39;elder.jpg\u0026#39;) # 送給長輩吧XD！ 結果應該會像這樣：\n除了文字以外，當然也可以畫一些像是點、線、矩形、橢圓等幾何圖形，\n讀者可以再參照Pillow的ImageDraw模組的說明文件。\n今天的練習的部分，\n請嘗試運用今天提到的部分，\n幫筆者設計一個宣傳長輩圖XD!\n例如：\n「請常唸\n從LeetCode學演算法 基礎打底 進階扎實 面試通靈\n選購全套享優惠 居家旅行 通過面試 必備良藥\n認同請分享」\n歡迎貼到留言區讓大家看看你的設計XD!\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-06T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-21-image-processing-with-pillow/","title":"從零開始學Python (21) —  基本圖形處理Pillow：花下是誰對影成雙"},{"content":"Day 20 時間量測與效率檢驗：你的時間也不是你的時間 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247284\n我們先來解一下昨天的練習吧！ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \u0026gt;\u0026gt;\u0026gt; from datetime import date, datetime, time ,timedelta \u0026gt;\u0026gt;\u0026gt; now = date(2020, 10, 1) \u0026gt;\u0026gt;\u0026gt; mem = [date(2021,8,14), date(2021,2,14), date(2021,3,14), date(2020,10,3), d ate(2021,11,3)] \u0026gt;\u0026gt;\u0026gt; diff = sorted([d - now for d in mem]) # 你沒看錯，是可以排序的~ \u0026gt;\u0026gt;\u0026gt; diff [datetime.timedelta(days=2), datetime.timedelta(days=136), datetime.timedelta(da ys=164), datetime.timedelta(days=317), datetime.timedelta(days=398)] \u0026gt;\u0026gt;\u0026gt; for d in diff: ... print(str(d)) # 這樣顯示也可以啦！但好像可以簡單一點XD ... 2 days, 0:00:00 136 days, 0:00:00 164 days, 0:00:00 317 days, 0:00:00 398 days, 0:00:00 1 2 3 4 \u0026gt;\u0026gt;\u0026gt; days = [d.days for d in diff] # deltatime也可以單取其中的單位 \u0026gt;\u0026gt;\u0026gt; \u0026gt;\u0026gt;\u0026gt; days [2, 136, 164, 317, 398] 糟糕，這篇文貼出來的時間點第一個重要日子已經過了，\n只好希望小亦有記得阿啾的生日了XD\n上一篇我們提到了可以利用time.time()來計算，\n但如果要取平均的話，可能要自己寫迴圏來處理，\n但寫迴圏這件事情從根本上就有些破壞原本的結構，\n那麼該怎麼作比較好呢？\n我們可以利用timeit這個模組。\n當我們想簡單計算某個指令的耗時的時候，\n我們可以先用直接在命令提示字元裡下指令的方法，\n比方說：\n1 2 C:\\Users\\Desolve\\utils\u0026gt;python -m timeit \u0026#34;\u0026#39;-\u0026#39;.join(str(n) for n in range(100))\u0026#34; # 今晚，我想來點字串組合套餐 10000 loops, best of 5: 23 usec per loop “python -m” 可以讓我們得以呼叫一些標準函式庫的方法並輸入一些參數，\n以本例來說，就是呼叫timeit，\n然後要求它測試將0~99轉成字串並用”-”連接起來的耗時。\n我們可以看到在沒有預設的狀況下，它跑了10000次，\n並且取到最快的5次平均，結果平均速度是23微秒。\n這個相當於我們在直譯器或.py檔中使用timeit.timeit()，\n其方法為：\ntimeit.timeit(stmt, setup, timer, number) ，\nstmt: 被量測的程式碼\nsetup: 開始前可能有一些前置的設定要做的話就放在這裡\ntimer: 請忽視，這是預設的timer\nnumber: stmt執行的次數\n1 2 3 4 5 6 7 8 9 \u0026gt;\u0026gt;\u0026gt; import timeit \u0026gt;\u0026gt;\u0026gt; timeit.timeit(\u0026#34;\u0026#39;-\u0026#39;.join(str(n) for n in range(100))\u0026#34;) ... # 然後你就會發現卡住了，因為在這裡預設的次數是1000000次(一百萬次) # 連續按Ctrl+C以中斷上面的執行 \u0026gt;\u0026gt;\u0026gt; timeit.timeit(\u0026#34;\u0026#39;-\u0026#39;.join(str(n) for n in range(100))\u0026#34;, number=10000) 0.24359135900000695 # 需要多行的話，請使用分號分隔不同行 \u0026gt;\u0026gt;\u0026gt; timeit.timeit(stmt=\u0026#39;x=3;y=5;res=x*y\u0026#39;) 0.04275195899998607 如果想要重複timeit的測量，可以使用timeit.repeat()：\n1 2 3 4 5 # 相當於做timeit.timeit() 7遍 \u0026gt;\u0026gt;\u0026gt; timeit.repeat(stmt=\u0026#39;x=3;y=5;res=x*y\u0026#39;, number=10000, repeat=7) [0.0004259219999767083, 0.0004217530000687475, 0.0004227150000133406, 0.00042143 199993915914, 0.00043714699995689443, 0.0004217530000687475, 0.00044612800002141 74] 如果是要測試一整個函式，我們是可以將整段都塞進字串裡沒錯，\n但看起來太醜了XD!\n那麼，怎麼樣在不動到原有的程式碼的狀況下新增進行測試呢？\n我們可以使用類似如下的方式：\n1 import timeit 1 2 3 4 5 6 7 8 def f(): import os for path, dirs, files in os.walk(\u0026#39;.\u0026#39;): print(path) for f in files: print(os.path.join(path, f)) for d in dirs: print(os.path.join(path, d)) 1 2 3 4 # 下面這三行的做的事情是一樣的 print(timeit.timeit(f, number=5)) # print(timeit.timeit(\u0026#39;f()\u0026#39;, setup=\u0026#39;from __main__ import f\u0026#39;, number=5)) # print(timeit.timeit(\u0026#39;f()\u0026#39;, globals=globals(), number=5)) 其結果如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 C:\\Users\\Desolve\\utils\u0026gt;python fromzero . .\\bookstore.json .\\check.py .\\fromzero.py .\\poem.txt .\\schedule.py .\\__init__.py .\\csv .\\json .\\__pycache__ .\\csv .\\csv\\student.csv .\\csv\\student_dic.csv .\\json .\\json\\classA.json .\\__pycache__ .\\__pycache__\\check.cpython-38.pyc .\\__pycache__\\schedule.cpython-38.pyc .\\__pycache__\\__init__.cpython-38.pyc ...(會再重複4次) 0.008256415 stmt也可以直接傳入函數名稱，這時候後面就不用加括號了，\n因為是當成一個函數物件；\n如果當成一個字串來傳進去的話，\n就必須要在setup的時後告訴它主程式 有這個東西，\n這樣Python才認得到呦！\n(也就是__main__)\n或者，也可以使用globals=globals()，\n直接將所有的程式碼當成全域來用，也可以達到相同的效果。\n昨天到今天這兩篇，應該可以幫助讀者對於時間相關的方法有初步的認識。\n事實上要再深究的話，執行時間還會受到一些額外的影響，\n比如Python的gc(資源回收處理)，執行程式時電腦其他程式占用CPU資源的影響等，\n但這比較深入一些，我們就不在這裡細究了XD！\n(註：timeit預設會把gc關掉，如果要測打開的狀況，\n可以在setup放入’gc.enable()’。)\n最後我們也來做個練習吧！ 還記得先前我們講遞迴嗎(第九篇)？\n我們後面有做過練習，在第十篇有解答。\n我們比較過沒有做好的遞迴的一個解答，\n跟有記錄前面答案的遞迴，且提供了二個解答；\n請比較這三種在做n=35 的時候的計算時速度的差異。\n(注意：只做n=35 即可，不用算1~35，此外number取10次 就好。)\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-05T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-20-time-measurements-and-efficiency-examinations/","title":"從零開始學Python (20) — 時間量測與效率檢驗：你的時間也不是你的時間"},{"content":"Day 19 日期與時間：你知不知道，我等到花兒也謝了 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10247281\n接下來我們要聊到日期與時間的處理相關模組：\ndatetime跟time。\n請想像一下，在人生當中，是不是常常有要算日子和時間的時候？\n不論是算退伍還有多少天；\n算紀念日520天是什麼時候；\n算紀念日1000天是什麼時候；\n算紀念日2000天是什麼時候……XD\n我們可以利用Python的datetime模組來幫忙計算時間日期與時間差，\n這樣子就不會在被問今天是什麼日子的時候答不出來了(吧)！\ndatetime 當中就有date物件 和time物件 ，\n接下來的示範還是屬於datetime模組的範疇，\n請大家不要跟後面的time模組 搞混歐！\n我們先來看看操作日期的date 物件的用法：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026gt;\u0026gt;\u0026gt; from datetime import date \u0026gt;\u0026gt;\u0026gt; doubleten = date(2020, 10, 10) # 順序是年/月/日 \u0026gt;\u0026gt;\u0026gt; doubleten.year, doubleten.month, doubleten.day (2020, 10, 10) # 用isoformat()和str()都可以轉成用\u0026#34;-\u0026#34;連接的字串 \u0026gt;\u0026gt;\u0026gt; doubleten.isoformat(), str(doubleten) (\u0026#39;2020-10-10\u0026#39;, \u0026#39;2020-10-10\u0026#39;) \u0026gt;\u0026gt;\u0026gt; today = date.today() # today()會取到今天 \u0026gt;\u0026gt;\u0026gt; str(today) # isoformat格式會補0 \u0026#39;2020-10-01\u0026#39; # 2020-10-01是星期四，weekday的記法是0(星期一)~6(星期日) # isoweekday的記法則是1(星期一)~7(星期日) \u0026gt;\u0026gt;\u0026gt; today.weekday(), today.isoweekday() (3, 4) # strftime可用來格式化想要的顯示樣態和目標 \u0026gt;\u0026gt;\u0026gt; doubleten.strftime(\u0026#39;%Y--%m--%d, WeekDay: %a\u0026#39;) \u0026#39;2020--10--10, WeekDay: Sat\u0026#39; 關於strftime以及後面常見的格式，\n大體上會跟一般通用的表示法相同，\n例如%Y代表年，%m代表月，%d代表日，%a則代表星期幾的縮寫；\n其他還有%H(小時)、%M(分)、%S(秒)等等，\n可以參考strftime() 和 strptime() Format Codes。\ndatetime中的time物件操作方式也很類似：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 \u0026gt;\u0026gt;\u0026gt; from datetime import time \u0026gt;\u0026gt;\u0026gt; time() # datetime的time.time()預設是從0開始 datetime.time(0, 0) \u0026gt;\u0026gt;\u0026gt; now = time() \u0026gt;\u0026gt;\u0026gt; now.isoformat() \u0026#39;00:00:00\u0026#39; \u0026gt;\u0026gt;\u0026gt; now = time(0,0,0,38) # 最小單位到微秒(百萬分之一秒，也就是10e-6) \u0026gt;\u0026gt;\u0026gt; now.microsecond # 取微秒 38 \u0026gt;\u0026gt;\u0026gt; now = time(hour=19, second=50) \u0026gt;\u0026gt;\u0026gt; str(now) \u0026#39;19:00:50\u0026#39; \u0026gt;\u0026gt;\u0026gt; now.strftime(\u0026#39;%H-%M\u0026#39;) # 同樣可以適用strftime \u0026#39;19-00\u0026#39; 或者，兩者都要的話，\n可以直接使用datetime.datetime物件！\n1 2 3 4 5 6 7 8 9 10 \u0026gt;\u0026gt;\u0026gt; from datetime import datetime \u0026gt;\u0026gt;\u0026gt; datetime.today() # 現在的時間，計到微秒 datetime.datetime(2020, 10, 1, 17, 37, 7, 490703) \u0026gt;\u0026gt;\u0026gt; datetime.utcnow() # UTC標準時間(所以台灣是+8，看出來了嗎？) datetime.datetime(2020, 10, 1, 9, 37, 43, 823644) # str這邊和isoformat就會有點不一樣了，isoformat會用\u0026#34;T\u0026#34;來分隔。 \u0026gt;\u0026gt;\u0026gt; str(datetime.now()) \u0026#39;2020-10-01 17:39:03.953659\u0026#39; \u0026gt;\u0026gt;\u0026gt; datetime.now().isoformat() \u0026#39;2020-10-01T17:39:23.671787\u0026#39; 讀者可能會問：\n「不對阿，說好的算紀念日呢？」\n要計算日期差距相關的處理，\n我們要用到datetime的另一個物件：\ntimedelta 。\ntimedelta的建立很簡單，就是timedelta(時間差)。\n下面我們假設小亦向阿啾在今年的情人節2/14告白並成功了 ，\n接下來我們先來算一下到現在(10/1)為止 ，\n他們已經經過了幾天，到後面的紀念日又還有多久呢？\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026gt;\u0026gt;\u0026gt; from datetime import date, datetime, time ,timedelta \u0026gt;\u0026gt;\u0026gt; valentine = date(2020, 2, 14) \u0026gt;\u0026gt;\u0026gt; today = date.today() \u0026gt;\u0026gt;\u0026gt; romanticlen = today - valentine # date相減會變成timedelta # 算一算交往時間吧！ \u0026gt;\u0026gt;\u0026gt; romanticlen datetime.timedelta(days=230) # 小亦要記得的幾個紀念日 \u0026gt;\u0026gt;\u0026gt; remember = [100, 200, 520, 1000, 2000] # 注意timedelta也可以用乘上數字來和定點日期相加減計算，相當有彈性 \u0026gt;\u0026gt;\u0026gt; memorialday = [valentine + timedelta(days=i) for i in remember] \u0026gt;\u0026gt;\u0026gt; memorialday # 咦？這時間怎麼好像有的已經過了？ [datetime.date(2020, 5, 24), datetime.date(2020, 9, 1), datetime.date(2021, 7, 1 8), datetime.date(2022, 11, 10), datetime.date(2025, 8, 6)] \u0026gt;\u0026gt;\u0026gt; diff = [i - today for i in memorialday] # 來減看看！ \u0026gt;\u0026gt;\u0026gt; diff # 小亦你很糟糕歐，有兩個紀念日已經過了！阿啾會哭哭呦XD [datetime.timedelta(days=-130), datetime.timedelta(days=-30), datetime.timedelta (days=290), datetime.timedelta(days=770), datetime.timedelta(days=1770)] 講完了datetime，我們現在來講time 模組。\ntime模組比較簡單一點點，基本上最常用到的就是time.time()。\ntime.time()會給出Unix標準時間 ，\n也就是以1970年1月1號起算到目前為止帶小數點的總秒數(不用背，不會考XD)。\n如果使用localtime()的話，則會換算成現在所在時區的時間。\n1 2 3 4 5 6 \u0026gt;\u0026gt;\u0026gt; import time \u0026gt;\u0026gt;\u0026gt; time.time() 1601547391.7189288 \u0026gt;\u0026gt;\u0026gt; time.localtime() # 筆者電腦目前是2020年10月1日下午6點16分 time.struct_time(tm_year=2020, tm_mon=10, tm_mday=1, tm_hour=18, tm_min=16, tm_s ec=34, tm_wday=3, tm_yday=275, tm_isdst=0) 上面範例中的struct_time是time的另一個物件，\n作用是可以用來給定一個指定的時間方便處理。\n我們也可以使用time.ctime()或time.strftime(格式化字串, 時間)，\n將其轉換成易讀的字串。\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; now = time.localtime() \u0026gt;\u0026gt;\u0026gt; time.ctime() \u0026#39;Thu Oct 1 18:22:46 2020\u0026#39; \u0026gt;\u0026gt;\u0026gt; time.strftime(\u0026#39;現在是%A, %Y年%m月%d日的%H時%M分%S秒\u0026#39;, now) \u0026#39;現在是Thursday, 2020年10月01日的18時22分35秒\u0026#39; 不同的國家語系，給出來的縮寫等會不同，\n如果要再精細轉換的話，可以使用local進行setlocale()的操作，\n有興趣的話，可以再進一步研究一下用法。\n但最常被簡單用到的方式還是time.time()跟time.sleep()了 !\n通常狀況下，我們會在跑完一段想測量的程式以後，\n使用time.time()的差值 來計算時間。\ntime.sleep()則可以讓程式暫時停止執行指定的秒數 ，\n待時間到才繼續運作。\n我們拿前面的os的程式來修改一下測試這兩個方法，\n會發現多次測試下，扣掉10秒以後，(因為10秒是我們睡掉的XD)\n耗時其實差距蠻大的。\n要取得一個比較良好的數據，\n就可能要用迴圏來多測幾次，再取平均值。\n1 2 3 4 5 6 7 8 9 10 11 import os, time start = time.time() for path, dirs, files in os.walk(\u0026#39;.\u0026#39;): print(path) for f in files: print(os.path.join(path, f)) for d in dirs: print(os.path.join(path, d)) time.sleep(10) # 睡10秒鐘(可以給小數) end = time.time() 1 print(\u0026#34;總耗時：%f\u0026#34; % (end - start)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 C:\\Users\\Desolve\\utils\u0026gt;python fromzero.py . .\\bookstore.json .\\check.py .\\fromzero.py .\\poem.txt .\\schedule.py .\\__init__.py .\\csv .\\json .\\__pycache__ .\\csv .\\csv\\student.csv .\\csv\\student_dic.csv .\\json .\\json\\classA.json .\\__pycache__ .\\__pycache__\\check.cpython-38.pyc .\\__pycache__\\schedule.cpython-38.pyc .\\__pycache__\\__init__.cpython-38.pyc 總耗時：10.003572 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 C:\\Users\\Desolve\\utils\u0026gt;python fromzero.py . .\\bookstore.json .\\check.py .\\fromzero.py .\\poem.txt .\\schedule.py .\\__init__.py .\\csv .\\json .\\__pycache__ .\\csv .\\csv\\student.csv .\\csv\\student_dic.csv .\\json .\\json\\classA.json .\\__pycache__ .\\__pycache__\\check.cpython-38.pyc .\\__pycache__\\schedule.cpython-38.pyc .\\__pycache__\\__init__.cpython-38.pyc 總耗時：10.002572 最後我們來做個練習吧！ 承前面小亦和阿啾的狀況需要補救，\n請幫其重新列出接下來到明年(2021)幾個重要的節日的時間，\n計算距離2020–10–01的天數，並排序將其從近排到遠 ，\n這樣小亦才不會漏掉。(1000天或2000天什麼的先不用算)\n[七夕(2021–08–14)、情人節(2021–02–14)、白色情人節(2021–03–14)、阿啾生日(2020–10–03)、阿啾生日(2021–10–03)]\n(什麼？你說為什麼有兩個生日？生日當然要每個生日都要過阿，\n會問這個問題的讀者請檢討一下自己是不是憑實力單身阿XD?) 那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-19-date-and-time/","title":"從零開始學Python (19) — 日期與時間：你知不知道，我等到花兒也謝了"},{"content":"Day 18 系統模組：走路的不是強尼，是你心中的OS 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。https://ithelp.ithome.com.tw/articles/10246454\n我們先來看看昨天的練習吧！ 一般來說，我們可以先打開來觀察，\n將其複製到JSON Online Editor上看看右邊的tree長什麼樣子，\n這樣會有助於後面思考操作方式。\n請下載下來並放到你自己執行的目錄(筆者命名為bookstore.json) 用以下的讀取方式，將json檔載入到bs裡： 1 2 3 import json with open(\u0026#39;bookstore.json\u0026#39;, \u0026#39;r\u0026#39;, encoding=\u0026#34;utf-8\u0026#34;) as f: bs = json.load(f) bs是一個串列(因為在這個json裡面是以array的型式儲存的) 我們可以用以下的方式(或者你要去用地址找也可以) 1 2 # 記得list comprehension嗎? taipei = [i for i in bs if \u0026#39;臺北市\u0026#39; in i[\u0026#39;cityName\u0026#39;]] taipei中特色書店點閱數超過2000的店家是哪幾家呢？請列出其名字。 1 2 3 # 我們要的是名字，所以要取\u0026#39;name\u0026#39;，判斷標準則是用hitRate。 \u0026gt;\u0026gt;\u0026gt; [i[\u0026#39;name\u0026#39;] for i in taipei if i[\u0026#39;hitRate\u0026#39;] \u0026gt; 2000] [\u0026#39;茉莉二手書店(臺大店)\u0026#39;, \u0026#39;信誼小太陽親子書房(臺北重慶店)\u0026#39;, \u0026#39;田園城市生活風格書店\u0026#39;, \u0026#39;亞典藝術書店\u0026#39;, \u0026#39;古原軒書店\u0026#39;] 請留意到，這個練習是相對比較輕鬆的，\n因為當中所用到的元素都沒有缺漏的部分，\n所以不會產生任何錯誤；\n但實務狀況上，常常會有一些資料是短少的，\n這時候就要先做過資料的前處理(preprocessing)以後，\n將缺漏的部分去除，或者補上適當的值，才能讓資料得以正常使用。\n在資料清理(data cleaning)這部分，Python常用的有pandas跟numpy，\n以後我們有機會再來介紹。\n我們今天要來講的是系統模組(os)。\nOS是Operating System(作業系統)的縮寫，\n主要作用是提供你所使用的作業系統的一些功能，\n例如檔案的路徑檢查、列出檔案列表、\n檔案複製/移動/改名/刪除等。\n下面的示範，我們是基於使用者在以下的資料夾環境操作的：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 C:\\Users\\Desolve\\utils\u0026gt;tree /f 列出資料夾 PATH 磁碟區序號為 D6BD-47D7 C:. │ bookstore.json │ check.py │ fromzero.py │ poem.txt │ schedule.py │ __init__.py │ ├─csv │ student.csv │ student_dic.csv │ ├─json │ classA.json │ └─__pycache__ check.cpython-38.pyc schedule.cpython-38.pyc __init__.cpython-38.pyc 要使用os，最重要的就是先import啦!\n請留意一件事情，\n在Unix系列的系統裡面，路徑分隔資料夾或檔案是使用”/”來處理的 ，\nWindows系列的系統中，則是使用”\\”，兩者剛好相反 。\n如果我們想看某個檔案或目錄是否存在於特定位置 ，\n我們可以使用os.path.exists() ，可以是相對路徑或絕對路徑 。\n相對路徑是從現在的資料夾為基準出發，來看到到目標位置要怎麼移動；\n絕對路徑則是從Unix的根目錄或Windows的C槽D槽之類的起始點出發；\n所以以相對路徑來起頭的，前面會有一個”./”或”.”開頭 ，\n用來表示從現在所在位置起算(一個點代表現在所在位置，兩個點代表上一層)\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \u0026gt;\u0026gt;\u0026gt; import os \u0026gt;\u0026gt;\u0026gt; os.path.exists(\u0026#39;check.py\u0026#39;) True \u0026gt;\u0026gt;\u0026gt; os.path.exists(\u0026#39;poem.txt\u0026#39;) True \u0026gt;\u0026gt;\u0026gt; os.path.exists(\u0026#39;.\\json\\classA.json\u0026#39;) True \u0026gt;\u0026gt;\u0026gt; os.path.exists(\u0026#39;./json/classA.json\u0026#39;) # 實際上用linux的寫法給Python去認也行得通，Python會明白含義 True \u0026gt;\u0026gt;\u0026gt; os.path.exists(\u0026#39;./json/classB.json\u0026#39;) # 不存在就回傳False False \u0026gt;\u0026gt;\u0026gt; os.path.exists(\u0026#39;C:\\Users\\Desolve\\utils\\json\\classA.json\u0026#39;) # 用絕對路徑時避免不必要的麻煩，請多加一個\u0026#34;\\\u0026#34;將可能造成的轉義去除 File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1 SyntaxError: (unicode error) \u0026#39;unicodeescape\u0026#39; codec can\u0026#39;t decode bytes in position 2-3: truncated \\UXXXXXXXX escape \u0026gt;\u0026gt;\u0026gt; os.path.exists(\u0026#39;C:\\\\Users\\\\Desolve\\\\utils\\\\json\\\\classA.json\u0026#39;) True 再來是分開來的檢查這個路徑是否是檔案/資料夾的方法：\nos.path.isfile()及os.path.isdir() 。\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; os.path.isfile(\u0026#39;./json/classA.json\u0026#39;) # 存在，且是檔案 True \u0026gt;\u0026gt;\u0026gt; os.path.isfile(\u0026#39;./json/classB.json\u0026#39;) # 不存在則回傳False False \u0026gt;\u0026gt;\u0026gt; os.path.isdir(\u0026#39;./json/classA.json\u0026#39;) # 是檔案，不是資料夾 False \u0026gt;\u0026gt;\u0026gt; os.path.isdir(\u0026#39;./json\u0026#39;) # 是資料夾 True 那麼如果想要複製或移動檔案呢？這就要用到另一個模組shutil 了：\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; import shutil \u0026gt;\u0026gt;\u0026gt; shutil.copy(\u0026#39;poem.txt\u0026#39;, \u0026#39;poem2.txt\u0026#39;) # 前面是來源，後面是目的地 \u0026#39;poem2.txt\u0026#39; \u0026gt;\u0026gt;\u0026gt; shutil.move(\u0026#39;poem2.txt\u0026#39;, \u0026#39;poem3.txt\u0026#39;) # 移動檔案並更名 \u0026#39;poem3.txt\u0026#39; 要修改名字的話，則可以使用os.rename() ：\n1 \u0026gt;\u0026gt;\u0026gt; os.rename(\u0026#39;./json/poem3.txt\u0026#39;, \u0026#39;poem3.txt\u0026#39;) # 也可以做為移動檔案用 要新增/刪除資料夾的話，可以使用os.mkdir()/os.rmdir() ，\n刪除檔案則使用os.remove() ：\n(有沒有覺得跟Unix系統的shell script很像呢XD?)\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; os.mkdir(\u0026#39;poems\u0026#39;) # 開一個新的資料夾 \u0026gt;\u0026gt;\u0026gt; os.rename(\u0026#39;poem3.txt\u0026#39;, \u0026#39;./poems/poem3.txt\u0026#39;) # 將poem3.txt移入 \u0026gt;\u0026gt;\u0026gt; os.rmdir(\u0026#39;poems\u0026#39;) # 將poems資料夾刪除...咦? Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; OSError: [WinError 145] 目錄不是空的。: \u0026#39;poems\u0026#39; \u0026gt;\u0026gt;\u0026gt; os.remove(\u0026#39;poems/poem3.txt\u0026#39;)　# 只能先將檔案移除 \u0026gt;\u0026gt;\u0026gt; os.rmdir(\u0026#39;poems\u0026#39;) # 再移除資料夾 讀者可能會問：\n「我怎麼會知道要先刪除哪些檔案？」\n問的好！我們可以使用os.listdir()先列出資料夾的所有檔案及資料夾 ：\n(注意，只會列出第一層的，再往下的子資料夾就不會展開囉！)\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; os.listdir() [\u0026#39;bookstore.json\u0026#39;, \u0026#39;check.py\u0026#39;, \u0026#39;csv\u0026#39;, \u0026#39;fromzero.py\u0026#39;, \u0026#39;json\u0026#39;, \u0026#39;poem.txt\u0026#39;, \u0026#39;schedule.py\u0026#39;, \u0026#39;__init__.py\u0026#39;, \u0026#39;__pycache__\u0026#39;] \u0026gt;\u0026gt;\u0026gt; os.listdir(\u0026#39;csv\u0026#39;) [\u0026#39;student.csv\u0026#39;, \u0026#39;student_dic.csv\u0026#39;] 最後，是我們的終極必殺武器：os.walk() 。\nos.walk()就像一個偏執的用路人一樣，\n它就是要將整個資料夾，連同子資料夾都走過一遍才會罷休。\n走完之後，所有的內容會以(dirpath, dirnames, filenames)的形式回傳，\n我們可以使用for … in …的方式取得，\n請看範例：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 for root, dirs, files in os.walk(\u0026#39;.\u0026#39;):　# os.walk必須要給一個起始點 print(root) for f in files: print(os.path.join(root, f)) # os.path.join()可用來處理路徑和檔案的結合 # 結果如下 . .\\bookstore.json .\\check.py .\\fromzero.py .\\poem.txt .\\schedule.py .\\__init__.py .\\csv .\\csv\\student.csv .\\csv\\student_dic.csv .\\json .\\json\\classA.json .\\__pycache__ .\\__pycache__\\check.cpython-38.pyc .\\__pycache__\\schedule.cpython-38.pyc .\\__pycache__\\__init__.cpython-38.pyc 如果想要刪除掉某個目錄以下的所有檔案及資料夾，\n可以參考Python的Document提供的範例：\n請特別留意慎用以下操作，\n底下的動作可是真的會將目標資料夾全刪光的！！！\n尤其是Unix系列的系統，\n如果給的top起始點是”/”(根目錄)而非”./”(當前目錄)，\n則會將整個檔案系統都砍光光呦！！！\n1 2 3 4 5 for root, dirs, files in os.walk(top, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) 今天我們介紹了os中跟檔案系統相關操作有關的方法，\n其他當然也有很多不錯的相關模組，\n例如剛剛有提到的shutil ，或是pathlib ，\n有興趣的讀者可再行挖掘。\n那麼，我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\n","date":"2020-10-03T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-18-system-modules/","title":"從零開始學Python (18) — 系統模組：走路的不是強尼，是你心中的OS"},{"content":"Day 17 檔案讀寫：妳出現在我詩的每一頁(下) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10246077\n上一回我們介紹了CSV的格式以及使用方法，\n事實上很多檔案如果是以Excel能表達的狀態下，\nCSV應該可以應付絕大多數的需求了！\n但對於許多程式開發，或較為複雜的資料，\n使用CSV就會稍嫌力有未逮，\n因為CSV並不能夠簡單分出比較大量的層級。\n舉例來說，如果我們現在有一組資料，\n內含了一個學校的兩個班級，\n那可能會長這樣：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 how_school = { \u0026#34;校長\u0026#34;: \u0026#34;How哥\u0026#34;, \u0026#34;工友\u0026#34;: \u0026#34;林阿嘉\u0026#34;, \u0026#34;class\u0026#34;: { \u0026#34;A\u0026#34;: { \u0026#34;teacher\u0026#34;: \u0026#34;蔡阿嘎\u0026#34;, \u0026#34;students\u0026#34;: { \u0026#34;阿明\u0026#34;: {\u0026#34;數學\u0026#34;:55, \u0026#34;英文\u0026#34;:70, \u0026#34;物理\u0026#34;:55}, \u0026#34;HowHow\u0026#34;: {\u0026#34;數學\u0026#34;:80, \u0026#34;英文\u0026#34;:60, \u0026#34;物理\u0026#34;:40} } }, \u0026#34;B\u0026#34;: { \u0026#34;teacher\u0026#34;: \u0026#34;二伯\u0026#34;, \u0026#34;students\u0026#34;: { \u0026#34;小美\u0026#34;: {\u0026#34;數學\u0026#34;:90, \u0026#34;英文\u0026#34;:88, \u0026#34;物理\u0026#34;:100}, \u0026#34;蔡哥\u0026#34;: {\u0026#34;數學\u0026#34;:50, \u0026#34;英文\u0026#34;:50, \u0026#34;物理\u0026#34;:40} } } } } 像這樣子的東西，就很難使用csv簡單表現出來了！\n所以我們一般會使用JSON來處理這樣子的結構。\nJSON是JavaScript Object Notation的縮寫，\n顧名思義，本來是用在JavaScript的格式。\n後來大家發現實在是很好用，\n所以也被拿來在很多地方做為資料交換用的格式。\n當然，如果要人從頭刻出來，可能中間會有一些沒寫好的地方容易出錯，\n這時候我們需要一個用來檢查格式的工具，\n讀者可以搜尋 ’JSON online editor’ ，選擇自己用得順手的來嘗試編寫，\n以下我們就拿在 https://jsoneditoronline.org/ 上操作做為範例：\n進入時，幾個簡單的操作就看中間的部分：\n左邊預設是code(原始的json碼)，右邊預設是tree(JSON Object長的樣子)；\n我們可以寫好左邊以後，按一下**”Copy\u0026gt;”** 將其複製到右邊產生tree，\n如果失敗的話，這個編輯器就會給你有關哪一行出錯的提示。\n(反過來先產生tree再讓它翻成code也可以呦！)\n預設裡應該會給出一段json碼如下，這是用來提示基本關於JSON的用法。\n1 2 3 4 5 6 7 8 9 10 11 12 13 \u0026#34;array\u0026#34;: [ 1, 2, 3 ], \u0026#34;boolean\u0026#34;: true, \u0026#34;color\u0026#34;: \u0026#34;gold\u0026#34;, \u0026#34;null\u0026#34;: null, \u0026#34;number\u0026#34;: 123, \u0026#34;object\u0026#34;: { \u0026#34;a\u0026#34;: \u0026#34;b\u0026#34;, \u0026#34;c\u0026#34;: \u0026#34;d\u0026#34; }, 首先留意到，每個單位一般都會以一個字串做為它的名字，\n和Python不同，字串請全數用**雙引號(“”)**來括住，單引號在這裡是行不通的！\nJSON常用的格式有以下幾個：\narray(陣列) ：跟Python的串列基本相似，\n除了前面有一個它的名字(可自行命名)，\n後面使用中括號框住，以**”,”** 逗號分隔。\nboolean(布林值) ：可以放在值的地方，使用true/false (注意是全小寫!)。\ncolor(色彩) ：用文字來表示色彩的話，有些編輯器 可以幫你解讀出來XD。\nnull(空) ：相當於Python的None，表示沒有東西存在。\nnumber(數字) ：在JSON中數字可以是整數或小數。\nobject(物件) ：使用大括號框起，裡面的每一段跟字典相似，\n使用key:value 的型態放入，\n可以多層(但是key必須要是字串 )。\n那麼，一段Python中的資料結構，要怎麼轉換成JSON呢？\n我們可以import json，並使用dumps() 方法來處理：\n(如果是從檔案的話要用dump()方法)\n1 2 3 import json how_json = json.dumps(how_school) print(how_json) 結果如下……咦？這什麼鬼東西？！\n1 2 3 4 C:\\Users\\Desolve\u0026gt;python fromzero.py {\u0026#34;\\u6821\\u9577\u0026#34;: \u0026#34;How\\u54e5\u0026#34;, \u0026#34;\\u5de5\\u53cb\u0026#34;: \u0026#34;\\u6797\\u963f\\u5609\u0026#34;, \u0026#34;class\u0026#34;: {\u0026#34;A\u0026#34;: {\u0026#34;teacher\u0026#34;: \u0026#34;\\u8521\\u963f\\u560e\u0026#34;, \u0026#34;students\u0026#34;: {\u0026#34;\\u963f\\u660e\u0026#34;: {\u0026#34;\\u6578\\u5b78\u0026#34;: 55, \u0026#34;\\u82f1\\u6587\u0026#34;: 70, \u0026#34;\\u7269\\u7406 \u0026#34;: 55}, \u0026#34;HowHow\u0026#34;: {\u0026#34;\\u6578\\u5b78\u0026#34;: 80, \u0026#34;\\u82f1\\u6587\u0026#34;: 60, \u0026#34;\\u7269\\u7406\u0026#34;: 40}}}, \u0026#34;B\u0026#34;: {\u0026#34;teacher\u0026#34;: \u0026#34;\\u4e8c\\u4f2f\u0026#34;, \u0026#34;students\u0026#34;: {\u0026#34;\\u5c0f\\u7f8e\u0026#34;: {\u0026#34;\\u6578\\u5b78\u0026#34;: 90, \u0026#34;\\u82f1\\u6587\u0026#34;: 88, \u0026#34;\\u7269\\u7406\u0026#34;: 100}, \u0026#34;\\u8521\\u54e5\u0026#34;: {\u0026#34;\\u6578\\u5b78\u0026#34;: 50, \u0026#34;\\u82f1\\u6587\u0026#34;: 50, \u0026#34;\\u7269\\u7406\u0026#34;: 40}}}}} Python提供的json模組在進行dump/dumps方法時，\n預設所有輸進來的內容全都是ASCII Code，\n所以當超出這個範圍，例如我們輸入的中文，\n實質上應該要用UTF-8來表達才對。\n所以我們改一下它的參數即可：\n1 2 3 import json how_json = json.dumps(how_school, ensure_ascii=False) # 我沒有要全ASCII，給我改回來XD print(how_json) 執行結果如下：\n1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py {\u0026#34;校長\u0026#34;: \u0026#34;How哥\u0026#34;, \u0026#34;工友\u0026#34;: \u0026#34;林阿嘉\u0026#34;, \u0026#34;class\u0026#34;: {\u0026#34;A\u0026#34;: {\u0026#34;teacher\u0026#34;: \u0026#34;蔡阿嘎\u0026#34;, \u0026#34;students\u0026#34;: {\u0026#34;阿明\u0026#34;: {\u0026#34;數學\u0026#34;: 55, \u0026#34;英文\u0026#34;: 70, \u0026#34;物理\u0026#34;: 55}, \u0026#34;HowHow\u0026#34;: {\u0026#34;數學\u0026#34;: 80, \u0026#34;英文\u0026#34;: 60, \u0026#34;物理\u0026#34;: 40}}}, \u0026#34;B\u0026#34;: {\u0026#34;teacher\u0026#34;: \u0026#34; 二伯\u0026#34;, \u0026#34;students\u0026#34;: {\u0026#34;小美\u0026#34;: {\u0026#34;數學\u0026#34;: 90, \u0026#34;英文\u0026#34;: 88, \u0026#34;物理\u0026#34;: 100}, \u0026#34;蔡哥\u0026#34;: {\u0026#34;數學\u0026#34;: 50, \u0026#34;英文\u0026#34;: 50, \u0026#34;物理\u0026#34;: 40}}}}} 剛剛是將一個Python的資料結構轉成JSON字串，\n那我們想要從JSON字串轉回Python的結構的話，\n可以使用loads方法：\n1 2 3 4 5 6 7 8 9 10 11 \u0026gt;\u0026gt;\u0026gt; how2 = json.loads(how_json) # 接續前面的how_json \u0026gt;\u0026gt;\u0026gt; how2 {\u0026#39;校長\u0026#39;: \u0026#39;How哥\u0026#39;, \u0026#39;工友\u0026#39;: \u0026#39;林阿嘉\u0026#39;, \u0026#39;class\u0026#39;: {\u0026#39;A\u0026#39;: {\u0026#39;teacher\u0026#39;: \u0026#39;蔡阿嘎\u0026#39;, \u0026#39;students\u0026#39;: {\u0026#39;阿明\u0026#39;: {\u0026#39;數學\u0026#39;: 55, \u0026#39;英文\u0026#39;: 70, \u0026#39;物理\u0026#39;: 55}, \u0026#39;HowHow\u0026#39;: {\u0026#39;數學\u0026#39;: 80, \u0026#39;英文\u0026#39;: 60, \u0026#39;物理\u0026#39;: 40}}}, \u0026#39;B\u0026#39;: {\u0026#39;teacher\u0026#39;: \u0026#39; 二伯\u0026#39;, \u0026#39;students\u0026#39;: {\u0026#39;小美\u0026#39;: {\u0026#39;數學\u0026#39;: 90, \u0026#39;英文\u0026#39;: 88, \u0026#39;物理\u0026#39;: 100}, \u0026#39;蔡哥\u0026#39;: {\u0026#39;數學\u0026#39;: 50, \u0026#39;英文\u0026#39;: 50, \u0026#39;物理\u0026#39;: 40}}}}} \u0026gt;\u0026gt;\u0026gt; how2[\u0026#39;校長\u0026#39;] \u0026#39;How哥\u0026#39; \u0026gt;\u0026gt;\u0026gt; how2[\u0026#39;工友\u0026#39;] \u0026#39;林阿嘉\u0026#39; \u0026gt;\u0026gt;\u0026gt; how2[\u0026#39;class\u0026#39;][\u0026#39;A\u0026#39;] {\u0026#39;teacher\u0026#39;: \u0026#39;蔡阿嘎\u0026#39;, \u0026#39;students\u0026#39;: {\u0026#39;阿明\u0026#39;: {\u0026#39;數學\u0026#39;: 55, \u0026#39;英文\u0026#39;: 70, \u0026#39;物理\u0026#39;: 55}, \u0026#39;HowHow\u0026#39;: {\u0026#39;數學\u0026#39;: 80, \u0026#39;英文\u0026#39;: 60, \u0026#39;物理\u0026#39;: 40}}} \u0026gt;\u0026gt;\u0026gt; 我們可以從上面的範例看到，\n在使用json時，轉換出來的Python結構，\n基本上可以當成是字典，裡面有可能含有串列的部分，\n操作起來不會有任何額外的問題，所以這點才對於Python相當重要，\n因為直接讀進來一個檔案，就可以做為字典使用是非常方便的一件事情！\n同樣我們再來嘗試一下寫到檔案和讀出來：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 寫入到json，使用json.dump() \u0026gt;\u0026gt;\u0026gt; classA = how2[\u0026#39;class\u0026#39;][\u0026#39;A\u0026#39;] \u0026gt;\u0026gt;\u0026gt; with open(\u0026#39;classA.json\u0026#39;, \u0026#39;w\u0026#39;) as f: ... json.dump(classA, f) ... \u0026gt;\u0026gt;\u0026gt; classA = how2[\u0026#39;class\u0026#39;][\u0026#39;A\u0026#39;] \u0026gt;\u0026gt;\u0026gt; with open(\u0026#39;classA.json\u0026#39;, \u0026#39;w\u0026#39;) as f: ... json.dump(classA, f, ensure_ascii=False) ... # 從json讀出，使用json.load() \u0026gt;\u0026gt;\u0026gt; with open(\u0026#39;classA.json\u0026#39;, \u0026#39;r\u0026#39;) as f: ... reclassA = json.load(f) ... \u0026gt;\u0026gt;\u0026gt; reclassA {\u0026#39;teacher\u0026#39;: \u0026#39;蔡阿嘎\u0026#39;, \u0026#39;students\u0026#39;: {\u0026#39;阿明\u0026#39;: {\u0026#39;數學\u0026#39;: 55, \u0026#39;英文\u0026#39;: 70, \u0026#39;物理\u0026#39;: 55}, \u0026#39;HowHow\u0026#39;: {\u0026#39;數學\u0026#39;: 80, \u0026#39;英文\u0026#39;: 60, \u0026#39;物理\u0026#39;: 40}}} 最後，提醒讀者留意一件事情：\njson當中的每個object必須要是獨一無二的，也就是不可以重名！\n其實這點對照一下Python的字典應該就清楚了，\n因為Python的字典的key也必須要是獨特的。\n那，如果重名會怎樣呢？\n一般狀況下，最後面出現的會蓋掉前面的：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; repeated_json = \u0026#39;{\u0026#34;數學\u0026#34;: 80, \u0026#34;數學\u0026#34;: 50, \u0026#34;數學\u0026#34;: 30}\u0026#39; \u0026gt;\u0026gt;\u0026gt; json.loads(repeated_json) # 越考越爛阿QQ {\u0026#39;數學\u0026#39;: 30} 當然，json還有不少其他的應用，\n有興趣的讀者可以再閱讀相關文件學習：\nhttps://docs.python.org/3/library/json.html?highlight=json#command-line-options\n那麼，我們來做個練習： 政府資料開放平臺上有提供不少的免費取用的資料，\n請將 https://data.gov.tw/dataset/6224 的JSON格式檔案下載下來。 請用上面示範的方式將其打開並存成一個Python的資料結構，\n命名為bs，這中間可能會遇到讀取的問題，\n是JSON檔文字編碼的錯誤，\n請在打開檔案時額外給入encoding=”utf-8\u0026quot; 的參數。 bs是一個什麼？(字串？串列？字典？) 請利用前面所學，將所有位在’臺北市’的書店資訊存成一個串列，\n名為taipei。 taipei中特色書店點閱數超過2000的店家是哪幾家呢？請列出其名字。 那我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-02T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-17-file-read-write-3/","title":"從零開始學Python (17) — 檔案讀寫：妳出現在我詩的每一頁(下)"},{"content":"Day 16 檔案讀寫：妳出現在我詩的每一頁(中) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10245278\n上一回我們簡單介紹了如何讀一般的文字檔案，\n那如果格式比較特別呢？\n通常狀況下，會需要特別格式的原因，\n是因為它代表了一段「資料」，\n也就是說，讀取不同格式的檔案，\n基本上就是在透過大家約定好的格式方法，\n將資料從檔案中按規則讀出來。\n以Python來說，最常見被拿來儲存的格式有CSV, XML, YAML, JSON等，\n接下來的兩篇文章中，讓我們來分別介紹CSV和JSON吧！\nCSV CSV是相當淺顯易懂的格式，\n如果讀者有在用Excel時，存檔時就會看到有CSV的選項。\n一般而言，一個CSV檔案中，\n每一個**row(列)的不同單位常以逗號分隔，\n(也有用tab鍵的，相當於’\\t’)\n而column(行)**的計算則是以換行符號為準。\n(Unix/Mac系統使用’\\n’，Windows系統則用’\\r\\n’)\n註：中國和台灣在指稱列跟行時是剛好相反的，容易搞混。\n如果沒有特別需求的話，直接使用row/column來對應稱呼橫向/直向就好。\n還記得我們之前的三個同學的成績嗎？\n1 2 3 ming = Student(\u0026#39;阿明\u0026#39;, {\u0026#39;數學\u0026#39;:55, \u0026#39;英文\u0026#39;:70, \u0026#39;物理\u0026#39;:55}) mei = Student(\u0026#39;小美\u0026#39;, {\u0026#39;數學\u0026#39;:90, \u0026#39;英文\u0026#39;:88, \u0026#39;物理\u0026#39;:100}) howhow = Student(\u0026#39;HowHow\u0026#39;, {\u0026#39;數學\u0026#39;:80, \u0026#39;英文\u0026#39;:60, \u0026#39;物理\u0026#39;:40}) 如果今天我們要使用csv的方式將這個成績記錄起來，\n我們可能會考慮寫成這樣：\n1 2 3 4 姓名, 數學, 英文, 物理 阿明, 55, 70, 55 小美, 90, 88, 100 HowHow, 80, 60, 40 那麼，我們怎麼存放到csv中呢？\nPython中有內建一個csv 的模組，\n我們可以用其writer的writerow()或writerows()來處理：\n1 2 3 4 5 6 7 8 9 10 import csv with open(\u0026#39;student.csv\u0026#39;, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as f: csvw = csv.writer(f, delimiter=\u0026#39; \u0026#39;) # delimiter預設是\u0026#39;,\u0026#39;，可以自己更改 csvw.writerow([\u0026#39;姓名\u0026#39;, \u0026#39;數學\u0026#39;, \u0026#39;英文\u0026#39;, \u0026#39;物理\u0026#39;]) # 一次寫一個row students = [ [\u0026#39;阿明\u0026#39;, 55, 70, 55], [\u0026#39;小美\u0026#39;, 90, 88, 100], [\u0026#39;HowHow\u0026#39;, 80, 60, 40] ] csvw.writerows(students) # 一次寫多個rows (delimiter是指分隔符號)\n特別留意，在使用csv來處理時，開啟檔案請務必設置參數, newline=’’，\n以避免掉作業系統對於換行的處理不同的問題。\n(全部交由csv writer來處理就好!)\n其結果應該如下：\n接著我們嘗試將其讀回來，\n這時候就要改成用csv的reader，\nreader的部分比較簡單，我們可以用for…in…的方式來按row取出：\n1 2 3 4 import csv with open(\u0026#39;student.csv\u0026#39;, \u0026#39;r\u0026#39;) as f: csvr = csv.reader(f, delimiter=\u0026#39; \u0026#39;) # student_from_file = [row for row in csvr] 1 print(student_from_file) 讀出來的結果如下。\n1 2 C:\\Users\\Desolve\u0026gt;python fromzero.py [[\u0026#39;姓名\u0026#39;, \u0026#39;數學\u0026#39;, \u0026#39;英文\u0026#39;, \u0026#39;物理\u0026#39;], [\u0026#39;阿明\u0026#39;, \u0026#39;55\u0026#39;, \u0026#39;70\u0026#39;, \u0026#39;55\u0026#39;], [\u0026#39;小美\u0026#39;, \u0026#39;90\u0026#39;, \u0026#39;88\u0026#39;, \u0026#39;100\u0026#39;], [\u0026#39;HowHow\u0026#39;, \u0026#39;80\u0026#39;, \u0026#39;60\u0026#39;, \u0026#39;40\u0026#39;]] 那麼，如果是要處理字典呢？\n我們可以使用DictWriter/DictReader 。\n假定我們已經有一段關於三名學生的字典：\n{‘姓名’:’阿明’, ‘數學’:55, ‘英文’:70, ‘物理’:55}\n{‘姓名’:’小美’, ‘數學’:90, ‘英文’:88, ‘物理’:100}\n{‘姓名’:’HowHow’,’數學’:80, ‘英文’:60, ‘物理’:40}\n我們可以用如下的方式來寫入：\n1 import csv 1 2 3 4 5 6 7 with open(\u0026#39;student_dic.csv\u0026#39;, \u0026#39;w\u0026#39;, newline=\u0026#39;\u0026#39;) as f: field = [\u0026#39;姓名\u0026#39;, \u0026#39;數學\u0026#39;, \u0026#39;英文\u0026#39;, \u0026#39;物理\u0026#39;] # 第一個row做為欄位名稱 csvw = csv.DictWriter(f, delimiter=\u0026#39; \u0026#39;, fieldnames=field) csvw.writeheader() csvw.writerow({\u0026#39;姓名\u0026#39;:\u0026#39;阿明\u0026#39;, \u0026#39;數學\u0026#39;:55, \u0026#39;英文\u0026#39;:70, \u0026#39;物理\u0026#39;:55}) csvw.writerow({\u0026#39;姓名\u0026#39;:\u0026#39;小美\u0026#39;, \u0026#39;數學\u0026#39;:90, \u0026#39;英文\u0026#39;:88, \u0026#39;物理\u0026#39;:100}) csvw.writerow({\u0026#39;姓名\u0026#39;:\u0026#39;HowHow\u0026#39;,\u0026#39;數學\u0026#39;:80, \u0026#39;英文\u0026#39;:60, \u0026#39;物理\u0026#39;:40}) 1 2 3 4 5 with open(\u0026#39;student_dic.csv\u0026#39;, \u0026#39;r\u0026#39;) as f: # DictReader將第一個row當做欄位名稱，所以就省略了 csvr = csv.DictReader(f, delimiter=\u0026#39; \u0026#39;) student = [row for row in csvr] print(student) 讀出來應該如下：\n1 2 C:\\Users\\Desolve\u0026gt;python fromzero.py [{\u0026#39;姓名\u0026#39;: \u0026#39;阿明\u0026#39;, \u0026#39;數學\u0026#39;: \u0026#39;55\u0026#39;, \u0026#39;英文\u0026#39;: \u0026#39;70\u0026#39;, \u0026#39;物理\u0026#39;: \u0026#39;55\u0026#39;}, {\u0026#39;姓名\u0026#39;: \u0026#39;小美\u0026#39;, \u0026#39;數學\u0026#39;: \u0026#39;90\u0026#39;, \u0026#39;英文\u0026#39;: \u0026#39;88\u0026#39;, \u0026#39;物理\u0026#39;: \u0026#39;100\u0026#39;}, {\u0026#39;姓名\u0026#39;: \u0026#39;HowHow\u0026#39;, \u0026#39;數學\u0026#39;: \u0026#39;80\u0026#39;, \u0026#39;英文\u0026#39;: \u0026#39;60\u0026#39;, \u0026#39;物理\u0026#39;: \u0026#39;40\u0026#39;}] 上面敘述的所有範例，在讀寫未知的檔案時，\n我們都無法保證是否csv能夠正常運作，\n所以最好還是用一下try…except的方法，\n對於csv模組傳出的錯誤，\n可以使用try …**except csv.Error as e:**來接取。\n還吃得消嗎？加油！\n那我們下一篇再來談談JSON囉！\n明天見～\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-10-01T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-16-file-read-write-2/","title":"從零開始學Python (16) — 檔案讀寫：妳出現在我詩的每一頁(中)"},{"content":"Day 15 檔案讀寫：妳出現在我詩的每一頁(上) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10245133\n先來解答昨天的問題吧！ 按部就班仔細寫完應該就沒問題啦！\n下面有省略掉前面的一部分東西，讀者也可以自行選擇保留。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Student(): cp_cnt = 0 # 這個變數是屬於整個Student類別的 def __init__(self, name, score): self.name = name self.score = score def __eq__(self, b): # 為了方便讀者檢查是否有問題 print(\u0026#39;self = %d, b = %d\u0026#39; % (self.score[\u0026#39;數學\u0026#39;] * 2 + self.score[\u0026#39;英文\u0026#39;] * 5, b.score[\u0026#39;數學\u0026#39;] * 2 + b.score[\u0026#39;英文\u0026#39;] * 5)) return self.score[\u0026#39;數學\u0026#39;] * 2 + self.score[\u0026#39;英文\u0026#39;] * 5 == b.score[\u0026#39;數學\u0026#39;] * 2 + b.score[\u0026#39;英文\u0026#39;] * 5 def __gt__(self, b): return self.score[\u0026#39;數學\u0026#39;] * 2 + self.score[\u0026#39;英文\u0026#39;] * 5 \u0026gt; b.score[\u0026#39;數學\u0026#39;] * 2 + b.score[\u0026#39;英文\u0026#39;] * 5 def readMyName(self): print(\u0026#39;聽清楚了，我的名字是\u0026#39; + self.name + \u0026#39;!!!\u0026#39;) def compare(self, b): Student.cp_cnt += 1 # 同樣，印出diff方便檢查正確性，讀者可自行註解掉。 diff = sum(self.score.values()) - sum(b.score.values()) print(\u0026#39;diff = %d\u0026#39; % diff) # 有冒號的式子如果底下程式碼只有一行，也可以選擇直接和判斷式寫成同一行 if diff \u0026gt; 0: print(self.name + \u0026#39;贏了！\u0026#39;) elif diff == 0: print(\u0026#39;什麼？竟然平手？！\u0026#39;) else: print(\u0026#39;可...可惡，難道，這就是\u0026#39; + b.name + \u0026#39;真正的實力嗎？\u0026#39;) print(\u0026#39;已比較 %d 次!\\n\u0026#39; % Student.cp_cnt) def compareE(self, b): Student.cp_cnt += 1 if self \u0026gt; b: print(self.name + \u0026#39; \u0026gt; \u0026#39; + b.name) elif self == b: print(self.name + \u0026#39; == \u0026#39; + b.name) else: print(self.name + \u0026#39; \u0026lt; \u0026#39; + b.name) print(\u0026#39;已比較 %d 次!\\n\u0026#39; % Student.cp_cnt) @classmethod def getCpCount(cls): print(\u0026#39;目前的比較次數：%d\u0026#39; % cls.cp_cnt) # 別忘了print也可以用format類型的形式 1 2 print(\u0026#39;開始之前\u0026#39;) Student.getCpCount() # 開始前先看看是不是0 1 2 3 4 5 6 ming = Student(\u0026#39;阿明\u0026#39;, {\u0026#39;數學\u0026#39;:55, \u0026#39;英文\u0026#39;:70, \u0026#39;物理\u0026#39;:55}) ming.readMyName() mei = Student(\u0026#39;小美\u0026#39;, {\u0026#39;數學\u0026#39;:90, \u0026#39;英文\u0026#39;:88, \u0026#39;物理\u0026#39;:100}) mei.readMyName() howhow = Student(\u0026#39;HowHow\u0026#39;, {\u0026#39;數學\u0026#39;:80, \u0026#39;英文\u0026#39;:60, \u0026#39;物理\u0026#39;:40}) howhow.readMyName() 1 2 3 4 5 6 7 print(\u0026#39;\\n來PK吧! 先比總分，再比加權分!\\n\u0026#39;) ming.compare(howhow) ming.compareE(howhow) ming.compare(mei) ming.compareE(mei) mei.compare(howhow) mei.compareE(howhow) 結果應該如下：\n1 2 3 4 5 6 C:\\Users\\Desolve\u0026gt;python fromzero.py 開始之前 目前的比較次數：0 聽清楚了，我的名字是阿明!!! 聽清楚了，我的名字是小美!!! 聽清楚了，我的名字是HowHow!!! 1 來PK吧! 先比總分，再比加權分! 1 2 3 diff = 0 什麼？竟然平手？！ 已比較 1 次! 1 2 3 self = 460, b = 460 阿明 == HowHow 已比較 2 次! 1 2 3 diff = -98 可...可惡，難道，這就是小美真正的實力嗎？ 已比較 3 次! 1 2 3 self = 460, b = 620 阿明 \u0026lt; 小美 已比較 4 次! 1 2 3 diff = 98 小美贏了！ 已比較 5 次! 1 2 小美 \u0026gt; HowHow 已比較 6 次! 今天我們來談談資料的讀寫。\n對Python來說，一旦程式結束，\n或退出Python直譯器，前面做過的事情，\n產生的變數等都會被清理一空，消失不見。\n為什麼呢？程式執行途中，所有的變數等東西要存放在記憶體中，\n在離開時，空間自然要還回去才不會浪費嘛！\n那麼，如果我們想保留中途取得的結果該怎麼辦呢？\n可以選擇存放到檔案中，或者是資料庫裡，\n我們先簡單介紹一些檔案存取的方法。\n對Python來說，要讀寫一個檔案前，\n要先打開它(開啟舊檔嘛XD！)。\n1 2 3 4 # 方法一 file = open(name, mode) ... (使用file來處理檔案) file.close() # 用完要關閉檔案 1 2 3 4 # 方法二 with open(name, mode) as file: ...(使用file來處理檔案) # 離開這個with的區塊以後，file自動關閉。 open會找尋name的檔案，並以mode的模式開啟，\n開啟成功的話，會回傳一個檔案物件，我們用file的名字來接取它。\nmode模式是一個字串，通常狀況下會有1~2個字母，其代表涵義如下：\n第一個字母：\n‘r’ -\u0026gt; 讀取(read)\n‘w’ -\u0026gt; 寫入(write)(但不給r預設還是會可讀)\n‘x’ -\u0026gt; 新增檔案(exclusive creation)，如果檔案已存在則回傳錯誤\n‘a’ -\u0026gt; 在結尾處寫入(append)\n第二個字母：\n‘b’ -\u0026gt; 用二進位的方式來處理\n(預設則是當成文字來處理)\n‘+’號： -\u0026gt; 更新(updating) (可讀可寫)\n通常會用’r+’，代表可讀可寫。\n我們先來看看怎麼樣將七里香的片段寫進詩裡：\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; f = open(\u0026#39;poem.txt\u0026#39;, \u0026#39;w\u0026#39;) \u0026gt;\u0026gt;\u0026gt; f.write(\u0026#39;院子落葉\\n跟我的思念厚厚一疊\u0026#39;) # write結束時會回傳寫入的字數(byte數) 14 \u0026gt;\u0026gt;\u0026gt; f.close() # 要先close()以後，才會真的寫入完畢！ 讀者可以在python執行的位置或者執行.py檔的位置，\n找到一個poem.txt，其內容如下：\n讀者如果多加嘗試的話，可以發現如果再次讀檔寫檔，\n前面的內容會被全數覆蓋 ！\n除了用了write()以外，print()也可以拿來輸出到檔案，\n其方法如下：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; f = open(\u0026#39;poem.txt\u0026#39;, \u0026#39;w\u0026#39;) \u0026gt;\u0026gt;\u0026gt; print(\u0026#39;院子落葉\\n跟我的思念厚厚一疊\u0026#39;, file=f, sep=\u0026#39;\u0026#39;, end=\u0026#39;\u0026#39;) \u0026gt;\u0026gt;\u0026gt; f.close() # 要先close()以後，才會真的寫入完畢！ 我們將print()的目標指向到檔案去，\n所以它就不會把字串印在命令列；\n同時，由於print()預設會有sep(分隔符號)和end(結束符號) ，\nsep預設會是一個空格，end預設會是換行 ，\n所以我們要自行將其設定為空字串，避免寫進去的東西不如預期。\n另一方面，如果字串很大，不適合直接一口氣處理完，\n也可以考慮使用slice的方法分段處理。\n(自己決定每段要寫入多少字元，搭配迴圏操作)\n由於檔案讀取使用**’x’**的話會有機會產生錯誤，\n在其他很多狀況下也有產生錯誤的可能，\n一般我們在使用檔案處理的相關函式時，\n會用try…except…來將其包含進來。\n1 2 3 4 5 6 7 \u0026gt;\u0026gt;\u0026gt; try: ... f = open(\u0026#39;poem.txt\u0026#39;, \u0026#39;x\u0026#39;) ... f.write(\u0026#39;窗外的麻雀\u0026#39;) ... except FileExistsError: # 想直接全包也行啦XD! ... print(\u0026#39;檔案已存在!\u0026#39;) ... 檔案已存在! 接下來是讀取檔案的部分：\n讀檔就比寫入還要更在意一次讀的內容了，\nPython提供了三個用來讀取的函式：\nread(), readline(), readlines() 。\nread()的本質和write()接近，就是有什麼讀什麼，\n就算今天是全本小說也照讀不誤，所以特別要留意這點！\n當不確定自己要讀的檔案大小時，千萬不要直接一口氣讀全部啊！\n1 2 3 4 5 6 \u0026gt;\u0026gt;\u0026gt; f = open(\u0026#39;poem.txt\u0026#39;, \u0026#39;r\u0026#39;) \u0026gt;\u0026gt;\u0026gt; poem = f.read() \u0026gt;\u0026gt;\u0026gt; print(poem) 院子落葉 跟我的思念厚厚一疊 \u0026gt;\u0026gt;\u0026gt; f.close() read()也可以傳入字數來限制每次要讀幾個字元：\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; f = open(\u0026#39;poem.txt\u0026#39;, \u0026#39;r\u0026#39;) \u0026gt;\u0026gt;\u0026gt; poem = \u0026#39;\u0026#39; \u0026gt;\u0026gt;\u0026gt; while True: ... next = f.read(3) # 每次只讀3個字 ... if not next: # 讀到結尾時，會產生空字串給next ... break ... poem += next ... \u0026gt;\u0026gt;\u0026gt; print(poem) 院子落葉 跟我的思念厚厚一疊 \u0026gt;\u0026gt;\u0026gt; f.close() 讀者也可以自行嘗試在迴圈中印看看next。\n接下來是readline()，\nreadline()每次會以行為單位將檔案讀出來：\n為了更明確表現整個狀況，我們先將poem.txt更改如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026gt;\u0026gt;\u0026gt; f.close() \u0026gt;\u0026gt;\u0026gt; f = open(\u0026#39;poem.txt\u0026#39;, \u0026#39;r\u0026#39;) \u0026gt;\u0026gt;\u0026gt; cnt = 0 \u0026gt;\u0026gt;\u0026gt; poem = \u0026#39;\u0026#39; \u0026gt;\u0026gt;\u0026gt; while True: ... cnt += 1 ... line = f.readline() ... if not line: break ... print(\u0026#39;Line %d: %s\u0026#39; % (cnt, line), end=\u0026#39;\u0026#39;) ... poem += line ... Line 1: 院子落葉 Line 2: 跟我的思念厚厚一疊 Line 3: Line 4: 幾句誓言 Line 5: 也無法將我的熱情冷卻 Line 6: \u0026gt;\u0026gt;\u0026gt; f.close() \u0026gt;\u0026gt;\u0026gt; 我們可以看到在readline()時，換行的符號是被算進去的，\n就算尾端只有幾個空白字元 ，照樣也會被算做一行。\nreadlines()則又再友善一點，\n會按行將讀出來的每一行為單位組成list。\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; f = open(\u0026#39;poem.txt\u0026#39;, \u0026#39;r\u0026#39;) \u0026gt;\u0026gt;\u0026gt; lines = f.readlines() \u0026gt;\u0026gt;\u0026gt; lines [\u0026#39;院子落葉\\n\u0026#39;, \u0026#39;跟我的思念厚厚一疊\\n\u0026#39;, \u0026#39;\\n\u0026#39;, \u0026#39;幾句誓言\\n\u0026#39;, \u0026#39;也無法將我的熱情冷卻\\n\u0026#39;, \u0026#39; \u0026#39;] 今天我們已經介紹了基礎的讀寫檔案，\n下一篇我們再來介紹比較進一步地使用模組來讀一些常見的檔案格式。\n那我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-30T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-15-file-read-write-1/","title":"從零開始學Python (15) — 檔案讀寫：妳出現在我詩的每一頁(上)"},{"content":"Day 14 物件與類別：我們不一樣，每個人都有不同的際遇(下) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10244886/\n前面兩篇我們從什麼是類別和物件的基本介紹起，\n講到如何初始化及設定屬性、方法，以及如何運用繼承。\n這篇我們首先要談的是，\n什麼時候該用類別/物件，什麼時候又該用模組呢？\n其實答案很簡單：\n看怎麼用比較方便，就怎麼用XD！\n讀者可能會覺得這是廢話，先別著急，讓筆者解釋一下。\n在程式的世界裡，當我們遇上問題時，\n大部分的狀況下都不會只有一種解法 。\n不同的解法，會有不同的優劣性，\n扣除掉一些根本效率的不同，剩下的就只是取捨問題。\n所以當碰到多個可行的選項，在考慮用哪一個方法時，\n請先問問自己以下的問題：\n題目(或現實的目標)是否有限制，導致某些方法其實不能用？ 這當中，哪些是前面寫起來比較簡單，後面維護(或擴充)比較麻煩的？\n哪些是前面寫起來比較複雜，後面卻可以節省力氣的？ 承2，在大前提的目標下，這個架構有需要考慮到後面的問題嗎？ 以上三個問題會影響實務上的選擇，\n所以你可以基於節省空間考量而選方法A，\n或基於節省時間而選方法B，亦或是為了架構比較好選方法C，\n不會有絕對的對錯，只是看考量而已。\n扯遠了，回過頭來看物件/類別及模組的抉擇。\n通常模組會比物件/類別還要精簡，因為不會牽扯到太多額外的東西；\n但模組在一個程式中import時，只會產生同一個東西，而類別可以產生多個不同的物件。\n當你的程式都是一些工具型函式，屬於那種呼叫完就會經過一番處理再輸出，\n但不會需要產生多個不同的物件來處理事情的話，\n以模組的型式處理會相當簡單。\n舉例來說，一個學校只會有一個校長，校長可能有一些事情是他的權責範圍，\n假設我們只鎖定一間學校，那校長能做的事情應該就可以直接以一個模組來囊括，\n因為同一間學校總不會出現第二位校長嘛！所以我們可以用模組來定義所有校長的業務。\n但學生就不行了，我們會有阿明，小美，HowHow跟其他路人甲乙丙丁，\n所以學生就適合建立一個Student的類別來生成多個物件。\n另一點是阿明和小美雖然都是學生，但它們會有屬性的差異，\n這種有相同性質但屬性質不同的，最適合使用類別與物件來處理了！\n另一方面，模組是不行繼承的 ，如果你有繼承的需求的話，\n類別與物件就是唯一的選擇。\n最後一點，如果可以用簡單的方式如字典、串列甚至一般函式來處理的話，\n不一定非得要模組或類別/物件不可 。\n接著我們來談談類別方法 及類別屬性 。\n類別方法是指會影響整個類別的方法，類別屬性則是指整個類別所共有的屬性。\n舉例來說，如果我們想要知道今天我們總共加入了幾個Student類別的物件，\n我們可以這麼寫：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Student(): cnt = 0 # 這個變數是屬於整個Student類別的 def __init__(self, name, score): Student.cnt += 1 # 每次新開一個Student的物件，計數器就會+1 self.name = name self.score = score def readMyName(self): print(\u0026#39;聽清楚了，我的名字是\u0026#39; + self.name + \u0026#39;!!!\u0026#39;) def compare(self, b): diff = sum(self.score.values()) - sum(b.score.values()) # 有冒號的式子如果底下程式碼只有一行，也可以選擇直接和判斷式寫成同一行 if diff \u0026gt; 0: print(self.name + \u0026#39;贏了！\u0026#39;) elif diff == 0: print(\u0026#39;什麼？竟然平手？！\u0026#39;) else: print(\u0026#39;可...可惡，難道，這就是\u0026#39; + b.name + \u0026#39;真正的實力嗎？\u0026#39;) @classmethod def getCount(cls): print(\u0026#39;目前的學生總數：%d\u0026#39; % cls.cnt) # 別忘了print也可以用format類型的形式 1 2 print(\u0026#39;開始之前\u0026#39;) Student.getCount() 1 2 3 ming = Student(\u0026#39;阿明\u0026#39;, {\u0026#39;數學\u0026#39;:55, \u0026#39;英文\u0026#39;:70, \u0026#39;物理\u0026#39;:55}) ming.readMyName() Student.getCount() 1 2 3 mei = Student(\u0026#39;小美\u0026#39;, {\u0026#39;數學\u0026#39;:90, \u0026#39;英文\u0026#39;:88, \u0026#39;物理\u0026#39;:100}) mei.readMyName() Student.getCount() 1 2 3 howhow = Student(\u0026#39;HowHow\u0026#39;, {\u0026#39;數學\u0026#39;:80, \u0026#39;英文\u0026#39;:60, \u0026#39;物理\u0026#39;:40}) howhow.readMyName() Student.getCount() 結果應該像這樣：\n1 2 3 4 5 6 7 8 9 C:\\Users\\Desolve\u0026gt;python fromzero.py 開始之前 目前的學生總數：0 聽清楚了，我的名字是阿明!!! 目前的學生總數：1 聽清楚了，我的名字是小美!!! 目前的學生總數：2 聽清楚了，我的名字是HowHow!!! 目前的學生總數：3 對於類別方法，我們會在前面加上**”@classmethod”，\n同時由於”class”** 已經是Python的保留字(用來定義類別)，\n所以在使用時Python是給定**”cls”** ，用來指稱這個類別。\n不過直接使用**Student.cnt**也可以，意思是一樣的。\n所以請留意類別方法/屬性和物件方法/屬性的差異，\n前者是屬於整個類別，後者是會依照產生的物件來操作。\n可以看到即便在開始之前，\n我們還沒加入任何Student，類別屬性就已經存在了。\n還有一種比較特別的方法叫靜態方法 。\n使用”@staticmethod”來開頭，不需要self或cls參數，\n通常用以處理可以固定不變，不受其他屬性影響的東西。\n例如：\n1 2 3 4 5 6 class Desolve(): @staticmethod def ads(): print(\u0026#39;無情工商時間!\u0026#39;) print(\u0026#39;從LeetCode學演算法是一系列非常好的課程!\u0026#39;) print(\u0026#39;https://bit.ly/leetcodeall\u0026#39;) 1 Desolve.ads() 同樣，無須Desolve類別產生物件，這個方法就能被使用(甚至也沒有用到其他屬性)。\n一個類別也可以繼承不只一個類別，例如假設我們有A, B兩個類別，\n想用一個C類別同時繼承它們：\n1 2 class C(A, B): ... 這麼一來，C就會同時擁有A跟B的屬性和方法。\n那麼，如果相衝突(比方說重名)怎麼辦？\n1 2 3 4 5 class A(): def __init__(self): self.name = \u0026#39;A\u0026#39; print(\u0026#39;A\u0026#39;) print(\u0026#39;Name = \u0026#39; + self.name) 1 2 3 4 5 class B(): def __init__(self): self.name = \u0026#39;B\u0026#39; print(\u0026#39;B\u0026#39;) print(\u0026#39;Name = \u0026#39; + self.name) 1 2 3 4 class C(A, B): pass test = C() 輸出應該會如下：\n1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py A Name = A 簡單來說，當A跟B有相同的方法時，\n呼叫方法會呼叫哪一個，端看你把誰寫前面，寫越前面的優先程度越大 。\n(讀者可以自行將C(A, B)改成C(B, A)看看結果)\n其他還有一些更深入的變化，我們就不在這個系列討論了，\n有興趣的讀者可以再深入研究繼承多個類別的變化。\n最後，我們來談談特殊的方法：\n當我們在Python內使用那些 ==, !=, \u0026gt;=, \u0026lt;=, \u0026gt;, \u0026lt;……等比較運算子時，\n其實是依靠Python有對這些東西做定義，才知道如何去做比較；\n但是對於我們自己生成的類別來說，想要比較兩個相同類別的物件，\n可能就需要我們自己定義了。\n例如說假設有一個類別叫nmod3()，會紀錄數字並判斷餘數是否相等：\n1 2 3 4 5 6 7 8 9 10 class nmod3(): def __init__(self, num): self.num = num def __eq__(self, n2): # 定義 \u0026#34;==\u0026#34;這個運算子為是否除以3的餘數相同 return self.num % 3 == n2.num % 3 a = nmod3(11) # 除以3餘2 b = nmod3(18) # 除以3餘0 c = nmod3(17) # 除以3餘2 1 2 3 print(a == b) print(a == c) print(b == c) 可以被特別定義的除了比較運算子以外，還有之前我們提到過的算術運算子等。\n這裡稍微列出一些提供參考：\n1 2 3 4 5 6 7 8 9 # 這些都是兩個物件相比，我們假定後面的物件叫b。 __eq__ =\u0026gt; self == b __ne__ =\u0026gt; self != b __lt__ =\u0026gt; self \u0026lt; b __gt__ =\u0026gt; self \u0026gt; b __add__ =\u0026gt; self + b __mul__ =\u0026gt; self * b # 原來字串的乘法是這麼弄出來的XD __len__ =\u0026gt; len(self) # 可以定義什麼是你的物件的\u0026#34;長度\u0026#34; ...(其他有需要再Google即可XD) 那我們一樣來練習一下題目吧！ 請參照之前的Student類別，\n假設今天有一個科系要求是(數學 * 2 + 英文 * 5)的加權分數採計，\n定義__gt__(也就是\u0026gt;), __eq__(也就是==)，\n用上面的採計方式及重新定義的比較運算子來寫成新的A.compareE(B)函式，\n假設：\nA的加權分高於B -\u0026gt; A的名字 + ‘ \u0026gt; ‘ + B的名字\nA的加權分等於B -\u0026gt; A的名字 + ‘ == ‘ + B的名字\nA的加權分小於B -\u0026gt; A的名字 + ‘ \u0026lt; ‘ + B的名字\n並分別讓阿明和HowHow比較、\n阿明和小美比較、小美和HowHow比較，輸出結果。\n(請保留之前compare的函式及呼叫的比較，我們兩種都要比呦!) 承上，請使用類別方法和屬性，在每次進行比較時就將總比較次數+1，\n並print出來，這邊的「比較」是指compare()及compareE()都算。 辛苦啦！那我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-29T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-14-object-and-class-3/","title":"從零開始學Python (14) — 物件與類別：我們不一樣，每個人都有不同的際遇(下)"},{"content":"Day 13 物件與類別：我們不一樣，每個人都有不同的際遇(中) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。https://ithelp.ithome.com.tw/articles/10244495\n先來解答昨天的問題吧！ 我們可以修改上一篇的範例，並且新增一個compare方法，\n由於比較的時候，我們利用self就可以取得現在的物件，\n那麼從外面傳入的，我們直接將其稱為b，\n要比較的就會是self.score的分數總和，和b.score的分數總和的關係。\n這邊繼續介紹好用的小函式：\n由於前面我們講過字典，要取所有的值的部分\n(因為沒有加權嘛，就不用管科目了XD)，\n是用.values()，那要加總在一起，\n我們可以用for … in …的方式一個一個加起來，\n或者，我們可以使用sum()函式，\n它可以把一個可以算值的一組資料給加總起來。\n於是一切就簡單啦！剩下的就是依照結果輸出。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Student(): def __init__(self, name, score): self.name = name self.score = score def readMyName(self): print(\u0026#39;聽清楚了，我的名字是\u0026#39; + self.name + \u0026#39;!!!\u0026#39;) def compare(self, b): diff = sum(self.score.values()) - sum(b.score.values()) # 有冒號的式子如果底下程式碼只有一行，也可以選擇直接和判斷式寫成同一行 if diff \u0026gt; 0: print(self.name + \u0026#39;贏了！\u0026#39;) elif diff == 0: print(\u0026#39;什麼？竟然平手？！\u0026#39;) else: print(\u0026#39;可...可惡，難道，這就是\u0026#39; + b.name + \u0026#39;真正的實力嗎？\u0026#39;) ming = Student(\u0026#39;阿明\u0026#39;, {\u0026#39;數學\u0026#39;:55, \u0026#39;英文\u0026#39;:70, \u0026#39;物理\u0026#39;:55}) mei = Student(\u0026#39;小美\u0026#39;, {\u0026#39;數學\u0026#39;:90, \u0026#39;英文\u0026#39;:88, \u0026#39;物理\u0026#39;:100}) howhow = Student(\u0026#39;HowHow\u0026#39;, {\u0026#39;數學\u0026#39;:80, \u0026#39;英文\u0026#39;:60, \u0026#39;物理\u0026#39;:40}) print(ming.name) print(mei.name) print(how.name) print(\u0026#39;\\n阿明 vs HowHow\u0026#39;) ming.compare(how) print(\u0026#39;\\n阿明 vs 小美\u0026#39;) ming.compare(mei) print(\u0026#39;\\n小美 vs HowHow\u0026#39;) mei.compare(how) 我們今天繼續來講物件與類別。\n上一篇我們介紹了一個基本的類別是怎麼被做出來的，\n也提到了初始化的函式，設定它們的屬性等做法。\n在實際運用上，我們會遇到一個問題：\n今天遇到更細項的屬性時，我們是否要將其設定到現有的類別呢？\n如果這麼做的話，有時候會導致通用性不夠的問題。\n例如：\n對於一輛車子來說，它是Tesla的話，有可能會有自動駕駛功能，\n但如果它是一般的車子的話，自動駕駛顯然不是一個正常會有的功能。\n所以當我們有一個名為Car的類別時，\n我們想要定義一個Tesla的Car，應該為其增設一個Tesla的類別，\n而非直接在Car新增自動駕駛的功能。\n但Tesla應該還是擁有Car的基本特性，所以我們可以利用這點，\n避免掉重新設定一個全新的類別。這就是我們要介紹的方法：繼承 。\n在繼承的概念裡，\n原先Car的類別被稱為「父類別」、「超類別」或「基礎類別」，\n(parent/super/base class)\n而要做出來的Tesla被稱為「子類別」或「衍生類別」\n(subclass/derived class)\n定義子類別的話，只要在子類別的括號內加入父類別的名稱即可：\n1 2 3 class Car(): def whoami(self): print(\u0026#39;I\\\u0026#39;m a Car!\u0026#39;) 1 2 class Tesla(Car): pass 1 2 3 4 car = Car() tla = Tesla() car.whoami() tla.whoami() 讀者會發現，在Tesla中儘管尚未定義whoami()，\n結果仍然會輸出，而輸出的結果其實是按照Car的whoami()來執行的：\n1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py I\u0026#39;m a Car! I\u0026#39;m a Car! 因為我們已經從Car這邊繼承過來了其屬性和方法，\n所以Tesla也會有whoami的方法。\n我們當然也可以把whoami做一下改變，並新增一些我們需要的東西：\n1 2 3 class Car(): def whoami(self): print(\u0026#39;I\\\u0026#39;m a Car!\u0026#39;) 1 2 3 4 5 6 7 8 9 class Tesla(Car): def __init__(self): self.pilotmode = 1 # ON: 1, OFF: 0 def whoami(self): print(\u0026#39;I\\\u0026#39;m a Tesla, not a trash car!\u0026#39;) def autopilot_switch(self): self.pilotmode ^= 1 # ^是取XOR(互斥或)，所以會在0和1之間切換 if self.pilotmode == 0: print(\u0026#39;Auto-pilot mode switch off!\u0026#39;) else: print(\u0026#39;Auto-pilot mode switch on!\u0026#39;) 1 2 3 4 5 6 car = Car() tla = Tesla() car.whoami() tla.whoami() tla.autopilot_switch() tla.autopilot_switch() 上面的示範中，我們為Tesla新增一個屬性，\n用來表示自動駕駛模式是否開啟，\n並提供一個切換開關的方法。但這是Tesla的東西，\n所以Car並不會有autopilot_switch()，\n讀者可以嘗試使用car.autopilot_switch()看看，應該會出現錯誤。\n同時留意我們也重寫了一次whoami，\n這個將父類別有的函式，重新給予定義的做法，\n稱為override(覆寫/覆載) 。\n整個執行的結果會如下所示：\n1 2 3 4 5 C:\\Users\\Desolve\u0026gt;python fromzero.py I\u0026#39;m a Car! I\u0026#39;m a Tesla, not a trash car! Auto-pilot mode switch off! Auto-pilot mode switch on! 讀者可能會問：\n「那如果我們想要覆寫父類別的方法，\n又想用到原先的內容，那該怎麼做呢？」\n這時候，我們就需要使用super()來取得父類別的東西了！\n舉例來說，假設我們對每一輛車都會給它自己一個名字，\n在whoami時，會先喊出自己的名字，我們可以修改上面的內容變成這樣：\n1 2 3 4 5 6 class Car(): def __init__(self, name): self.name = name def whoami(self): print(\u0026#39;My name is \u0026#39; + self.name) print(\u0026#39;I\\\u0026#39;m a Car!\u0026#39;) 1 2 3 4 5 6 7 8 9 10 11 12 class Tesla(Car): def __init__(self, name, mode): super().__init__(name) # 使用super來對name初始化，看起來稍微多此一舉，但可以保證對於name處理的一致性，之後如果要額外針對Car這個父類別修改時，就可以一起同時影響到Tesla這邊 self.pilotmode = mode def whoami(self): super().whoami() # 先喊名字跟喊自己是輛車 print(\u0026#39;Also, I\\\u0026#39;m a Tesla, not a trash car!\u0026#39;) # 這兩行再做只有Tesla會做的事情 print(\u0026#39;Auto-pilot mode: \u0026#39; + str(self.pilotmode)) def autopilot_switch(self): self.pilotmode ^= 1 if self.pilotmode == 0: print(\u0026#39;Auto-pilot mode switch off!\\n\u0026#39;) else: print(\u0026#39;Auto-pilot mode switch on!\\n\u0026#39;) 1 2 3 4 5 6 7 8 car = Car(\u0026#39;CC\u0026#39;) tla = Tesla(\u0026#39;TT\u0026#39;, 0) car.whoami() print() tla.whoami() tla.autopilot_switch() tla.whoami() tla.autopilot_switch() 其執行結果應該像這樣：\n1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py My name is CC I\u0026#39;m a Car! 1 2 3 4 5 My name is TT I\u0026#39;m a Car! Also, I\u0026#39;m a Tesla, not a trash car! Auto-pilot mode: 0 Auto-pilot mode switch on! 1 2 3 4 5 My name is TT I\u0026#39;m a Car! Also, I\u0026#39;m a Tesla, not a trash car! Auto-pilot mode: 1 Auto-pilot mode switch off! 辛苦啦！在接下來的篇幅中，我們會再談談類別方法及靜態方法，\n還有討論一下什麼時候該用類別/物件，什麼時候又該用模組的問題。\n那我們就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-28T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-13-object-and-class-2/","title":"從零開始學Python (13) — 物件與類別：我們不一樣，每個人都有不同的際遇(中)"},{"content":"Day 12 物件與類別：我們不一樣，每個人都有不同的際遇(上) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10244018\n先來解答昨天的問題吧！ 給定兩個字串s跟t，已經知道t的組成，\n是將s的字母打亂以後進行重組，再隨機加上一個字母。\n請用前面所學，找出被加上的那個字母。 以這題來說，我們可以採用內建的方式來處理，\n或者使用上一篇提到的Counter()。\n首先，讓我們再額外教一對有用的方法：ord()跟chr()。\n一般狀況下，程式語言中有時候會提到char(字元)這個單位，\n字元的單位就是單一一個英文字母或符號，\n是用8個二進位來組成，有定義的有128個不同的字元。\n這種字元的表達方是我們稱之為ASCII Code (阿斯奇扣德)。\n更詳細的介紹可以看 https://zh.wikipedia.org/wiki/ASCII 。\n我們只需要知道，ASCI Code上面6590是AZ，而97122是az。\n而要如何在數字和對應的字元做轉換呢？\n在Python中會使用ord() ，也就是order，\n將一個字元轉成對應的ASCII Code；\n而使用chr() ，則可以將一個數字轉為對應的字元。\n利用這點，我們可以取一個長度為26的list，\n把a放到list的index 0，b放到list的index 1…，z放到list的index 25。\n什麼？你不記得哪個數字對應的ASCII Code？\n我們只需要拿ord(‘a’)為基準去相減就好囉！\n因此，我們要做的事情就是將s的東西全部當做減1次，\nt的東西全部當做加1次，最後因為t只比s多一個字元而已，\n留下來計數是1的那個就會是答案囉！\n如果先減後加的話，只要我們找到即將由0轉1的時候的那個字元，\n就是我們要的答案囉！\n1 2 3 4 5 6 7 # 變數後面加冒號，再加資料型態，可以提示輸入的資料型態。 # 但實質上Python並不會強制檢查是否正確。 # \u0026#34;-\u0026gt;\u0026#34; 後面接的則是回傳的資料型態 def findTheDifference(s: str, t: str) -\u0026gt; str: cnt = [0] * 26 for c in s: cnt[ord(c) - ord(\u0026#39;a\u0026#39;)] -= 1 1 2 3 for c in t: if cnt[ord(c) - ord(\u0026#39;a\u0026#39;)] == 0: return c cnt[ord(c) - ord(\u0026#39;a\u0026#39;)] += 1 第二種方法，我們可以直接使用Counter()。\n1 2 3 4 5 6 def findTheDifference(self, s: str, t: str) -\u0026gt; str: from collections import Counter cnt_s = Counter(s) cnt_t = Counter(t) # most_common(1)[0]取到了唯一的一組，再一個[0]取到key的部分 return (cnt_t - cnt_s).most_common(1)[0][0] 接下來今天我們要講很多程式語言都有的重要的東西：物件 。\n我們先前講過函式，就是透過自己組合一些程式碼，\n做成自己想要的一組功能。\n事實上，以Python的角度來說，任何東西都是一種物件，\n物件不只有自己的函式(方法) ，還有一些屬於它的變數(屬性) 。\n舉例來說：\n如果有一個人叫阿明，另一個人叫小美，\n他們都是同一個高中同一班的學生，\n所以要考試時，阿明要考數學跟英文，小美也要考數學跟英文。\n如果我們要記錄阿明跟小美的成績的話，按照先前所學的，\n讀者可能會做類似如下的變數設定：\n1 2 3 4 ming_score_math = 55 ming_score_english = 70 mei_score_math = 90 mei_score_english = 88 這麼做有以下幾個缺點：\n字很長XD 每個變數都要重新再命名一次，如果今天要40個同學都這樣的話，\n寫變數命名就累死了！\n所以為了加以簡化，我們可以用物件的概念來處理這個問題。\n在創造一個物件(object)之前，我們要先定義類別(class) 。\n什麼是類別呢？\n我們要考慮處理的目標，其共通性是什麼？\n比方說阿明是學生，小美也是學生，\n阿明會有考試的成績，小美也是，同時，阿明和小美都會上課。\n那麼我們就會可以定義一個類別稱為Student\n(一般類別習慣會使用第一個字大寫)。 最基礎的類別定義如下：\n1 2 class Student(): pass # pass表示暫時不做任何事情，但將來必須要將其填補好。 如果要從一個定義產生物件，其用法如下：\n1 2 ming = Student() # 阿明是個學生 mei = Student() # 小美是個學生，但和阿明不一樣 上面的ming和mei都是分別都是一個物件，其類別為Student。\n以最初始的定義來說，它什麼事情都不會做，接下來我們來加入一些屬性：\n1 2 3 class Student(): def __init__(self, name): self.name = name 在一個物件被初始化的時候，最先會呼叫其中的__init__()函式。\n它最前面必須要是self開頭，self的概念是指這個物件本體 ，\n我們可以透過self.xxx 的方式來取得或修改物件的其他屬性或方法。\n注意到除了self以外，我們還增加一個name，\n代表當我們呼叫Student()時，其第一個位置傳入的將會是name。\n而self.name = name 則代表我們要在開始時，\n將從外面傳入進來的name的值，\n存放進這個物件本體的name的值。\n所以我們現在在來修改一下剛剛產生物件的方式：\n1 2 3 4 5 ming = Student(\u0026#39;阿明\u0026#39;) # 阿明是個學生 mei = Student(\u0026#39;小美\u0026#39;) # 小美是個學生，但和阿明不一樣 # 要使用\u0026#39;.\u0026#39;來取得各自的名字 print(ming.name) print(mei.name) 除了屬性以外，我們還可以為類別新增一些方法，\n其方式基本和前面函式定義的方法一致，只是要加上self。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Student(): def __init__(self, name): self.name = name # 可以利用self取得自己這個類別裡面的變數 def readMyName(self): print(\u0026#39;聽清楚了，我的名字是\u0026#39; + self.name + \u0026#39;!!!\u0026#39;) ming = Student(\u0026#39;阿明\u0026#39;) mei = Student(\u0026#39;小美\u0026#39;) print(ming.name) print(mei.name) ming.readMyName() mei.readMyName() 由於物件概念比較需要仔細釐清，我們就分成兩篇來細講，\n請務必仔細完成今天的練習呦！\n那我們來練習一下題目吧！ 在上述的例子當中，請為類別新增一個字典，名稱為score，\n將該字典用來儲存{‘科目’:’分數’}的各科成績，並修改__init__()的函式，\n在產生阿明及小美時，同時輸入各科成績，\n如未輸入則預設為0分(也就是缺考)。\n阿明的成績分別為：數學55/英文70/物理55\n小美的成績分別為：數學90/英文88/物理100 承上題，請新增一名Student，其name為’HowHow’，\n數學成績為80，英文成績為60，物理成績為40。 請為Student新增一個方法，讓兩個Student可以互相比較，\n名稱為compare()。\n例如A.compare(B)，假設：\nA的總分高於B -\u0026gt; A的名字 + ‘贏了！’\nA的總分等於B -\u0026gt; ‘什麼？竟然平手？！’\nA的總分小於B -\u0026gt; ‘可…可惡，難道，這就是’ + B的名字 + ‘真正的實力嗎？’ 並分別讓阿明和HowHow比較、阿明和小美比較、小美和HowHow比較，\n輸出結果。\n辛苦啦！我們明天見！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-27T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-12-object-and-class-1/","title":"從零開始學Python (12) — 物件與類別：我們不一樣，每個人都有不同的際遇(上)"},{"content":"Day 11 標準程式庫：你的機車不機車，載我瀏覽世界景色 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10243343\n先來解答昨天的問題吧！ 我們可以使用randint(1, 100)，\n或者使用int(1 + random() * 100)來取得亂數值。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from random import randint ans, guess = randint(1, 100), 0 l, r = 1, 100 while ans != guess: try: guess = int(input(\u0026#39;\\n請在\u0026#39; + str(l) + \u0026#39;到\u0026#39; + str(r) + \u0026#39;之間猜一個數:\u0026#39;)) except: # 加入continue，直接跳過後面的範圍處理，回到迴圈的開頭 print(\u0026#39;請輸入正常的數字，不要加其他字母或符號呦！\u0026#39;) continue if guess \u0026lt; l or guess \u0026gt; r: # 超出範圍的部分同樣也要跳過(當然，也可以用elif和下面的判斷連起來) print(\u0026#39;請輸入正確範圍內的數字！\u0026#39;) continue if guess \u0026lt; ans: print(\u0026#39;您猜的數字比答案還要小，請再猜大一點~\u0026#39;) l = guess + 1 elif guess \u0026gt; ans: print(\u0026#39;您猜的數字比答案還要大，請再猜小一點~\u0026#39;) r = guess - 1 print(\u0026#39;恭喜你猜出答案啦！\u0026#39;) 為了要避開，我們可以先生成一個串列，\n範圍為1~100並且去除掉avoid_lt的值。 1 2 3 4 from random import choice avoid_lt = [4, 14, 44, 94] ans_lt = [i for i in range(1, 101) if i not in avoid_lt] # 在列表生成式中使用if來處理要跳過的值 ans, guess = choice(ans_lt), 0 在上一篇我們用了一些匯入的模組及套件以後，\n今天我們再花一點時間進一步來介紹Python的標準程式庫！\n在Python當中有很多已經做好的函式，只需要匯入就可以使用囉！\n在實作一些功能前，有時候不妨先查一下是否有適用的函式可用。\n但有一點很重要的要先提到：\n請不要造一輛車子以後只拿輪子，這會很沒效率。\n為什麼呢？\n因為當我們造一輛車子的時候會耗費大量的時間，\n但如果我們只是要一個輪子的話，\n我們應該去尋找專門製作輪子的方式，而非造車拔輪。\n所以讀者在使用函式的時候，都要盡量去留意當前自己的目標是什麼，\n避免耗費過多時間讓Python在不必要的部分計算。\n首先我們來介紹defaultdict() 。\n先前我們介紹過字典，假設我們現在有一個字典名為dic，\n當我們使用dic[key]時，如果這個key並不在字典裡，\n會發生什麼事情呢？\n答案是：會產生錯誤！\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; dic = {} \u0026gt;\u0026gt;\u0026gt; dic[\u0026#39;XD\u0026#39;] Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; KeyError: \u0026#39;XD\u0026#39; 為了處理這個問題，我們有幾種方式：\n每次檢查if key in dic ，存在的話，再做其他的事情。 如果我們有一些預設的狀況的話，例如要存放key出現的次數，那可以使用get() 。\nget()的第一個參數放入要找的key，第二個位置放入預設的value值，\n如果這個key不存在於字典，就使用後面給定的value做為結果；\n如果存在的話，當然就用對應到的value。 1 2 \u0026gt;\u0026gt;\u0026gt; dic.get(\u0026#39;XD\u0026#39;, 0) 0 defaultdict() 1 2 3 4 5 6 7 8 9 10 11 \u0026gt;\u0026gt;\u0026gt; from collections import defaultdict \u0026gt;\u0026gt;\u0026gt; cnt = defaultdict(int) \u0026gt;\u0026gt;\u0026gt; cnt[3] 0 \u0026gt;\u0026gt;\u0026gt; cnt[\u0026#39;XD\u0026#39;] 0 \u0026gt;\u0026gt;\u0026gt; cnt[\u0026#39;a\u0026#39;]=1 \u0026gt;\u0026gt;\u0026gt; cnt.get(\u0026#39;a\u0026#39;) 1 \u0026gt;\u0026gt;\u0026gt; cnt.get(\u0026#39;XD\u0026#39;) 0 在defaultdict中，當key沒有被指定value時，\n就會採用初始化時預設給進去的東西：\n寫int代表預設值為0、寫list代表預設為空串列、寫dict表預設為空字典…\n以此類推。\n省略參數的時候，會被設定為None ，也就是什麼都沒有的意思，\n但這麼一來，就又會回到一般字典對於不存在的key會報錯的狀況。\n給進去的東西還有其他的用法，有興趣的讀者也可以再深入研究。\n接著我們來看看Counter() 。\n顧名思義，Counter()基本上就是用來計算什麼東西出現幾次 用的，\n它是屬於collections裡面的一部分，\n我們直接來看範例：\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; from collections import Counter \u0026gt;\u0026gt;\u0026gt; scores = [35,70,10,20,35,70,70] \u0026gt;\u0026gt;\u0026gt; score_counter = Counter(scores) # 將list代入，即可產生一個Counter型態的東西 \u0026gt;\u0026gt;\u0026gt; score_counter Counter({70: 3, 35: 2, 10: 1, 20: 1}) # 為當中的元素計數 \u0026gt;\u0026gt;\u0026gt; names = [\u0026#39;James\u0026#39;, \u0026#39;Michael\u0026#39;, \u0026#39;Ted\u0026#39;, \u0026#39;James\u0026#39;, \u0026#39;Leo\u0026#39;] \u0026gt;\u0026gt;\u0026gt; Counter(names) # str也可以使用 Counter({\u0026#39;James\u0026#39;: 2, \u0026#39;Michael\u0026#39;: 1, \u0026#39;Ted\u0026#39;: 1, \u0026#39;Leo\u0026#39;: 1}) \u0026gt;\u0026gt;\u0026gt; score_counter.most_common() # most_common()會按由大到小的出現次數來排序 [(70, 3), (35, 2), (10, 1), (20, 1)] \u0026gt;\u0026gt;\u0026gt; score_counter.most_common(2) # 代入的值代表要取幾個數 [(70, 3), (35, 2)] 除了範例提到的基本以外，兩個Counter之間可以做加、減，\n結果就是將對應的key出現的次數加總及相減。\n(相減時小於等於0的部分會去掉)\n使用\u0026amp;和|則會像set一樣取得交集和聯集。\n前面包含了dict及defaultdict的部分，\n都有一個特點：它不一定 按照原先順序排列。\n那麼如果你真的很在意一開始的順序呢？\n我們可以使用**OrderedDict()**來處理。\n1 2 3 4 5 6 7 8 9 \u0026gt;\u0026gt;\u0026gt; scores = OrderedDict([(\u0026#39;James\u0026#39;, 80), (\u0026#39;Andy\u0026#39;, 70), (\u0026#39;Curry\u0026#39;, 100)]) # 每組要用tuple處理 \u0026gt;\u0026gt;\u0026gt; scores OrderedDict([(\u0026#39;James\u0026#39;, 80), (\u0026#39;Andy\u0026#39;, 70), (\u0026#39;Curry\u0026#39;, 100)]) # 按進去的順序，取出也會相同 \u0026gt;\u0026gt;\u0026gt; for s in scores: ... print(s) ... James Andy Curry 當我們在練習LeetCode寫題目時，\n常常會需要使用到stack(堆疊)或queue(佇列)這兩種資料結構，\n前者通常使用list即可，後者則一般會使用deque 。\n(理論上念做deck，但我都習慣念de-queue)\ndeque 是一個雙向的序列，\n可以從開頭或結尾傳入或取出資料。\n我們直接來看範例：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026gt;\u0026gt;\u0026gt; from collections import deque \u0026gt;\u0026gt;\u0026gt; s = \u0026#39;abcde\u0026#39; \u0026gt;\u0026gt;\u0026gt; deque(s) # 直接將字換成deque deque([\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;e\u0026#39;]) \u0026gt;\u0026gt;\u0026gt; d = deque(s) \u0026gt;\u0026gt;\u0026gt; scores \u0026gt;\u0026gt;\u0026gt; d.popleft() # 從左邊取出 \u0026#39;a\u0026#39; \u0026gt;\u0026gt;\u0026gt; d.popleft() \u0026#39;b\u0026#39; \u0026gt;\u0026gt;\u0026gt; d.pop() # 從右邊取出 \u0026#39;e\u0026#39; \u0026gt;\u0026gt;\u0026gt; d.append(\u0026#39;XDFES\u0026#39;) \u0026gt;\u0026gt;\u0026gt; d deque([\u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;XDFES\u0026#39;]) \u0026gt;\u0026gt;\u0026gt; d.appendleft(\u0026#39;YES\u0026#39;) \u0026gt;\u0026gt;\u0026gt; d deque([\u0026#39;YES\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;, \u0026#39;XDFES\u0026#39;]) 由於從右邊處理才是一般常見狀態，\n所以無論是append或pop，\n在往左時都會加上一個left，\n藉以區分兩者差別。\n如果對於資料結構、演算法、LeetCode有興趣的話，\n也歡迎看看去年的鐵人賽發文，或者查筆者的Medium系列文章!\n以上只不過是Python內建函式庫的冰山一角而已XD\n有興趣的讀者，可以再自己找看看有什麼你需要的東西~\n那我們來練習一下題目吧！ 給定兩個字串s跟t，已經知道t的組成，\n是將s的字母打亂以後進行重組，再隨機加上一個字母。\n請用前面所學，找出被加上的那個字母。 辛苦啦！我們明天見！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-26T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-11-standard-libraries/","title":"從零開始學Python (11) — 標準程式庫：你的機車不機車，載我瀏覽世界景色"},{"content":"Day 10 模組與套件：借一段往日旋律，宛轉悠揚 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10242602\n先來解答昨天的問題吧！ 假定有一個樓梯，你從第0階要爬到第n階，\n每次你只能選擇爬1階或者爬2階，這樣稱做一步。\n請寫出一個函式名為cs ，給定n的値以後(n \u0026gt; 0)，\n計算出從第0階爬到第n階的方法共有幾種不同的變化？ 上一篇提到了遞迴的關鍵點，首要在於將目標不斷簡化，\n那麼我們該怎麼思考這題的簡化呢？\n想想看，爬到第n階之前，應該要先爬到哪一階呢？\n應該是n-1或n-2階吧？因為一次只能走一步和走兩步。\n也就是說，假設我們知道cs(n-1)跟cs(n-2)，\n我們就能知道cs(n)，因為它們兩個狀況只要分別走1步或2步，\n就可以到達第n階，\n而且cs(n-1)跟cs(n-2)彼此之間並沒有重複的走法。\n所以cs(n) = cs(n-1) + cs(n-2)，\n接下來的問題是，在什麼狀況下該停下來？\n顯然，在n = 1及n = 2時，\ncs(1)和cs(2)的值已經確定是1跟2了，\n所以我們每次在遞迴時，只要碰到n=1或n=2時，就應該回傳n的值即可。\n1 2 3 4 def cs(n): if n == 1 or n == 2: return n # 請留意一件事情，函式在使用return回傳以後，不論它當下是否處在迴圏或者是否往下還有東西未完成，都會直接離開函式並回傳值歐！ return cs(n-1) + cs(n-2) 1 2 3 # 測試計算從cs(1)到cs(100) for i in range(1, 101): print(cs(i)) 這麼做其實有一個缺點：\n比方說我們算cs(10)的時候，會拆分成cs(9)跟cs(8)，\n而接下來會是：\ncs(9) -\u0026gt; cs(8) + cs(7) -\u0026gt; cs(7) + cs(6) + cs(6) + cs(5) -\u0026gt; …\ncs(8) -\u0026gt; cs(7) + cs(6) -\u0026gt; cs(6) + cs(5) + cs(5) + cs(4) -\u0026gt; …\n在化簡的過程中，因為Python並不知道我們有重複的東西，\n所以它並不會主動去幫我們把相同的cs(x)給結合在一起，\n所以最終就會相當耗時。\n(讀者可以執行)\n那該怎麼改善呢？\n這裡提供兩個方法。\n方法一：將用過的答案先記下來(可以使用list或dict)\n1 2 3 4 5 6 7 def cs(n, dic): # n在裡面就直接回傳(因為已經算過了!) if n in dic: return dic[n] # 先將n的結果算完再回傳，別忘了放到字典裡！ dic[n] = cs(n-1, dic) + cs(n-2, dic) return dic[n] 1 2 3 dic = {1 : 1, 2 : 2} # 預設cs(1), cs(2)的結果 for i in range(1, 101): print(cs(i, dic)) 方法二：lru_cache\nlru_cahce是一個工具，\n它可以記住函式已經計算過的內容，並存放起來。\n在maxsize=None的時候，我們就不會限制它最多可以記幾個，\n因此利用這個性質，它會幫我們自主處理重複計算的部分。\n1 2 3 4 5 6 import functools @functools.lru_cache(maxsize=None) # 用@開頭的稱為裝飾器，有興趣的讀者可再深入了解。 def cs(n): if n == 1 or n == 2: return n return cs(n-1) + cs(n-2) 1 2 for i in range(1, 101): print(cs(i)) 那麼該如何做出迭代解呢？\n由於cs(n)只跟cs(n-1)和cs(n-2)有關，\n我們完全可以從cs(3)開始，一路往上加到結束。\n1+2=3, 2+3=5, 3+5=8, …以此類推。\n當我們要算cs(n)時，表示我們需要經過n-2次的計算，\n因此，我們只要利用兩個變數反覆交替並取代，\n最終即可得到答案。\n1 2 3 4 5 6 7 8 def cs(n): if n == 1 or n == 2: return n s1, s2 = 1, 2 for i in range(n - 2): # Python的賦值是會一起看開始前的值來計算 # 所以不會因為s1的值變s2了, s2新的值就變成s2+s2 s1, s2 = s2, s1 + s2 return s2 1 2 for i in range(1, 101): print(cs(i)) 註：請留意當我們在使用字典或list時，其做為參數時是整包一起給，\n但當傳一般的int時，傳入的值則當成另一個本地端的變數看待。\n1 2 3 4 5 r = 33 def t1(r): print(r) r = 2 print(r) # 改完變2 1 2 3 4 def t2(lt): print(lt) lt[0] = 100 print(lt) 1 2 3 print(\u0026#39;t1\u0026#39;) t1(r) print(r) # 改完以後外面r的值還是33 1 2 3 4 print(\u0026#39;\\nt2\u0026#39;) lt = [555] t2(lt) print(lt) # 改完後lt內的值已經成為100了! 1 2 3 4 t1 33 2 33 1 2 3 4 t2 [555] [100] [100] 今天我們講點比較輕鬆的東西：模組和套件\n如同前面我們所提過的，因為重複做相同的事情太麻煩了，\n所以使用函式來將要重複做的事情寫在一起，可以反復呼叫。\n那麼，如果你知道有些你需要做的事情，\n已經有別人寫過了，用現成的當然會比自己寫還要快很多囉！\n我們前面已經用過幾次import(匯入)了，\n它的根本其實就是從你自己寫的程式，或者別人寫的程式(或函式庫)，\n把前人的智慧來個拾人牙慧一下XD!\nimport的寫法大體有如下的變化：\n1 2 3 4 import module # 直接將整個檔案納入(不用加.py) from module import function # 只匯入function的部分 import module as xx # xx是自己選的名字，用來在這個程式中全程替代原先的module名 from module import function as oo # 這時候用oo就相當於跟function一樣 舉例來說，在Python中有一個內建模組叫random，random中的random()，\n可以隨機生成一個0~1之間的小數亂數(包含0但不包含1)，\n我們可以先import random，再呼叫random的random()函式來得到亂數；\n或者，我們可以從random中取得random()函式，同時將其取一個別名。\n(要為模組取別名也行，取別名的好處是可以比較簡短，且可以避免碰到名稱衝突的問題)\n1 2 3 4 5 6 \u0026gt;\u0026gt;\u0026gt; import random \u0026gt;\u0026gt;\u0026gt; random.random() 0.8076966930768202 \u0026gt;\u0026gt;\u0026gt; from random import random as rd \u0026gt;\u0026gt;\u0026gt; rd() 0.23723453093568025 如果是Python內建的模組，那麼不論你的主要的程式.py檔放在哪都沒問題；\n但如果你想要匯入的是別的檔案，那麼要將這些檔案放在同一個目錄 下，\n才能夠正常匯入。\n如果我們要更嚴謹一點的話，就要使用套件 的形式。\n假設我們有一批寫好的檔案，他們都是這個主程式可能會用到的工具，\n我們可能會開一個名為utils(工具箱)的資料夾，\n裝入所有的檔案，比方說假設有check.py, schedule.py這兩個檔案。\n除此以外，還要裝入一個至少是空白的檔案，必須取名為__init__.py。\n(前後都有兩個底線)\n所以我們的資料夾結構會變成這樣：\n1 2 3 4 5 | — fromzero.py | — utils | — __init__.py | — check.py | — schedule.py 那我們來示範一下運作的模式：\n1 2 3 4 # fromzero.py from utils import check, schedule # 透過套件的模式來匯入 print(\u0026#34;Check a lucky number: \u0026#34;, check.getLucky()) print(\u0026#34;Check daily routine: \u0026#34;, schedule.get()) 1 2 3 4 # utils/check.py def getLucky(): from random import random return int(random() * 7 + 1) # 取1~7之間的亂數 1 2 3 # utils/schedule.py def get(): return \u0026#34;You have a meeting today!\u0026#34; # 就只是回傳一段str而已 那我們一樣來練習題目吧！ 上次我們的猜數字遊戲本來是固定的數字，\n已知現在可以使用從random模組中的函式取得亂數法，\n(詳見Python Document https://docs.python.org/3/library/random.html)\n請利用random.randint(a,b)或random.random()，\n將前面的題目中要猜的數字改成隨機的1~100(含)之間的整數。 承上題，1~100當中有一些數假設有我們想避開，\n不想被成為要猜的數字的話，\n若給定該串列avoid_lt = [4, 14, 44, 94]，\n請參照上面的說明，使用random.choice(seq)來處理。\n(random.choice()方法可以從一個序列型態的東西seq中隨機取出一個值)\n(序列是有順序的元素的集合統稱，比如list, tuple, range)\n提示：可以先新增一個數列並去處掉不要的元素再做random.choice() 辛苦啦！我們明天見！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-25T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-10-modules-and-packages/","title":"從零開始學Python (10) — 模組與套件：借一段往日旋律，宛轉悠揚"},{"content":"Day 09 例外處理、遞迴：誰用三生浮世的煙火，換你一次長憶的交錯 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10242043\n先來解答昨天的問題吧！ 為了表現出串列表達式的用法，\n這邊我們就先不將range的部分和取偶數合併，\n不然使用range(2, 11, 2)就行了。\n連同2的寫法如下： 1 2 3 4 5 6 7 8 9 lt1 = [] for i in range(1, 11): # 記得每層都是用縮排表示 if i % 2 == 0: for j in range(1, 11): if j % 2 == 0: lt1.append(i * j) print(lt1) lt2 = [i * j for i in range(1, 11) if i % 2 == 0 for j in range(1, 11) if j % 2 == 0] # 我們可以用不只一層的for來處理列表生成式 print(lt2) 執行結果參考如下：\n1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py [4, 8, 12, 16, 20, 8, 16, 24, 32, 40, 12, 24, 36, 48, 60, 16, 32, 48, 64, 80, 20, 40, 60, 80, 100] [4, 8, 12, 16, 20, 8, 16, 24, 32, 40, 12, 24, 36, 48, 60, 16, 32, 48, 64, 80, 20, 40, 60, 80, 100] 以現有給出來的內容，我們可以寫成類似以下的小遊戲： 1 2 3 4 5 6 7 8 9 10 11 ans, guess = 37, 0 l, r = 1, 100 while ans != guess: # 猜對就離開，猜錯則繼續 guess = int(input(\u0026#39;請在\u0026#39; + str(l) + \u0026#39;到\u0026#39; + str(r) + \u0026#39;之間猜一個數:\u0026#39;)) if guess \u0026lt; ans: print(\u0026#39;您猜的數字比答案還要小，請再猜大一點~\u0026#39;) l = guess + 1 # 範圍會被限縮到比剛剛猜的數字還要大做為左邊界 elif guess \u0026gt; ans: print(\u0026#39;您猜的數字比答案還要大，請再猜小一點~\u0026#39;) r = guess - 1 print(\u0026#39;恭喜你猜出答案啦！\u0026#39;) 請留意，這只是按照我們現在已經學到的部分來撰寫的，\n以這個解法來說的話就包含了以下幾個明顯的bug\n(程式臭蟲，指程式碼中有一些問題導致運行會當掉或是輸出結果有問題，\n可能是輸入錯誤，也有可能是程式的邏輯本身出的問題)：\n輸入非數字的時候會因為無法轉換成整數而使程式當掉。 輸入數字可以限縮範圍，但我們並沒有真的限制使用者只能輸入這個範圍內的數字。\n請參照執行結果，應該能理解上面兩點所造成的問題。 1 2 3 4 5 6 7 8 9 10 11 12 13 C:\\Users\\Desolve\u0026gt;python fromzero.py 請在1到100之間猜一個數:90 您猜的數字比答案還要大，請再猜小一點~ 請在1到89之間猜一個數:10 您猜的數字比答案還要小，請再猜大一點~ 請在11到89之間猜一個數:-5 您猜的數字比答案還要小，請再猜大一點~ 請在-4到89之間猜一個數:88 您猜的數字比答案還要大，請再猜小一點~ 請在-4到87之間猜一個數:34 您猜的數字比答案還要小，請再猜大一點~ 請在35到87之間猜一個數:37 恭喜你猜出答案啦！ 1 2 3 4 5 6 C:\\Users\\Desolve\u0026gt;python fromzero.py 請在1到100之間猜一個數:67u Traceback (most recent call last): File \u0026#34;fromzero.py\u0026#34;, line 4, in \u0026lt;module\u0026gt; guess = int(input(\u0026#39;請在\u0026#39; + str(l) + \u0026#39;到\u0026#39; + str(r) + \u0026#39;之間猜一個數:\u0026#39;)) ValueError: invalid literal for int() with base 10: \u0026#39;67u\u0026#39; 1 2 3 4 5 6 C:\\Users\\Desolve\u0026gt;python fromzero.py 請在1到100之間猜一個數:st Traceback (most recent call last): File \u0026#34;fromzero.py\u0026#34;, line 4, in \u0026lt;module\u0026gt; guess = int(input(\u0026#39;請在\u0026#39; + str(l) + \u0026#39;到\u0026#39; + str(r) + \u0026#39;之間猜一個數:\u0026#39;)) ValueError: invalid literal for int() with base 10: \u0026#39;st\u0026#39; 接下來我們來講今天的第一個主題：\n如昨天的第三題來說，我們會發現使用者永遠可以超乎你的想像。\n這時候你希望得到可以轉成1~100的字串，並且能夠處理掉輸入錯誤的問題的話，\n該怎麼辦呢？\n如果你能將使用者輸入的每一種內容都分門別類，\n當然可以用if…elif…else的形式來進行解決，\n如果沒有想要分那麼精細呢？\n我們可以使用Python的錯誤處理機制try…except…。\n基本語法如下：\n1 2 3 4 try: 有可能發生例外的程式碼 except: 發生例外時，執行這個區塊的程式碼處理 讓我們改一下前面的程式碼看看：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ans, guess = 37, 0 l, r = 1, 100 while ans != guess: try: guess = int(input(\u0026#39;\\n請在\u0026#39; + str(l) + \u0026#39;到\u0026#39; + str(r) + \u0026#39;之間猜一個數:\u0026#39;)) except: # 加入continue，直接跳過後面的範圍處理，回到迴圈的開頭 print(\u0026#39;請輸入正常的數字，不要加其他字母或符號呦！\u0026#39;) continue if guess \u0026lt; l or guess \u0026gt; r: # 超出範圍的部分同樣也要跳過(當然，也可以用elif和下面的判斷連起來) print(\u0026#39;請輸入正確範圍內的數字！\u0026#39;) continue if guess \u0026lt; ans: print(\u0026#39;您猜的數字比答案還要小，請再猜大一點~\u0026#39;) l = guess + 1 elif guess \u0026gt; ans: print(\u0026#39;您猜的數字比答案還要大，請再猜小一點~\u0026#39;) r = guess - 1 print(\u0026#39;恭喜你猜出答案啦！\u0026#39;) 在上面的程式中，當我們用try包住input那行以後，\n一旦我們輸入了不是數字的東西，原本Python會報錯並結束程式，\n此時就會改成來到except處來執行對應的程式碼。\n(如果沒輸入錯誤，except的部分就會被忽略)\n事實上，不同的例外在Python當中會有不同的錯誤類型，\n如果你想要分開精細地處理不同類型的例外的話，\n就要寫成如下型式：\n1 2 3 4 5 6 7 8 try: 有可能發生例外的程式碼 except 例外1 as 命名1: 處理例外1的種類所造成的例外的程式碼(發生什麼事情可以從命名1的變數印出) except 例外2 as 命名2: ... except 例外3 as 命名3: ... 當一個例外發生時會依序由上到下檢查符合哪一個種類的例外，\n先滿足條件的獨佔(可以想成類似if…elif的檢查方式)\n例外的類別有像是UppercaseException, IndexError, ValueError等等，\n他們的共同的大類別都是Exception。\n你也可以使用raise Exception(傳入值)來主動將例外丟出。\n(如果你有做好處理的準備的話)\n同時，它可以帶著給定的訊息，有助於我們判斷到底是怎麼一回事。\n1 2 3 4 5 6 \u0026gt;\u0026gt;\u0026gt; try: ... raise Exception(\u0026#39;讚讚\u0026#39;) ... except Exception as exc: ... print(exc) ... 讚讚 接下來我們要來講一個日後各位一定碰得到也很常用的方法：遞迴(Recursion) 。\n什麼是遞迴呢？\n遞迴就是當一個函式在使用時，中途不斷呼叫自己，\n藉以達到某些目的或完成某些問題。\n通常狀況下，\n寫得正常的遞迴應該會不斷在過程中將要計算的問題進行簡化，\n最終只剩下我們要的東西，同時沒有再繼續呼叫函式。\n聽起來……超級無敵抽象的阿！！！\n沒關係，讓我們看看實際的範例。\n還記得那個白目的小男孩高斯嗎？\n假設我們不會公式，希望使用Python來幫我們手算1~100，\n按現有前面學過的東西，你可能會這樣寫：\n1 2 3 4 5 6 7 # 別命名成sum()，它是Python已經有的東西，可以用來計算一個串列的所有值加總 # 預設算到100 def cal(end=100): res = 0 # res意思是result, 你要命名成ans也可以，看自己習慣 for i in range(1, end + 1): # range的範圍記得是頭算尾不算，所以要加1 res += i return res 1 print(cal()) 如果你不會range的話可能就真的要一個一個加了！\n那麼，從遞迴的角度是怎麼看待這件事情的呢？\n答案是一個一個處理 。\n既然cal(100)是1加到100，那麼cal(99)就是1加到99；\n因此，cal(100)就相當於100加上cal(99)囉！\n以此類推，我們可以得到cal(end)會等於end + cal(end — 1)。\n於是，我們可以將函式按照這個概念重寫成下面的樣子：\n1 2 3 # 好像哪裡怪怪的？ def cal(end): return end + cal(end - 1) 有沒有覺得哪邊怪怪的？\n我們忘記一件事情，就是當碰到cal(1)的時候，\n它本身應該要直接等於1才對，\n不然按照這樣呼叫下去，cal輸入的值會變成0, -1, -2, -3, … ，\n但不會停下來XD！\n那我們再改寫一下：\n1 2 def cal(end): return end + cal(end - 1) if end != 1 else 1 說明一下，上面的式子前面還沒有講過，但應該不難理解，\n這是屬於Python的三元運算子，使用if跟else，\n也就是說，當end != 1時，這行會回傳前面那段”end + cal(end — 1)” ，\n否則，就回傳1 (也就是當end為1時，直接回傳1就對了！)。\n實際在呼叫函式的時候，例如將100代入，\n我們會先呼叫cal(100)，發現cal(100)要算100+cal(99)；\nPython會將100先記錄下來，先去算cal(99)，\n也就是等算出cal(99)後，再回過頭來加上100；\ncal(99)又會被拆成99+cal(98)，以此類推。\n由於函式執行時實際上需要記憶體空間，這種還沒得到結果的函式，\n往下又呼叫了東西的話，就會再疊上下一段的函式，\n也就是在電腦的記憶體中會有地方放cal(100), cal(99), cal(98)… ，\n一路堆疊上去，這樣子的結構被我們稱之為呼叫堆疊(call stack) 。\n所以假設一個函式還沒完成，\n就又在裡面呼叫另一個函式(可能是自己或別人)的話，\ncall stack就會越疊越高，從而占用大量記憶體。\n因此，一般來說程式語言都會限制call stack最大的堆疊的函式數量，\n以Python來說，可以用以下的方式來檢查call stack的限制：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; import sys # import我們會在後面進行介紹 \u0026gt;\u0026gt;\u0026gt; print(sys.getrecursionlimit()) 1000 所以如果我們將剛剛的cal改成1000的話，這個程式就廢了XD!\n1 2 3 4 5 6 7 8 9 10 11 12 C:\\Users\\Desolve\u0026gt;python fromzero.py Traceback (most recent call last): File \u0026#34;fromzero.py\u0026#34;, line 4, in \u0026lt;module\u0026gt; print(cal(1000)) File \u0026#34;fromzero.py\u0026#34;, line 2, in cal return end + cal(end - 1) if end != 1 else 1 File \u0026#34;fromzero.py\u0026#34;, line 2, in cal return end + cal(end - 1) if end != 1 else 1 File \u0026#34;fromzero.py\u0026#34;, line 2, in cal return end + cal(end - 1) if end != 1 else 1 [Previous line repeated 996 more times] RecursionError: maximum recursion depth exceeded in comparison 我們總結一下建立一個遞迴函式的條件：\n我們可以將一個要計算的東西拆小 ，不管是拆成一部分已知一部分未知 ，\n或是拆成數塊比較小的部分 都可以。 在越拆分越小的時候，要至少有一個狀態是可以直接得到結果的 (比如剛剛的cal(1)=1)，\n因而，讓所有的區塊最後都能變成已知，從而可以計算出結果 。 讀者可能會有一些疑惑：\n看起來遞迴好像就簡單一點，但是沒有迴圏快阿！\n而且迴圏也不會有限制call stack的層數的問題，為什麼不用迴圏呢？\n好問題！\n我們現在示範的只是很簡單的範例，\n事實上在絕大多數狀況下，可以用遞迴的問題，用迴圏也寫得出來，\n這邊通常會稱使用迴圏寫出來的解法為迭代解(iterative solution)。\n問題是……\n越難的題目，通常遞迴解就會很常比迭代解還要容易思考，\n而迭代解有時候會需要用到比較複雜的推導，才能夠寫出來！\n所以如果未來讀者在學了Python以後，\n可能還學了一些別的進階的應用，當面試的時候被考到白板題，\n在沒有特別的狀況下，請盡量先確定給出自己遞迴解，\n有信心的話，再更進一步去嘗試迭代解，會比較穩妥。\n補充：\n感謝FB 程式人雜誌 社團的網友** Cheng-En Chuang**留言補充如下，\n想更深入了解遞迴的運作的話，請參考他的解說及提供的參考資料：\n「有點雞蛋裡挑骨頭，\n但遞迴在Python裡面有深度限制是因為沒做tail-call optimization。\n在其他有做tail-call optimization的語言裡面就不會有深度限制，\n另外在某些語言裡面recursion也不一定比iteration慢。\n甚至在Python裡面也可以用decorator達到tail-call效果：\nhttps://towardsdatascience.com/python-stack-frames-and-tail-call-optimization-4d0ea55b0542」\n那我們一樣來練習題目吧！ 假定有一個樓梯，你從第0階要爬到第n階，\n每次你只能選擇爬1階或者爬2階，這樣稱做一步。\n請寫出一個函式名為cs，給定n的値以後(n \u0026gt; 0)，\n計算出從第0階爬到第n階的方法共有幾種不同的變化？\n例：\ncs(1) = 1 (1)\ncs(2) = 2 (1+1, 2)\ncs(3) = 3 (1+2, 2+1, 1+1+1)\ncs(4) = 5 (1+1+2, 2+2, 1+2+1, 2+1+1, 1+1+1+1)\n請分別給出遞迴解和迭代解。 對初學者來說，可能不是那麼容意思考，請務必好好觀察函式之間的關係。\n辛苦啦！我們明天見！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-24T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-9-exception-handling-recursion/","title":"從零開始學Python (9) — 例外處理、遞迴：誰用三生浮世的煙火，換你一次長憶的交錯"},{"content":"Day 08 程式結構與流程語法：如果對手太弱太簡單，那不是很爽嗎?(下) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10241349\n在上一篇文章中我們講了if…elif…else, while, for, 以及range，\n我們也提到了像range()這樣子的方法，是用來生成一個可迭代的Python物件。\n而只要可迭代的話，我們通常就可以將其轉成一個list，如上一篇文章那樣。\n不管是if, while, for等，都可以使用多層的架構，\n對於while跟for來說，其處理方式也是類似多層if的概念，\n同時外層內層的東西不同也是可以的。\n例如：\n1 2 3 4 5 6 7 while xxx: ooo rrr while yyy: uuu vvv www 這個雙重迴圏，執行的順序應該是：\nxxx成立時，進入迴圏-\u0026gt;ooo-\u0026gt;rrr-\u0026gt;\nyyy成立時，進入迴圏-\u0026gt;uuu-\u0026gt;vvv-\u0026gt;\n內層迴圏完成一次，重新檢查yyy，若成立則繼續運行，\n否則就會執行完www後，回到xxx檢查。\n(所以說內層的執行完，才會輪到外層)\n今天我們要介紹一個在Python中很好用且常用的東西，\n它也用到了for…in…的方法，名字叫做list comprehension ，\n可以用來快速簡單地生成list，\n中文目前沒有統一的叫法，\n可以叫成串列生成式/串列表達式/串列解析式 都行。\n其基本形式像這樣：\n[算式 for 單項 in 迭代項目]\n舉例來說，假設我們要一個從0~9的串列，我們可以這樣寫：\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; list(range(9)) [0, 1, 2, 3, 4, 5, 6, 7, 8] \u0026gt;\u0026gt;\u0026gt; [i for i in range(9)] [0, 1, 2, 3, 4, 5, 6, 7, 8] 串列生成式的意義在於每次從迭代的項目當中取出一個單項，\n接下來將這個單項透過算式進行加工處理，才放到list當中。\n所以除了基本的方法以外，我們也可以用if條件式來進行過濾，只要在後面加上if條件式即可。\n1 2 \u0026gt;\u0026gt;\u0026gt; [2 * i for i in range(9) if i % 2 == 0] # 取0~8當中能整除2的數，每個都先乘以2再加到list [0, 4, 8, 12, 16] 另一方面，我們也可以利用多重的for in來製造出雙層的list，\n或者組合性質的東西。\n我們前面提到過list裡面的element也可以是list，\n如果我們今天要表達一組4 * 3的格子，格子裡面一開始只放零的話，\n可以寫成：\n1 2 \u0026gt;\u0026gt;\u0026gt; [[0 for i in range(3)] for j in range(4)] # 一層一層看就會理解等於[0, 0, 0]重複4次 [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]] 如果我想要把所有的座標(從(0, 0)起算)的組合寫到一個list呢?\n1 2 3 \u0026gt;\u0026gt;\u0026gt; combo = [(row, col) for row in range(4) for col in range(3)] # 留意4跟3的順序 \u0026gt;\u0026gt;\u0026gt; combo [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (3, 0), (3, 1), (3, 2)] (註：像這樣子在存取每一個格子都需要指定兩層index的串列，\n我們稱之為二維串列，代表它有兩個維度。)\n字典和集合也有生成式，其概念和列表生成式一致，\n只是字典的話就會是{key:value for 單項 in 迭代項} (必須給出key跟value的部分)\n集合的話除了外面是大括號 外，和列表生成式一致。\n接下來我們要來談一個程式語言很重要的東西：函式(function)\n還記得前面我們有做過計算圓面積的練習對吧？\n計算圓面積明明是一個不會改變的公式，\n但我們還是要反覆改動代入值，這樣顯得有點麻煩。\n為了不要浪費時間在做相同的事情上，\n我們可以將寫好的一段程式碼(比如剛剛講的算面積)，定義成函式，\n就像數學的函式那樣，公式已經寫好了，只差將要算的東西代入進去就好。\n一個函式的程式架構一般如下：\n1 2 3 4 5 def 函式名(變數1, 變數2, 變數3, ...): xxx yyy ... return ooo def代表define(定義) ，後面接你的命名，\n括號內是放入你需要從呼叫函式的對象那邊得到的變數(或者稱為參數)，\n也可以都不放，表示你不需要從外界傳入；\n接著就在這個函式內按照一般程式碼的流程來撰寫，\n最終如果這個函式需要回報一些訊息的時候，則需要進行return(回傳) 。\n我們拿圓面積計算為例：\n1 2 3 def area(r): pi = 3.14 return 3.14 * r ** 2 # 會將計算完的結果輸出到呼叫它的地方 由於Python是腳本式語言，\n一個函式必需要先被定義或引入後，\n才能夠被使用，所以我們必須在使用(或稱呼叫)函式前，\n先將它定義完，在下一行開始才能夠使用它。\n1 2 3 4 5 6 7 # area(1) 不能放在這邊，因為我們還沒有定義area函式! def area(r): pi = 3.14 return 3.14 * r ** 2 print(\u0026#39;半徑長為1的圓，其面積為：\u0026#39; + str(area(1))) print(\u0026#39;半徑長為3的圓，其面積為：\u0026#39; + str(area(3))) 執行結果如下：\n1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py 半徑長為1的圓，其面積為：3.14 半徑長為3的圓，其面積為：28.26 假設我們今天不滿足圓周率pi只用3.14的話，\n除了用math模組的pi外(引入模組這部分之後再講)，\n那麼就必須將pi也一併設定為可以拿進來用的變數。\n但是一般來說，像pi這類型的常數，\n我們會希望**「不特別講的話就按照預設的來」，** 這時候我們可以利用在給入的變數的後面加上等號及一個值 ，\n一旦這個變數沒有被指定，就會使用預設值 。\n此外，很多時候乍看之下，我們會容易不曉得一個函式中，\n每一個位置先後要代入什麼才是對的順序，\n為此，Python提供我們可以指定變數名稱的方式，\n只要輸入時有帶上變數名稱，即便順序和原先函式定義給的順序不一樣，\nPython依舊可以正確地幫我們對應上。\n1 2 def area(r, pi=3.14): return pi * r ** 2 1 2 3 print(\u0026#39;半徑長為1的圓，其面積為：\u0026#39; + str(area(1, 3.14159))) # 指定圓周率 print(\u0026#39;半徑長為3的圓，其面積為：\u0026#39; + str(area(3))) # 不指定圓周率，使用預設值3.14 print(\u0026#39;半徑長為3的圓，其面積為：\u0026#39; + str(area(pi=3.141, r=3))) # 順序會被自動對上 結果如下：\n1 2 3 4 C:\\Users\\Desolve\u0026gt;python fromzero.py 半徑長為1的圓，其面積為：3.14159 半徑長為3的圓，其面積為：28.26 半徑長為3的圓，其面積為：28.269 同樣的，在函式內部也可以定義函式，\n一樣的概念，要有定義過的才能被呼叫使用，\n同時，可以接受參數，但也可以直接用其外層得到的變數。\n1 2 3 4 5 6 7 8 9 def printAll(r, pi=3.14): def area(): return pi * r ** 2 def perimeter(): return 2 * pi * r # 下面{}的用法是所謂的format，可以將多個變數按照順序放置到{}中 print(\u0026#39;半徑 = {}的圓，其面積 = {}，周長 = {}\u0026#39;.format(r, area(), perimeter())) printAll(3, 3.14159) 執行結果如下：\n1 2 C:\\Users\\Desolve\u0026gt;python fromzero.py 半徑 = 3的圓，其面積 = 28.27431，周長 = 18.849539999999998 我們前面已經提過，\n變數就像是將一個標籤(變數名稱)貼在一個裝有東西(資料)的箱子。\n那麼，你家的急救箱和我家的急救箱 ，\n雖然名字都是急救箱，但應該是指不一樣的東西。\n在Python或其他程式語言中也一樣，\n一個名稱，有屬於它存在的適用範圍，我們稱之為命名空間。\n如果在最外面(也就是沒有在函式中)命名一個變數的時候，\n任何人應該都看得到這個變數的存在，並且可以自由使用它，\n我們稱之為全域變數 。\n那麼在函式內呢？\n如果今天在公共的地方有一個急救箱，你又自己去買了一個急救箱回來，\n那麼在命名時，\n你在你家稱呼的急救箱，自然是你自己買的那個，而非公共的。\n(稱為區域(local)變數 )\n除非你都用公共的，那麼自然你指的還是那個公共的急救箱\n(函式內可以取得全域變數 )\n如果打定主意要用全域變數，且有要進行修改的話，\n請在函式內使用global 這個關鍵字。\n1 fak = \u0026#39;global\u0026#39; # First-Aid Kit 1 2 def home1(): print(fak) # 直接取得全域的變數，不做修改 1 2 3 4 5 6 7 8 def home2(): fak = \u0026#39;h2\u0026#39; # 定義一個local的變數，所以修改到的變數跟全域的fak無關 print(fak) def home3(): global fak # 告訴Python現在要用的就是全域的那個fak fak = \u0026#39;h3\u0026#39; print(fak) 1 2 3 4 5 6 print(\u0026#39;Before:\u0026#39;) print(fak) print(\u0026#39;\\nhome1:\u0026#39;) home1() print(\u0026#39;After home1:\u0026#39;) print(fak) 1 2 3 4 print(\u0026#39;\\nhome2:\u0026#39;) home2() print(\u0026#39;After home2:\u0026#39;) print(fak) 1 2 3 4 print(\u0026#39;\\nhome3:\u0026#39;) home3() print(\u0026#39;After home3:\u0026#39;) print(fak) 所以我們可以看到這三者之間的差異，\n一個只印出全域變數，一個只使用區域變數，第三個則是不但使用了全域變數且修改了它。\n1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py Before: global 1 2 3 4 home1: global After home1: global 1 2 3 4 home2: h2 After home2: global 1 2 3 4 home3: h3 After home3: h3 註：其實還有更細節的部分，但講太多恐怕對初學者容易造成混淆，\n我們還是先講這兩種就好，其他的在碰到狀況，或有興趣的話，\n再請讀者搜尋變數範圍的部分。\n那麼我們來做個練習吧！ 請使用兩個迴圏，將1~10之間的偶數兩兩相乘並放到一個空的list中。\n(所以這個list應該會有\n2 * 2, 2 * 4, 2 * 6, 2 * 8, 2 * 10, 4 * 2, 4 * 4, …, 10 * 10) 請改用列表生成式來完成1的問題。 請用while, if else等，寫出一個猜數字的遊戲，遊戲的答案為37，\n請在開始時提示使用者猜1~100範圍中的數字，\n並依據使用者的答案，逐步將範圍縮小，直到猜中答案，\n則印出恭喜訊息並離開迴圏。\n(先不考慮使用者會亂輸入的問題，\n並且要告訴使用者這次猜的比答案大還是小) 那就明天見啦！\n2023/08/29: 感謝iT邦幫忙的Sean勘誤周長和面積呼叫順序顛倒的問題~\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-23T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-8-programming-structure-flow-control-2/","title":"從零開始學Python (8) — 程式結構與流程語法：如果對手太弱太簡單，那不是很爽嗎?(下)"},{"content":"Day 07 程式結構與流程語法：如果對手太弱太簡單，那不是很爽嗎?(上) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10240601\n先來解答昨天的問題吧！ 李嚴的是炸鳳尾蝦，劉昴星的是雲龍炸蝦，\n如同上一篇所提到的，字典的value是可以是list的！ 按照步驟，前三個問題要取liu-lee, lee-liu, lee \u0026amp; liu，\n後面將set加進新的key後再替代回原本shrimp[‘炸鳳尾蝦’]。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 \u0026gt;\u0026gt;\u0026gt; shrimp = {\u0026#39;炸鳳尾蝦\u0026#39;:[\u0026#39;蝦子\u0026#39;,\u0026#39;核果\u0026#39;,\u0026#39;油\u0026#39;],\u0026#39;雲龍炸蝦\u0026#39;:[\u0026#39;蝦子\u0026#39;,\u0026#39;核果\u0026#39;,\u0026#39;油\u0026#39;,\u0026#39;豆皮\u0026#39;,\u0026#39;醬汁\u0026#39;]} \u0026gt;\u0026gt;\u0026gt; lee = set(shrimp[\u0026#39;炸鳳尾蝦\u0026#39;]) \u0026gt;\u0026gt;\u0026gt; liu = set(shrimp[\u0026#39;雲龍炸蝦\u0026#39;]) \u0026gt;\u0026gt;\u0026gt; lee # 所以我說那個醬汁呢？ {\u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;, \u0026#39;蝦子\u0026#39;} \u0026gt;\u0026gt;\u0026gt; liu {\u0026#39;醬汁\u0026#39;, \u0026#39;蝦子\u0026#39;, \u0026#39;豆皮\u0026#39;, \u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;} \u0026gt;\u0026gt;\u0026gt; liu-lee {\u0026#39;豆皮\u0026#39;, \u0026#39;醬汁\u0026#39;} \u0026gt;\u0026gt;\u0026gt; lee-liu　# 李嚴沒有多用到的東西 set() \u0026gt;\u0026gt;\u0026gt; lee \u0026amp; liu # 都用到的材料 {\u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;, \u0026#39;蝦子\u0026#39;} \u0026gt;\u0026gt;\u0026gt; lee.add(\u0026#39;蘋果\u0026#39;, \u0026#39;洋蔥\u0026#39;,\u0026#39;醬汁\u0026#39;) # set不能夠一次add多個key，除了一個一個加以外，也可以用update()方法。(lee.update([\u0026#39;蘋果\u0026#39;, \u0026#39;洋蔥\u0026#39;,\u0026#39;醬汁\u0026#39;])) Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; TypeError: add() takes exactly one argument (3 given) \u0026gt;\u0026gt;\u0026gt; lee.add(\u0026#39;蘋果\u0026#39;) \u0026gt;\u0026gt;\u0026gt; lee.add(\u0026#39;洋蔥\u0026#39;) \u0026gt;\u0026gt;\u0026gt; lee.add(\u0026#39;醬汁\u0026#39;) \u0026gt;\u0026gt;\u0026gt; lee {\u0026#39;洋蔥\u0026#39;, \u0026#39;醬汁\u0026#39;, \u0026#39;蝦子\u0026#39;, \u0026#39;蘋果\u0026#39;, \u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;} \u0026gt;\u0026gt;\u0026gt; lee-liu {\u0026#39;洋蔥\u0026#39;, \u0026#39;蘋果\u0026#39;} \u0026gt;\u0026gt;\u0026gt; shrimp[\u0026#39;炸鳳尾蝦\u0026#39;] = list(lee) \u0026gt;\u0026gt;\u0026gt; shrimp {\u0026#39;炸鳳尾蝦\u0026#39;: [\u0026#39;洋蔥\u0026#39;, \u0026#39;醬汁\u0026#39;, \u0026#39;蝦子\u0026#39;, \u0026#39;蘋果\u0026#39;, \u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;], \u0026#39;雲龍炸蝦\u0026#39;: [\u0026#39;蝦子\u0026#39;, \u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;, \u0026#39;豆皮\u0026#39;, \u0026#39;醬汁\u0026#39;]} 按照題目要求一個一個來就可以了，請留意index的初始値是0這點呦！ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 \u0026gt;\u0026gt;\u0026gt; lt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] \u0026gt;\u0026gt;\u0026gt; lt1 = lt[::2] \u0026gt;\u0026gt;\u0026gt; lt2 = lt[1::2] \u0026gt;\u0026gt;\u0026gt; lt1, lt2 ([1, 3, 5, 7, 9], [2, 4, 6, 8, 10]) \u0026gt;\u0026gt;\u0026gt; lt1.extend(lt2) \u0026gt;\u0026gt;\u0026gt; lt1 [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] \u0026gt;\u0026gt;\u0026gt; del lt1[7] \u0026gt;\u0026gt;\u0026gt; lt1 [1, 3, 5, 7, 9, 2, 4, 8, 10] \u0026gt;\u0026gt;\u0026gt; del lt1[1] \u0026gt;\u0026gt;\u0026gt; lt1 [1, 5, 7, 9, 2, 4, 8, 10] \u0026gt;\u0026gt;\u0026gt; lt1.sort() \u0026gt;\u0026gt;\u0026gt; lt1 [1, 2, 4, 5, 7, 8, 9, 10] 接下來，讓我們來介紹今天的主題：程式結構與流程語法。\n在這篇文章中，我們要來介紹一些超級無敵常用的東西，\n常用到基本上天天會遇到的那種。\n首先是程式結構。\n我們應該在前幾篇文章中有提到過，\n在Python中當需要執行的東西比較多時，\n我們是可以將一整段寫在一個.py檔案裡，\n再用python xxx.py 的方式去執行，對吧！\n在之後的程式裡，如果程式碼比較多比較複雜，\n建議讀者先將程式規劃好打在檔案內，再進行執行，\n可以避免打錯造成的一些麻煩。\n先來談談註解 ，註解通常使用**「#」的符號，\n基本上意味著一行程式碼在這個符號後面的任何東西都不會有影響。\n(且只影響該行)\n(但是擺在字串內的話就不會有註解的效果，會被當成普通的字元)\n通常狀況下，在文字編輯器內將想註解的行框起來，再按Ctrl+/**，\n編輯器會自動幫助你將這幾行都註解起來。\n如果要多行註解的話，也可以在行的最前面使用’’’ (三個單引號)，\n註解結束的位置同樣放置’’’。\n(但這種註解一般被視為在為函式(後面會提到)打說明文件用的文字，\n稱之為文件字串(docstring)，\n沒特別需求的話，Ctrl+/即可)\n1 2 3 4 5 6 7 \u0026#39;\u0026#39;\u0026#39; a = 10 b = 5 print(a * b) print(\u0026#34;一起從零開始學Python，我知道10 * 5 = \u0026#34; + str(a * b)) # 雖然這行有「#」，但實際起作用是外層造成的 \u0026#39;\u0026#39;\u0026#39; 如果你有一整行很長的運算或文字，\n想要做換行的話，請在換行之前的行尾放上「\\」 ，\nPython會將這樣延續下去的行都當成同一行解讀。\n如果在直譯器的狀態下也適用，\n這時候直譯器會顯示「…」，代表這行還沒輸入完。\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; 3+5+7+\\ ... +11+18+\\ ... 23\\ ... +10 77 接下來就是所有程式基本上都有的方法：如果(if)\n「如果…我就…」這種思維邏輯是日常中很常用到的概念，\nPython中也不例外，我們常常需要很多判斷來決定下一步要怎麼走。\n語法結構如下：\n1 2 3 4 5 6 7 if 陳述式1: 要做的事情1(可以不只一行) elif 陳述式2: 要做的事情2(可以不只一行) ... else: 要做的事情n(可以不只一行) 上面的意思是說，當陳述式1的結果是真(True)的的時候，\n就做「要做的事情1」，\n否則如果(elif, 也就是else if的意思)陳述式2是真的的時候，\n就做「要做的事情2」，\n可以一直接續，前面的陳述式(statement)一旦先碰到一組是真的時候，\n做完要做的事情就離開了，\n並不會繼續往下看 。\n一直到最後一個else的時候，前面的都不成立，就做「要做的事情n」 。\n這個結構底下，你可以選擇使用if, if…elif…else, if…else, if…elif都可以。\n(只要順序是if最先，elif其次，else擺最後 即可)\n其他語言在框「要做的事情」時，\n通常會使用大括號{}來表達開頭和結尾，\n這點在Python中有很大的不同！\nPython中會在陳述式後面加上一個冒號:來做為分界，\n接下來的式子執行到哪裡，並不使用大括號，\n而是看縮排的程式碼到哪一行。\n(一般縮排是用4個空格 ，盡量不要使用tab或2個空格)\n還記得上一篇問題中的炸蝦嗎？\n1 2 3 4 5 6 7 lee = {\u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;, \u0026#39;蝦子\u0026#39;} if \u0026#39;醬汁\u0026#39; not in lee: # 李嚴並沒有做醬汁，所以這個陳述式會是真 print(\u0026#39;李嚴\u0026#39;) print(\u0026#39;沒醬汁\u0026#39;) else: print(\u0026#39;有醬汁\u0026#39;) print(\u0026#39;所以我說那個醬汁呢？\u0026#39;)\t# 這個print並不在else的範圍內！ 我們執行上面的程式碼的結果應該會得到：\n1 2 3 李嚴 沒醬汁 所以我說那個醬汁呢？ 因為最後一行並沒有縮排，所以不會算在else的範圍內，\n依舊會被print出來。\n在判斷的時候，除了剛剛示範的in，\n可以使用其他的比較運算子及布林運算子來計算真假。\n比較運算子 有：==(相等，因為一個等號是將右邊的東西指定給左邊), !=(不等於),\n\u0026lt;(小於), \u0026gt;(大於), \u0026lt;=(小於等於), \u0026gt;=(大於等於), in…(前者在後者的範圍內)\n布林運算子 常用的有：and(且), or(或), not(否定)\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; x=24 \u0026gt;\u0026gt;\u0026gt; x\u0026gt;3 True \u0026gt;\u0026gt;\u0026gt; x\u0026lt;21 False \u0026gt;\u0026gt;\u0026gt; 12\u0026lt;x\u0026lt;100 # 相當於12 \u0026lt; x and x \u0026lt; 100 True \u0026gt;\u0026gt;\u0026gt; x == 24 True \u0026gt;\u0026gt;\u0026gt; lt = [1, 3, 24, 10, 33] \u0026gt;\u0026gt;\u0026gt; x in lt and not x \u0026lt; 23 # and/or的優先順序比較低，會等左右計算完成才處理，not會將結果反轉 True 如果有很多重的判斷的話，\n我們也可以將其寫成不同層來處理，\n怎麼判斷不同層的方式，一樣是看縮排來決定。\n1 2 3 4 5 6 7 8 x = 24 if x % 2 == 0: if x % 3 == 0: print(\u0026#39;6的倍數\u0026#39;) else: print(\u0026#39;2的倍數\u0026#39;) else: print(\u0026#39;不是2的倍數\u0026#39;) 執行完應該會print出’6的倍數’，讀者也可以自行嘗試做出不同的多層if結構。\n接著要補充一個很重要的點：\nPython在處理判斷時，也可以將單純的資料型態做為判斷的依據，\n這時候主要在考慮的，就是這個資料型態是否有存放東西，或者它是0 。\n包含False, None(代表沒有東西), 0, 0.0, ‘’(空字串), [], (), {}, set()等，\n在做為True/False的判斷中，都會被視為False。\n所以例如要判斷一個list是否為空，我們可以這樣寫：\n1 2 3 4 5 6 7 \u0026gt;\u0026gt;\u0026gt; lt = [] \u0026gt;\u0026gt;\u0026gt; if lt: ... print(\u0026#39;lt is not empty\u0026#39;) ... else: ... print(\u0026#39;lt is empty\u0026#39;) ... lt is empty 接下來我們來談談迴圈 。\n迴圈在Python裡面有兩種：while跟for。\nwhile的語法結構如下。\n1 2 3 4 5 while 陳述式: xxx yyy zzz ... while很簡單，只要這個陳述式是真的 ，就會將下面的程式碼區塊執行一次 ，\n做完以後呢？回到while這行，重新判斷一次 ，\n如果還是成立，就再做一次；\n一直到陳述式不成立，或者我們呼叫一些其他的東西強行跳出，才會離開。\n可以用來跳離迴圈的方式名為break ，顧名思義就是強行中止現在所在的迴圈 ，\n不繼續往下執行 。\n另外有一個功能叫continue ，目的是跳過這次的迴圈 (只跳過這次歐！)，\n回到while這行 ，依照陳述式的結果決定要不要再繼續執行。\n我們下面使用input()方法來示範，它能顯示提示字樣，並接受使用者輸入一段字串存放，\n讀者可以自行試試看，是否除非你選擇專家模式，否則完全無法離開迴圈。\n1 2 3 4 5 6 7 8 9 while True: # 使用while True須謹慎，一定要留下可以離開的方法！ mode = input(\u0026#39;請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] \u0026#39;) if mode == \u0026#39;3\u0026#39;: print(\u0026#39;\\n選擇專家模式的難關 帶著我的夥伴 還有我的不平凡\u0026#39;) break elif mode == \u0026#39;1\u0026#39; or mode == \u0026#39;2\u0026#39;: # 簡單來說，其他模式都不給過XD print(\u0026#39;不選難一點的嗎？再給你選一次！\\n\u0026#39;) continue # 所以在這邊會直接回到迴圈開始處，因而不會印出下一行 print(\u0026#39;請輸入正確的選項！\\n\u0026#39;) 1 print(\u0026#39;恭喜你選擇專家模式，加油！\u0026#39;) 1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 5545 請輸入正確的選項！ 1 2 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 1 不選難一點的嗎？再給你選一次！ 1 2 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 2 不選難一點的嗎？再給你選一次！ 1 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 3 1 2 選擇專家模式的難關 帶著我的夥伴 還有我的不平凡 恭喜你選擇專家模式，加油！ 在Python中，迴圈還有一個特別的用法，就是可以加else。\n1 2 3 4 while 陳述式: xxx else: ooo 當while正常的結束，沒有被break跳出 的話，\n離開後就會出來找else的區塊執行。\n(讀者可將其想成if else的感覺，\n正常離開迴圈就是陳述式結果為false的狀況，所以要走else路線)\n反之，當迴圈是被break強行離開時，就不會走到else去了！\n舉例來說，我們也可以將上面改成：\n1 2 3 4 5 6 7 8 9 10 11 12 mode = \u0026#39;\u0026#39; while mode != \u0026#39;3\u0026#39;: # 使用者選專家模式才能離開！ mode = input(\u0026#39;請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] \u0026#39;) if mode == \u0026#39;3\u0026#39;: print(\u0026#39;\\n選擇專家模式的難關 帶著我的夥伴 還有我的不平凡\u0026#39;) elif mode == \u0026#39;1\u0026#39; or mode == \u0026#39;2\u0026#39;: # 簡單來說，其他模式都不給過XD print(\u0026#39;不選難一點的嗎？再給你選一次！\\n\u0026#39;) else: print(\u0026#39;不想玩就算了！\\n\u0026#39;) # 不想玩的，後續就不繼續給提示 break else: # 正常離開，表示mode輸入了\u0026#39;3\u0026#39; print(\u0026#39;恭喜你選擇專家模式，加油！\u0026#39;) 1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 1 不選難一點的嗎？再給你選一次！ 1 2 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 2 不選難一點的嗎？再給你選一次！ 1 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 3 1 2 選擇專家模式的難關 帶著我的夥伴 還有我的不平凡 恭喜你選擇專家模式，加油！ 1 2 3 C:\\Users\\Desolve\u0026gt;python fromzero.py 請問你要選擇什麼模式？1. 簡單模式 2. 困難模式 3. 專家模式 [輸入1, 2, 3] 8 不想玩就算了！ 通常狀況下，我們會將迴圏的過程每一次的執行稱為一次迭代(iteration) 。\n有些資料型態可以適合每次從裡面取出一個單位出來，\n例如str, list, set, dict, tuple…等，\n這時候我們會說這些是可迭代的Python物件。\n對於可迭代的東西，我們有另一個for迴圏的模式可以輕鬆處理。\nfor迴圏的語法結構如下：\n1 2 for xxx in ooo: (對xxx做事情，比如印出來) 舉例來說，我們可以從一個list中一個一個取出當中的element，\n並將其印出。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 \u0026gt;\u0026gt;\u0026gt; lt = [1, -5, 3, 2, 4, 10, 100] \u0026gt;\u0026gt;\u0026gt; for num in lt: ... print(num) ... 1 -5 3 2 4 10 100 \u0026gt;\u0026gt;\u0026gt; index = 0 # 也可以用index的方式一個一個拿，不要忘記將index每次加1 \u0026gt;\u0026gt;\u0026gt; while index \u0026lt; len(lt): ... print(lt[index]) ... index += 1 ... 1 -5 3 2 4 10 100 如上篇文章提到的，字典的items()也會產生可迭代的物件，\n我們可以按順序用name和ingre(ingredient)來對應它。\n1 2 3 4 5 6 \u0026gt;\u0026gt;\u0026gt; shrimp = {\u0026#39;炸鳳尾蝦\u0026#39;:[\u0026#39;蝦子\u0026#39;,\u0026#39;核果\u0026#39;,\u0026#39;油\u0026#39;],\u0026#39;雲龍炸蝦\u0026#39;:[\u0026#39;蝦子\u0026#39;,\u0026#39;核果\u0026#39;,\u0026#39;油\u0026#39;,\u0026#39;豆皮\u0026#39;,\u0026#39;醬汁\u0026#39;]} \u0026gt;\u0026gt;\u0026gt; for name, ingre in shrimp.items(): ... print(name, ingre) ... 炸鳳尾蝦 [\u0026#39;蝦子\u0026#39;, \u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;] 雲龍炸蝦 [\u0026#39;蝦子\u0026#39;, \u0026#39;核果\u0026#39;, \u0026#39;油\u0026#39;, \u0026#39;豆皮\u0026#39;, \u0026#39;醬汁\u0026#39;] 另一方面，break, continue, else在for迴圏的用法和while迴圏的用法是一模一樣的，\n讀者可以自行嘗試寫寫看。\n提到了for，就不得不提另一個很常用的產生迭代的方式：range()。\nrange()的用法跟slice很像，都是(start, stop, step)；\n這當中，start不給的話會從0開始，step預設則是1，\n而stop由於不像list有確定的長度，所以是必需要給出的數字。\n(同樣請留意stop的位置是不算在內的，這點跟slice相同 )\n例如：\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; range(7) # 只給一個數字的話是表示stop，所以相當於range(0, 7) range(0, 7) \u0026gt;\u0026gt;\u0026gt; list(range(7)) # 可以將其產生為list [0, 1, 2, 3, 4, 5, 6] \u0026gt;\u0026gt;\u0026gt; list(range(1, 5)) [1, 2, 3, 4] \u0026gt;\u0026gt;\u0026gt; list(range(1, 5, -1)) # step走-1並沒有符合的數字 [] \u0026gt;\u0026gt;\u0026gt; list(range(1, 5, 2)) [1, 3] \u0026gt;\u0026gt;\u0026gt; list(range(10, -88, -10)) [10, 0, -10, -20, -30, -40, -50, -60, -70, -80] 因此，如果我們想要從list中從頭每次相隔2，印出其值，就可以寫成這樣：\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; lt = [1, -5, 3, 2, 4, 10, 100] \u0026gt;\u0026gt;\u0026gt; for i in range(0, len(lt), 2): # 從index 0開始，每次間隔2，直到len(lt)-1 (因為stop的位置不算) ... print(lt[i]) ... 1 3 4 100 辛苦啦！今天的內容也相當的多，\n同樣請練習一下，可別偷懶呦！\n那就明天見啦！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-22T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-7-programming-structure-flow-control-1/","title":"從零開始學Python (7) — 程式結構與流程語法：如果對手太弱太簡單，那不是很爽嗎?(上)"},{"content":"Day 06 串列(list)、Tuple(元組)、字典(dict)、集合(set)：我的字典裡沒有放棄，因為我還沒有寫進去(下) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10240088/\n接下來我們要介紹另外兩個資料型態：字典(dict)與集合(set)。\n首先是字典：\n字典跟串列有點類似的部分，\n但是它的表示方式是一個鍵(key)對一個值(value)，\n就好像函式一樣，一個字典裡面不會出現重覆的key，\n但有可能不同key對應的value剛好一樣；\n這樣一來，我們就可以用key去查找其對應的value。\n需要注意的是，串列是有一個固定的順序排列的，\n但字典並不會有固定排序(也就是說一般我們不在意排的順序)。\nkey和value可以是各種不同的型態如str, int, float, bool等等，\n但是key必須要是hashable的資料型態(像list就不是hashable)，\nvalue做為被對應的對象，則沒有這種限制。\n字典的建立方式，可以用dict()方法，也可以用大括號{}，\n當中每個key和value的對應使用冒號:來分隔，\n而每組key:value之間，使用逗號來分開。\n同時，要取得某個key對應的value值，\n就像list是用index來取得對應位置的値，字典則使用dict[key]來取得。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \u0026gt;\u0026gt;\u0026gt; dic0 = dict() \u0026gt;\u0026gt;\u0026gt; dic0 {} \u0026gt;\u0026gt;\u0026gt; dic = {\u0026#39;xd\u0026#39;: 1, \u0026#39;放棄\u0026#39;: False, [1,5,9]: 3} # list是unhashable，不能作為key Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; TypeError: unhashable type: \u0026#39;list\u0026#39; \u0026gt;\u0026gt;\u0026gt; dic = {\u0026#39;xd\u0026#39;: 1, \u0026#39;放棄\u0026#39;: False, 3.33: 3} # 這樣就沒問題啦！ \u0026gt;\u0026gt;\u0026gt; dic {\u0026#39;xd\u0026#39;: 1, \u0026#39;放棄\u0026#39;: False, 3.33: 3} \u0026gt;\u0026gt;\u0026gt; dic[\u0026#39;XD\u0026#39;] # 在程式語言的世界裡，通常大小寫是當作不一樣的呦！ Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; KeyError: \u0026#39;XD\u0026#39; \u0026gt;\u0026gt;\u0026gt; dic[\u0026#39;xd\u0026#39;] # 取值 1 \u0026gt;\u0026gt;\u0026gt; dic[\u0026#39;放棄\u0026#39;] False \u0026gt;\u0026gt;\u0026gt; dic[3.33] 3 上篇提到list()可以拿來轉換，dict()也有類似的特異功能，\n只要內容是剛好每一組都是兩項的就可以了！\n(串列/tuple/剛好兩個字元的字串…)\n我們看一下範例：\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; lol = [(\u0026#39;易大師\u0026#39;,\u0026#39;我的劍，就是你的劍。\u0026#39;),(\u0026#39;犽宿\u0026#39;,\u0026#39;死亡如風，常伴吾身。\u0026#39;),(\u0026#39;阿祈爾\u0026#39;,\u0026#39;蘇瑞瑪！你的王已經歸來了！\u0026#39;)] \u0026gt;\u0026gt;\u0026gt; diclol = dict(lol) \u0026gt;\u0026gt;\u0026gt; diclol {\u0026#39;易大師\u0026#39;: \u0026#39;我的劍，就是你的劍。\u0026#39;, \u0026#39;犽宿\u0026#39;: \u0026#39;死亡如風，常伴吾身。\u0026#39;, \u0026#39;阿祈爾\u0026#39;: \u0026#39;蘇瑞瑪！你的王已經歸來了！\u0026#39;} \u0026gt;\u0026gt;\u0026gt; tul = ([\u0026#39;a\u0026#39;,\u0026#39;b\u0026#39;],[\u0026#39;c\u0026#39;,\u0026#39;d\u0026#39;],[\u0026#39;e\u0026#39;,\u0026#39;f\u0026#39;],[\u0026#39;g\u0026#39;,\u0026#39;h\u0026#39;]) # 裡外兩層不管是tuple或list都沒有問題！ \u0026gt;\u0026gt;\u0026gt; dictul = dict(tul) \u0026gt;\u0026gt;\u0026gt; dictul {\u0026#39;a\u0026#39;: \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;: \u0026#39;d\u0026#39;, \u0026#39;e\u0026#39;: \u0026#39;f\u0026#39;, \u0026#39;g\u0026#39;: \u0026#39;h\u0026#39;} \u0026gt;\u0026gt;\u0026gt; chs = [\u0026#39;ab\u0026#39;,\u0026#39;cd\u0026#39;,\u0026#39;13\u0026#39;] # 兩個字元的字串會被拆開用(但超過兩個字元就不支援了) \u0026gt;\u0026gt;\u0026gt; dicchs = dict(chs) \u0026gt;\u0026gt;\u0026gt; dicchs {\u0026#39;a\u0026#39;: \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;: \u0026#39;d\u0026#39;, \u0026#39;1\u0026#39;: \u0026#39;3\u0026#39;} 我們可以使用類似list的方式來對字典插入或修改某個key對應的value值，\n如果該key已經存在在字典，則對應的value會被覆蓋，否則就產生一個新的對應。\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; diclol[\u0026#39;伊澤瑞爾\u0026#39;] = \u0026#39;是時候展現真正的技術了！\u0026#39; # 新增 \u0026gt;\u0026gt;\u0026gt; diclol {\u0026#39;易大師\u0026#39;: \u0026#39;我的劍，就是你的劍。\u0026#39;, \u0026#39;犽宿\u0026#39;: \u0026#39;死亡如風，常伴吾身。\u0026#39;, \u0026#39;阿祈爾\u0026#39;: \u0026#39;蘇瑞瑪！你的王已經歸來了！\u0026#39;, \u0026#39;伊澤瑞爾\u0026#39;: \u0026#39;是時候展現真正的技術了！\u0026#39;} \u0026gt;\u0026gt;\u0026gt; dicchs {\u0026#39;a\u0026#39;: \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;: \u0026#39;d\u0026#39;, \u0026#39;1\u0026#39;: \u0026#39;3\u0026#39;} \u0026gt;\u0026gt;\u0026gt; dicchs[\u0026#39;a\u0026#39;]=\u0026#39;XD\u0026#39; # 修改 \u0026gt;\u0026gt;\u0026gt; dicchs {\u0026#39;a\u0026#39;: \u0026#39;XD\u0026#39;, \u0026#39;c\u0026#39;: \u0026#39;d\u0026#39;, \u0026#39;1\u0026#39;: \u0026#39;3\u0026#39;} 接下來是一些常見的dict操作方法，同樣請多加練習，\n讀者可能會發現很多會跟list的操作概念相同，所以可以的話，請對照著比較一下。\ndict1.update(dict2) -\u0026gt; 將dict2的內容複製後放到dict1(** key重覆時，dict2的value優先**)。\ndel dict1[‘key’] -\u0026gt; 將dict1的**’key’:’value’** 的對應從dict1中刪去**。\ndict1.clear() -\u0026gt; ** 清空整個dict1的對應(也可以用dict1 = dict())。\n‘XXX’ in dict1 -\u0026gt; 檢查dict1是否有’XXX’這個key。\ndict1.keys() -\u0026gt; 給出整個dict1的** 所有key**(如果需要用list的形式表達，請用** list()將其框住)。\ndict1.values() -\u0026gt; 同上，但給出的是所有value**。\ndict1.items() -\u0026gt; 給出一個一個的** key:value對應**(每對都以tuple形式給出)。\ndict2 = dict1.copy() -\u0026gt; 複製一份dict1的內容，生成一個dict2的字典。\n(註：如果是用dict2 = dict1，只會讓兩者共用 一個字典，修改會動到同一個呦！)\n我們來看一下範例：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 \u0026gt;\u0026gt;\u0026gt; diclol[\u0026#39;國動\u0026#39;] = \u0026#39;社 社 社社社 社社 社會搖\u0026#39; \u0026gt;\u0026gt;\u0026gt; diclol # 前面建立的字典 {\u0026#39;易大師\u0026#39;: \u0026#39;我的劍，就是你的劍。\u0026#39;, \u0026#39;犽宿\u0026#39;: \u0026#39;死亡如風，常伴吾身。\u0026#39;, \u0026#39;阿祈爾\u0026#39;: \u0026#39;蘇瑞瑪！你的王已經歸來了！\u0026#39;, \u0026#39;伊澤瑞爾\u0026#39;: \u0026#39;是時候展現真正的技術了！\u0026#39;, \u0026#39;國動\u0026#39;: \u0026#39;社 社 社社社 社社 社會搖\u0026#39;} \u0026gt;\u0026gt;\u0026gt; diclol[\u0026#39;國動\u0026#39;] = \u0026#39;社 社 社社社 社社 社會搖\u0026#39; \u0026gt;\u0026gt;\u0026gt; diclolfame = {\u0026#39;國動\u0026#39;:\u0026#39;還敢下來阿冰鳥!\u0026#39;, \u0026#39;統神\u0026#39;:\u0026#39;他的手怎麼可以穿過我的叭叭啊！\u0026#39;} \u0026gt;\u0026gt;\u0026gt; diclol.update(diclolfame) # 合併過去，重覆的會被覆蓋 \u0026gt;\u0026gt;\u0026gt; diclol {\u0026#39;易大師\u0026#39;: \u0026#39;我的劍，就是你的劍。\u0026#39;, \u0026#39;犽宿\u0026#39;: \u0026#39;死亡如風，常伴吾身。\u0026#39;, \u0026#39;阿祈爾\u0026#39;: \u0026#39;蘇瑞瑪！你的王已經歸來了！\u0026#39;, \u0026#39;伊澤瑞爾\u0026#39;: \u0026#39;是時候展現真正的技術了！\u0026#39;, \u0026#39;國動\u0026#39;: \u0026#39;還敢下來阿冰鳥!\u0026#39;, \u0026#39;統神\u0026#39;: \u0026#39;他的手怎麼可以穿 過我的叭叭啊！\u0026#39;} \u0026gt;\u0026gt;\u0026gt; del diclol[\u0026#39;統神\u0026#39;] # 刪除對應的鍵值對 \u0026gt;\u0026gt;\u0026gt; diclol {\u0026#39;易大師\u0026#39;: \u0026#39;我的劍，就是你的劍。\u0026#39;, \u0026#39;犽宿\u0026#39;: \u0026#39;死亡如風，常伴吾身。\u0026#39;, \u0026#39;阿祈爾\u0026#39;: \u0026#39;蘇瑞瑪！你的王已經歸來了！\u0026#39;, \u0026#39;伊澤瑞爾\u0026#39;: \u0026#39;是時候展現真正的技術了！\u0026#39;, \u0026#39;國動\u0026#39;: \u0026#39;還敢下來阿冰鳥!\u0026#39;} \u0026gt;\u0026gt;\u0026gt; dicchs = {\u0026#39;a\u0026#39;: 123, \u0026#39;c\u0026#39;: 428, \u0026#39;1\u0026#39;: \u0026#39;3\u0026#39;, \u0026#39;eee\u0026#39;: 11} \u0026gt;\u0026gt;\u0026gt; dicchs {\u0026#39;a\u0026#39;: 123, \u0026#39;c\u0026#39;: 428, \u0026#39;1\u0026#39;: \u0026#39;3\u0026#39;, \u0026#39;eee\u0026#39;: 11} \u0026gt;\u0026gt;\u0026gt; dicchs.clear() # 清空字典 \u0026gt;\u0026gt;\u0026gt; dicchs {} \u0026gt;\u0026gt;\u0026gt; \u0026gt;\u0026gt;\u0026gt; \u0026#39;統神\u0026#39; in diclolfame True \u0026gt;\u0026gt;\u0026gt; \u0026#39;統神\u0026#39; in diclol # 我們剛剛刪除了，所以\u0026#39;統神\u0026#39;不會在diclol裡 False \u0026gt;\u0026gt;\u0026gt; dicn = {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3, \u0026#39;d\u0026#39;: 4} \u0026gt;\u0026gt;\u0026gt; dicn {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3, \u0026#39;d\u0026#39;: 4} \u0026gt;\u0026gt;\u0026gt; dicn.keys() # 取得key dict_keys([\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;]) \u0026gt;\u0026gt;\u0026gt; list(dicn.keys()) # 如果需要list型式的話就外面加一層list() [\u0026#39;a\u0026#39;, \u0026#39;b\u0026#39;, \u0026#39;c\u0026#39;, \u0026#39;d\u0026#39;] \u0026gt;\u0026gt;\u0026gt; dicn.values() dict_values([1, 2, 3, 4]) \u0026gt;\u0026gt;\u0026gt; dicn.items() dict_items([(\u0026#39;a\u0026#39;, 1), (\u0026#39;b\u0026#39;, 2), (\u0026#39;c\u0026#39;, 3), (\u0026#39;d\u0026#39;, 4)]) \u0026gt;\u0026gt;\u0026gt; dico = dicn # 直接用等號，在字典相當於貼標籤在同一個身上 \u0026gt;\u0026gt;\u0026gt; dico[\u0026#39;a\u0026#39;] = \u0026#39;XD\u0026#39; \u0026gt;\u0026gt;\u0026gt; dico {\u0026#39;a\u0026#39;: \u0026#39;XD\u0026#39;, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3, \u0026#39;d\u0026#39;: 4} \u0026gt;\u0026gt;\u0026gt; dicn # 結果原先的也一起被改到了！ {\u0026#39;a\u0026#39;: \u0026#39;XD\u0026#39;, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3, \u0026#39;d\u0026#39;: 4} \u0026gt;\u0026gt;\u0026gt; dico = dicn.copy() # 使用copy()來處理 \u0026gt;\u0026gt;\u0026gt; dico[\u0026#39;a\u0026#39;] = 1 \u0026gt;\u0026gt;\u0026gt; dico {\u0026#39;a\u0026#39;: 1, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3, \u0026#39;d\u0026#39;: 4} \u0026gt;\u0026gt;\u0026gt; dicn # 這樣dico和dicn就是兩個不一樣的字典囉！ {\u0026#39;a\u0026#39;: \u0026#39;XD\u0026#39;, \u0026#39;b\u0026#39;: 2, \u0026#39;c\u0026#39;: 3, \u0026#39;d\u0026#39;: 4} (註：在其他語言裡，通常把key:value對應的資料結構稱作hash或hash map)\n接下來要講的是集合(set)。\n集合不像字典，它的本身只有key而已，\n每個key都必須不重覆 (就像數學學到的那樣)\n要建立的方式，可以使用set()，或者使用大括號{}，\n當中每個key之間使用逗號連接，要增加key則使用add()。\n(同樣用大括號，集合沒有value對應的部份)\n集合本身也是不講求排列順序的，這點和字典一樣。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 \u0026gt;\u0026gt;\u0026gt; st = set() \u0026gt;\u0026gt; st # 因為空的大括號代表字典，所以要產生一個空集合只能使用set()，不能用{} set() \u0026gt;\u0026gt;\u0026gt; st.add(3) \u0026gt;\u0026gt;\u0026gt; st {3} \u0026gt;\u0026gt;\u0026gt; st.add(3) # 重覆的增加相同的key不會對set造成影響 \u0026gt;\u0026gt;\u0026gt; st {3} \u0026gt;\u0026gt;\u0026gt; st.add(\u0026#39;XD\u0026#39;) # set中的key不一定要有相同的資料型態 \u0026gt;\u0026gt;\u0026gt; st {\u0026#39;XD\u0026#39;, 3} \u0026gt;\u0026gt;\u0026gt; set(\u0026#39;XDDDD\u0026#39;) # 可以拿單一字串放入，會被拆開來看待(重覆的被刪去) {\u0026#39;D\u0026#39;, \u0026#39;X\u0026#39;} \u0026gt;\u0026gt;\u0026gt; set([\u0026#39;XDDDD\u0026#39;,\u0026#39;XD\u0026#39;,\u0026#39;XD\u0026#39;,\u0026#39;XDDD\u0026#39;]) # list則會以元素為單位，此外，留意它並沒有順序。 {\u0026#39;XD\u0026#39;, \u0026#39;XDDDD\u0026#39;, \u0026#39;XDDD\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1 = {\u0026#39;A\u0026#39;, \u0026#39;C\u0026#39;, \u0026#39;E\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st2 = {\u0026#39;B\u0026#39;, \u0026#39;C\u0026#39;, \u0026#39;A\u0026#39;, \u0026#39;D\u0026#39;} \u0026gt;\u0026gt;\u0026gt; \u0026#39;A\u0026#39; in st1 # 集合同樣也可以用in來檢查是否存在key True \u0026gt;\u0026gt;\u0026gt; \u0026#39;e\u0026#39; in st1 False 既然是集合，可想而知就會有許多跟數學上集合對應的操作，\n我們就直接來看範例：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 \u0026gt;\u0026gt;\u0026gt; st1 \u0026amp; st2 # \u0026#39;\u0026amp;\u0026#39;(念作and, 代表\u0026#39;且\u0026#39;，也就是兩者皆有才算有)和intersection都是取交集 {\u0026#39;C\u0026#39;, \u0026#39;A\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1.intersection(st2) {\u0026#39;C\u0026#39;, \u0026#39;A\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1 | st2 # \u0026#39;|\u0026#39;(念作or, 代表\u0026#39;或\u0026#39;，也就是兩者之一有就可以了)和union都是取聯集 {\u0026#39;A\u0026#39;, \u0026#39;D\u0026#39;, \u0026#39;E\u0026#39;, \u0026#39;C\u0026#39;, \u0026#39;B\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1.union(st2) {\u0026#39;A\u0026#39;, \u0026#39;D\u0026#39;, \u0026#39;E\u0026#39;, \u0026#39;C\u0026#39;, \u0026#39;B\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1 - st2 # \u0026#39;-\u0026#39;和difference都是取差集，也就是取前者有，後者沒有 {\u0026#39;E\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st2 - st1 {\u0026#39;D\u0026#39;, \u0026#39;B\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1.difference(st2) {\u0026#39;E\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1 ^ st2 # \u0026#39;^\u0026#39;(念作exclusive or, 代表\u0026#39;互斥或\u0026#39;，也就是只能其中一個有，另一個沒有的)和symmetric_difference(太長啦！不用記XD)都是取互斥或 {\u0026#39;B\u0026#39;, \u0026#39;D\u0026#39;, \u0026#39;E\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1.symmetric_difference(st2) {\u0026#39;B\u0026#39;, \u0026#39;D\u0026#39;, \u0026#39;E\u0026#39;} \u0026gt;\u0026gt;\u0026gt; st1 \u0026lt;= st2 # \u0026#39;\u0026lt;=\u0026#39;和issubset代表檢查前者是否是後者的子集 False \u0026gt;\u0026gt;\u0026gt; st2 \u0026lt;= st1 False \u0026gt;\u0026gt;\u0026gt; st1.issubset(st2) False 其他還有一些，但有需要用到時再查對應功能即可。\n最後一樣來做個練習吧！ 眾所周知，李嚴和劉昴星曾經比過炸龍蝦，\n請建立一個字典名為shrimp，當中\n請使用兩者的作品的名字做為key ，\n將其做的炸蝦所使用到的材料/內容列表list做為value ，\n還未做完成的部分不算 。請參考原本對於兩人作品的描述如下： 李嚴的作品：「我的料理是炸鳳尾蝦 ，就是蝦子 裹碎核果去炸的，將核果 搗碎後裹在蝦肉上，油 炸成為金黃色，不但要考慮核果跟蝦肉的比例，高低油溫的調節也需要高度的技術跟經驗的。鮮脆可口的核果外衣，經油炸之後，其香味立即倍增，堪稱人間第一美味，搭配特製醬汁來食用，味道更是妙不可言。跟醬汁巧妙的組合，這是這個炸蝦的精華所在。那個醬汁，那要先將蘋果，洋蔥等切成末之後，跟各種調味料以絕妙的比例互相調合。那個醬汁，再給我一分鐘我一定能完成的!」\n劉昴星的作品：「炸的香酥的核果 外衣，蝦肉(蝦子 )的甘甜，與順滑可口的醬汁 搭配起來，真是太棒了……我在蝦肉和外衣之間，夾了豆皮 封住醬汁，如此一來，就算在油鍋裡炸，醬汁也一定不會流出來。裹著一層豆皮雲的龍蝦，名字叫做小當家特製雲龍炸蝦 ！」\n承1，請將兩人的材料從shrimp中取出，\n分別放入兩個set中，並命名為’lee’跟’liu’。\n請利用set的操作，回答以下問題：\n劉昴星的作品中比李嚴的作品多用了什麼材料？\n李嚴的作品中比劉昴星的作品多用了什麼材料？\n兩人的作品都有用到什麼材料？\n假定今天李嚴能做完醬汁的話，請將新增的材料(蘋果、洋蔥)以及內容(醬汁)，\n加到lee這個set中，\n接著請指出現在李嚴的作品中比劉昴星的作品多用了什麼材料？\n並請將材料和內容更新回shrimp這個字典中的對應作品。\n已知有一個列表lt = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]，\n請利用slice及其他方法來達成以下要求：\na. 請生成一個lt1，其內容為lt的所有奇數\nb. 請生成一個lt2，其內容為lt的所有偶數\nc. 請將lt2的所有元素依序附加到lt1上\nd. 請刪除lt1當中index 7和index 1的數\ne. 請將lt1進行排序\n辛苦了，這兩篇對於初學者來說應該很長，\n但很基本，請多加嘗試練習，\n後續使用到對應用法如果還是忘記的話，\n可以再回頭看著對照。\n那就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-6-list-tuple-dict-set-2/","title":"從零開始學Python (6) — 串列(list)、Tuple(元組)、字典(dict)、集合(set)：我的字典裡沒有放棄，因為我還沒有寫進去(下)"},{"content":"Day 05 串列(list)、Tuple(元組)、字典(dict)、集合(set)：我的字典裡沒有放棄，因為我還沒有寫進去(上) 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。https://ithelp.ithome.com.tw/articles/10239342/\n先來解答昨天的問題吧！ 1. 答案如下：\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; chs=\u0026#39;abcdefghijklmnopqrstuvwxyz\u0026#39; \u0026gt;\u0026gt;\u0026gt; print(chs[::-2]) # 從尾往頭，step為-2，不要忘記沒有寫的還是要補冒號！ zxvtrpnljhfdb \u0026gt;\u0026gt;\u0026gt; print(chs[16]+chs[14]*2+\u0026#39; \u0026#39;+\u0026#39;有種果汁真好喝~\u0026#39;) # 對吧XD qoo 有種果汁真好喝~ 2. 已經知道bin的前兩位表示是0b，那麼利用slice取第二位以後即可。\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; bin(36) \u0026#39;0b100100\u0026#39; \u0026gt;\u0026gt;\u0026gt; print(bin(36)[2:]) 100100 3. 只要按照順序就可以接起來囉！\n1 2 3 \u0026gt;\u0026gt;\u0026gt; a, b, c = \u0026#39;pen\u0026#39;, \u0026#39;apple\u0026#39;, \u0026#39;pine\u0026#39; \u0026gt;\u0026gt;\u0026gt; print(a+c+b*2+a) # PPAP penpineappleapplepen 接下來，讓我們介紹幾個比較進階的資料型態：\n串列(list)、tuple(元組)、字典(dict)、集合(set)\n首先是串列和tuple，\n由於Tuple的稱呼(元組)翻法實在相對比較少人愛用，\n因此習慣上tuple就直接叫做tuple就可以了。\n你說到底要念做「禿波」(too-pull)還是「他波」(tub-pull)呢？\nGuido自己講說他都隨便念沒有關系，\n不過我是都念咖死口啦！\n我們先講串列的部分，\n所謂的串列，就是一連串的元素(單一的資料)放進一個表裡面的東西。\n這個表可以沒有任何元素，也可以有很多個元素，其數量是可以被改變的。\n要做出一個串列，可以使用list()，或者一組中括號[]來表示，\n當然，也可以在當中用逗號分隔每個元素並在開始時直接置入：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 \u0026gt;\u0026gt;\u0026gt; lt = [] \u0026gt;\u0026gt;\u0026gt; llt = list() \u0026gt;\u0026gt;\u0026gt; lt, llt # 兩個都是空的串列 ([], []) \u0026gt;\u0026gt;\u0026gt; lt = [\u0026#39;my\u0026#39;, \u0026#39;dict\u0026#39;, \u0026#39;doesn\\\u0026#39;t\u0026#39;, \u0026#39;have\u0026#39;, \u0026#39;the\u0026#39;, \u0026#39;word\u0026#39;, \u0026#39;giving\u0026#39;, \u0026#39;up.\u0026#39;, 9527, True] # 一個串列裡的元素彼此不一定非得要是同樣的資料型態，這點跟C++/Java等不同 \u0026gt;\u0026gt;\u0026gt; print(lt) [\u0026#39;my\u0026#39;, \u0026#39;dict\u0026#39;, \u0026#34;doesn\u0026#39;t\u0026#34;, \u0026#39;have\u0026#39;, \u0026#39;the\u0026#39;, \u0026#39;word\u0026#39;, \u0026#39;giving\u0026#39;, \u0026#39;up.\u0026#39;, 9527, True] \u0026gt;\u0026gt;\u0026gt; \u0026#39; \u0026#39;.join(lt) # 上一篇提到說使用join可以將串列連接，但必須要全都是字串 Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; TypeError: sequence item 8: expected str instance, int found \u0026gt;\u0026gt;\u0026gt; \u0026#39; \u0026#39;.join(lt[:-2]) # 串列同樣可以用slice，用法和字串的邏輯一樣，所以倒數2個被去掉後就能正常join了！ \u0026#34;my dict doesn\u0026#39;t have the word giving up.\u0026#34; \u0026gt;\u0026gt;\u0026gt; (\u0026#39; \u0026#39;.join(lt[:-2])).split()　# 使用split可以將字串拆成串列 [\u0026#39;my\u0026#39;, \u0026#39;dict\u0026#39;, \u0026#34;doesn\u0026#39;t\u0026#34;, \u0026#39;have\u0026#39;, \u0026#39;the\u0026#39;, \u0026#39;word\u0026#39;, \u0026#39;giving\u0026#39;, \u0026#39;up.\u0026#39;] \u0026gt;\u0026gt;\u0026gt; list(\u0026#39;apple pen\u0026#39;) # 直接對字串使用list()方法，會將每個字元拆開來變成一個串列 [\u0026#39;a\u0026#39;, \u0026#39;p\u0026#39;, \u0026#39;p\u0026#39;, \u0026#39;l\u0026#39;, \u0026#39;e\u0026#39;, \u0026#39; \u0026#39;, \u0026#39;p\u0026#39;, \u0026#39;e\u0026#39;, \u0026#39;n\u0026#39;] \u0026gt;\u0026gt;\u0026gt; lt[3] # 單獨給定索引值(index)，就會得到對應位置的資料(別忘了是從0開始呦！) \u0026#39;have\u0026#39; \u0026gt;\u0026gt;\u0026gt; lt[-2] 9527 \u0026gt;\u0026gt;\u0026gt; lt[0] \u0026#39;my\u0026#39; \u0026gt;\u0026gt;\u0026gt; lt[100] # 但是不論用正數表達或負數表達，超過的部分都不會繞一圈回來，而是會顯示錯誤 Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; IndexError: list index out of range \u0026gt;\u0026gt;\u0026gt; lt[::-1] # 同樣的，利用slice可以輕鬆做到將整個list反轉過來 [True, 9527, \u0026#39;up.\u0026#39;, \u0026#39;giving\u0026#39;, \u0026#39;word\u0026#39;, \u0026#39;the\u0026#39;, \u0026#39;have\u0026#39;, \u0026#34;doesn\u0026#39;t\u0026#34;, \u0026#39;dict\u0026#39;, \u0026#39;my\u0026#39;] \u0026gt;\u0026gt;\u0026gt; lt[2] = \u0026#39;0800\u0026#39; # 指定index可以對list的對應的元素做更動 \u0026gt;\u0026gt;\u0026gt; lt [\u0026#39;my\u0026#39;, \u0026#39;dict\u0026#39;, \u0026#39;0800\u0026#39;, \u0026#39;have\u0026#39;, \u0026#39;the\u0026#39;, \u0026#39;word\u0026#39;, \u0026#39;giving\u0026#39;, \u0026#39;up.\u0026#39;, 9527, True] 接著，留意到串列中的元素既然沒有限定，那麼元素可以是另一個串列嗎?\n當然可以！\n1 2 3 4 5 6 7 8 9 10 11 \u0026gt;\u0026gt;\u0026gt; lt3 = [[1, 2], [3, 4, 5], [6, 7, 9, 0], \u0026#39;X\u0026#39;, \u0026#39;D\u0026#39;] # 有些元素是串列，有些只是單一的字元 \u0026gt;\u0026gt;\u0026gt; lt3[0], lt3[1], lt3[2][3], lt3[3], lt3[4] # 第二層的話就加括號和對應的index ([1, 2], [3, 4, 5], 0, \u0026#39;X\u0026#39;, \u0026#39;D\u0026#39;) \u0026gt;\u0026gt;\u0026gt; lt3[4][1] # 當取得的是str時，按照規則取字串的字元，超出的話會顯示錯誤 Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; IndexError: string index out of range \u0026gt;\u0026gt;\u0026gt; lt3[0][2] # 當取得的是list時，超出取得的list的範圍的index也會顯示錯誤 Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; IndexError: list index out of range 接下來是串列常見的一些操作，請務必多加熟練，\n我們先簡單敘述一下常見的操作：(以下請將lt開頭的東西當成是list)\nlt.append(element) -\u0026gt; 將element接到lt的** 尾巴**。\nlt.extend(lt2) -\u0026gt; 將lt2的所有elements** 依序接到lt的尾巴** (相當於** lt+=lt2**)。\nlt.insert(index, element) -\u0026gt; 在index處插入element\n(原本該位置及其後的元素都往後挪 )。\ndel lt[index] -\u0026gt; 將index處的element** 刪去**，其他element** 往前遞補**。\nlt.remove(name) -\u0026gt; 從lt中** 搜尋符合name的element**，將其** 刪去**，\n其他element往前遞補 。\nlt.index(name) -\u0026gt; 從lt中** 搜尋符合name的element**，並將其** 索引值回報**。\nxx in lt -\u0026gt; 如果** xx這個元素在lt中的話則為True，否則為Flase。\nlt.count(name) -\u0026gt; 計算name在lt 出現的次數**。\nlt.join(sep) -\u0026gt; 使用join內的間隔** sep**，將lt的元素** 一個一個接起來**。\nlt2 = sorted(lt) -\u0026gt; 將lt排序過後(按元素的順序** 由小到大**)，存放到lt2。\n(lt不會受改變)\nlt.sort() -\u0026gt; 將lt於原地排序。\nlen(lt) -\u0026gt; 取得lt的** 元素個數**。(想成取長度也行)\nlt2 = lt.copy()\nlt3 = list(lt) -\u0026gt; lt2~lt4都代表** 複製lt的所有元素並 產生新的list**。\nlt4 = lt[:]\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \u0026gt;\u0026gt;\u0026gt; lt = [1, 3, 5] \u0026gt;\u0026gt;\u0026gt; lt.append(15) # 附加一個元素到尾端 \u0026gt;\u0026gt;\u0026gt; lt [1, 3, 5, 15] \u0026gt;\u0026gt;\u0026gt; lt.extend([3,9, -1]) # 附加一組元素到尾端(如果這個用append的話，會將[3, 9, -1]直接當成單一元素放入) \u0026gt;\u0026gt;\u0026gt; lt [1, 3, 5, 15, 3, 9, -1] \u0026gt;\u0026gt;\u0026gt; lt.insert(3, 2) # 先選位置，再給插入值 \u0026gt;\u0026gt;\u0026gt; lt [1, 3, 5, 2, 15, 3, 9, -1] \u0026gt;\u0026gt;\u0026gt; del lt[1] # 砍掉index位置的値，後面遞補 \u0026gt;\u0026gt;\u0026gt; lt [1, 5, 2, 15, 3, 9, -1] \u0026gt;\u0026gt;\u0026gt; lt.remove(3) # 砍掉對應的值的元素(找不到的話會出錯) \u0026gt;\u0026gt;\u0026gt; lt [1, 5, 2, 15, 9, -1] \u0026gt;\u0026gt;\u0026gt; lt.index(9) # 找對應的値在串列的索引值 4 \u0026gt;\u0026gt;\u0026gt; 9 in lt # 在喊在 True \u0026gt;\u0026gt;\u0026gt; 3 in lt # 不在喊不在 False \u0026gt;\u0026gt;\u0026gt; lt.extend([-3, -1, 2, -1, -2]) \u0026gt;\u0026gt;\u0026gt; lt [1, 5, 2, 15, 9, -1, -3, -1, 2, -1, -2] \u0026gt;\u0026gt;\u0026gt; lt.count(-1) # 計算元素出現次數 3 \u0026gt;\u0026gt;\u0026gt; lt.count(-2) 1 \u0026gt;\u0026gt;\u0026gt; lt.count(2) 2 \u0026gt;\u0026gt;\u0026gt; lt.sort() # 原地排序 \u0026gt;\u0026gt;\u0026gt; lt [-3, -2, -1, -1, -1, 1, 2, 2, 5, 9, 15] \u0026gt;\u0026gt;\u0026gt; lt.extend([3, 9, -2]) \u0026gt;\u0026gt;\u0026gt; lt2 = sorted(lt) # 另行排序，排完放到lt2，lt不會被改變 \u0026gt;\u0026gt;\u0026gt; lt2 [-3, -2, -2, -1, -1, -1, 1, 2, 2, 3, 5, 9, 9, 15] \u0026gt;\u0026gt;\u0026gt; len(lt2) # 取長 14 蠻多的對吧？\n盡量不要死記硬背，嘗試多練習不同的操作變化看看呦！\n接下來介紹tuple(元組)，\ntuple可以說是固定版的串列，\n一旦決定以後，它本身裡面的元素就無法被單獨修改了！\n要使用tuple，我們會用小括號()，當中是空白或用逗號分隔的元素。\n要留意的是，無論除非你直接將變數名稱整個指定成別的內容，\n否則是無法用像tpl[1] = ‘edit’這樣的東西去修改的！\n除此以外，我們也可以用多重指派的方式，\n來讓每個元素接取到tuple或list的元素。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \u0026gt;\u0026gt;\u0026gt; tpl = (1, 3, \u0026#39;XD\u0026#39;, \u0026#39;9\u0026#39;, 123) \u0026gt;\u0026gt;\u0026gt; tpl (1, 3, \u0026#39;XD\u0026#39;, \u0026#39;9\u0026#39;, 123) \u0026gt;\u0026gt;\u0026gt; tpl[1] 3 \u0026gt;\u0026gt;\u0026gt; tpl[1] = 100 Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; TypeError: \u0026#39;tuple\u0026#39; object does not support item assignment \u0026gt;\u0026gt;\u0026gt; a, b, c, d, e = tpl # 對應五個元素，左右兩邊互相對到即可，這種方式也稱為tuple開箱(unpacking) \u0026gt;\u0026gt;\u0026gt; a 1 \u0026gt;\u0026gt;\u0026gt; b 3 \u0026gt;\u0026gt;\u0026gt; c \u0026#39;XD\u0026#39; \u0026gt;\u0026gt;\u0026gt; d \u0026#39;9\u0026#39; \u0026gt;\u0026gt;\u0026gt; e 123 由於不能修改的特性，前面提到list的append/extend等方法tuple都沒有；\n但是tuple有幾點好處：\n占用空間較少 tuple的元素不會不小心被動到\n除此之外，tuple後續也可以做為字典的輸入使用，\n這點下一篇文章會提到。\n其他還有一些特別的特性，之後有機會再提吧! 我們在下半段將介紹另外兩種資料型態：字典(dict)及集合(set)。\n那就明天見啦！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-20T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-5-list-tuple-dict-set/","title":"從零開始學Python (5) — 串列(list)、Tuple(元組)、字典(dict)、集合(set)：我的字典裡沒有放棄，因為我還沒有寫進去(上)"},{"content":"Day 04 型態轉換及字串基礎：叫你印出來不是叫你開印表機阿！ 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10238980\n註：本文同步刊載在Medium，若習慣Medium的話亦可去那邊看呦！\n我們先來解答一下昨天的問題。 讀者的變數名稱可以自己定義，只要答案正確即可。\n(但定義的時候，盡量是能夠表達出這個變數是用來做什麼的會比較好)\n第一題的內容很簡單，就是把東西放進去計算，然後print出來。\n範例解如下：\n1 2 3 4 5 6 \u0026gt;\u0026gt;\u0026gt; pi=3.14 \u0026gt;\u0026gt;\u0026gt; r=7.77 \u0026gt;\u0026gt;\u0026gt; print(2*pi*r) # 周長 48.7956 \u0026gt;\u0026gt;\u0026gt; print(pi*r**2) # 面積 189.57090599999998 請留意到，運算子之間有優先合併順序，這個可以Google一下會有詳盡的列表，\n但簡單來說，就像小時候老師教先乘除後加減一樣，\n以pi*r**2 這個式子來說，”**”這個運算子會先被優先納入計算，\n所以r平方會先算完，再和左邊的pi相乘。\n第二題呢？其實也只是加起來而已。\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; pi=3.14 \u0026gt;\u0026gt;\u0026gt; r1=7.77 \u0026gt;\u0026gt;\u0026gt; r2=5.3 \u0026gt;\u0026gt;\u0026gt; r3=2.5 \u0026gt;\u0026gt;\u0026gt; print(2*pi*(r1+r2+r3)) 97.7796 \u0026gt;\u0026gt;\u0026gt; print(pi*(r1**2+r2** 2+r3**2)) 297.398506 很簡單吧！\n接下來第三天的部分，我們要來談一下型態轉換及一些字串的操作。\n我們昨天已經提到有一些基本常見的型態：\nbool, int, float, str，\n也許讀者有想到一個問題：\n兩個不一樣的型態是怎麼互相轉換的呢？\n比方說我們先前在除法的時候，兩個int相除，\n是會產生float的(如果不使用整數除法)，\n這個就是Python在這當中自動進行了型態轉換的部分。\n有些時候，型態轉換則需要我們自己來操作，\n比如int和float的互轉，只需要使用int()或float()即可。\n我們來看一下int和float轉換的範例：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 \u0026gt;\u0026gt;\u0026gt; float(1) # 從沒有小數點的int變成帶小數點的float 1.0 \u0026gt;\u0026gt;\u0026gt; int(1.0) # 很直觀XD 1 \u0026gt;\u0026gt;\u0026gt; int(1.6) # 咦? 不是2嗎？ 1 \u0026gt;\u0026gt;\u0026gt; int(1.4) 1 \u0026gt;\u0026gt;\u0026gt; int(-1.1) -1 \u0026gt;\u0026gt;\u0026gt; int(-2.1) # 所以是無條件捨棄 -2 \u0026gt;\u0026gt;\u0026gt; 1.5+1　# float和int相加 2.5 \u0026gt;\u0026gt;\u0026gt; 1+3.0 # 順序不影響 4.0 int轉換成float以後，就是多加.0在後面就對了！\nfloat轉換成int的話，則是將小數點後面的東西全數捨棄 。\n四則運算的話，int和float相遇最後結果會變成float，以求保留較多的資料。\n那bool和int之間的關係呢？0會被當成偽，1會被當成真，\n但是其他的數字(0以外的所有數字)也會被當成真呦！\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; bool(0) False \u0026gt;\u0026gt;\u0026gt; bool(1) True \u0026gt;\u0026gt;\u0026gt; bool(3) True \u0026gt;\u0026gt;\u0026gt; bool(-2) True \u0026gt;\u0026gt;\u0026gt; int(True) 1 \u0026gt;\u0026gt;\u0026gt; int(False) 0 int還有其他變化，\n可以將其轉換成用二進位/八進位/十六進位來表達。\n所謂的二進位就是每個位數只有0或1兩種數字，\n超過就進一位。\n舉例來說，十進位的7等於二進位的111，\n因為111等於1 * 2² + 1 * 2¹ + 1 * 2⁰ = 4+2+1=7\n(看不懂這段的，可以搜尋一下二進位，這邊不再贅述)\n我們一般用X進位來表達數字時，稱這個X為「基數」。\n在Python中如果數字用10以外的基數來表達時，\n會額外做顯示上的處理：\n二進位 -\u0026gt; 0b或0B (b代表binary)\n八進位 -\u0026gt; 0o或0O (o代表octal)\n十六進位 -\u0026gt; 0x或0X (x代表hexadecimal)\n舉例來說：\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; 0b10 # 2 2 \u0026gt;\u0026gt;\u0026gt; 0b111 # 4+2+1=7 7 \u0026gt;\u0026gt;\u0026gt; 0o11 # 8+1=9 9 \u0026gt;\u0026gt;\u0026gt; 0x1F # 16+15=31 (A~F分別代表16進位的10~15) 31 上面這些有點枯燥我明白，但請記下來，有些東西將來會用上的XD\n再來談談字串(str)吧！\n在Python中，一個字串的資料，是用兩個單引號或兩個雙引號括起來的，\n當int, float, bool等型態要轉為str時，\nPython只有做一件事情：把它們加進引號中。(真是偷懶XD)\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; str(9) \u0026#39;9\u0026#39; \u0026gt;\u0026gt;\u0026gt; str(97.1) \u0026#39;97.1\u0026#39; \u0026gt;\u0026gt;\u0026gt; str(True) \u0026#39;True\u0026#39; \u0026gt;\u0026gt;\u0026gt; str(0o11) # 以其他基數表達的int，仍會先轉回10進位再處理 \u0026#39;9\u0026#39; 那反方向呢？\n1 2 3 4 5 6 7 8 9 10 \u0026gt;\u0026gt;\u0026gt; int(\u0026#39;9\u0026#39;) 9 \u0026gt;\u0026gt;\u0026gt; int(\u0026#39;9.1\u0026#39;) # python會跳出錯誤說：你騙我，它不是int！ Traceback (most recent call last): File \u0026#34;\u0026lt;stdin\u0026gt;\u0026#34;, line 1, in \u0026lt;module\u0026gt; ValueError: invalid literal for int() with base 10: \u0026#39;9.1\u0026#39; \u0026gt;\u0026gt;\u0026gt; float(\u0026#39;9.1\u0026#39;) # 這樣總符合了吧！ 9.1 \u0026gt;\u0026gt;\u0026gt; bool(\u0026#39;3\u0026#39;)　# 因為是0以外的東西，所以會是True True 講到這裡，讀者可能會有疑問：\n「前面講過print可以將東西印出來，\n那我如果要印出字串，但裡面含單引號或雙引號呢？」\n問的好！\n由於有些特殊字元如單引號，雙引號等會有被拿去用的困擾，\n所以當遇到會有特殊含義的字元，\n或者要將特定字元轉換用途時，我們可以使用一個反斜線()，\n將原先的含義給轉換。\n這邊請留意一下，在一般大多數的程式語言來說，\n印出(print)通常代表把一些內容，輸出到螢幕上，\n可能是程式的命令提示字元，或者別的東西，\n但不是印表機！！！\n請不要問為什麼我家沒有印表機筆者卻要你印出東西來的問題XD\n比如我們想印出’We will rock you!’ (連同單引號)，\n那麼，我們可以這樣子：\n1 2 \u0026gt;\u0026gt;\u0026gt; print(\u0026#39;\\\u0026#39;We will rock you!\\\u0026#39;\u0026#39;) # 外層的單引號仍然是用來表達字串的開頭跟結尾，但內層的單引號被轉義回一般無特殊含義的單引號 \u0026#39;We will rock you!\u0026#39; 其他還有一些常用的轉義字元，但最常用的就是”\\n”了，\n可以用來做換行的效果！\n舉例來說：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; print(\u0026#39;天青色等煙雨 而我在等你\\n炊煙裊裊升起 隔江千萬里\u0026#39;) 天青色等煙雨 而我在等你 炊煙裊裊升起 隔江千萬里 你要多換幾行？那就多打幾個\\n吧！\n想同時印出多個字串的話，可以用逗號來連接，Python會幫忙在中間加空格。\n1 2 3 \u0026gt;\u0026gt;\u0026gt; print(\u0026#39;I\\n\u0026#39;,\u0026#39;feel\u0026#39;,\u0026#39;good\u0026#39;) # 即便換行，feel前面還是有一格空格 I feel good 再來談談Python中字串的一些常見的操作：\n+結合、*複製、[]取字元、[start:end:step]切片、len()取長、split()分割、join()結合\n以下是範例：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 \u0026gt;\u0026gt;\u0026gt; \u0026#39;a\u0026#39;+\u0026#39;b\u0026#39;+\u0026#39;c\u0026#39; # 相加就是串在一起就對了！ \u0026#39;abc\u0026#39; \u0026gt;\u0026gt;\u0026gt; \u0026#39;apple\u0026#39;*2 # 乘上的正整數相當於重複的次數 \u0026#39;appleapple\u0026#39; \u0026gt;\u0026gt;\u0026gt; a = \u0026#39;apple\u0026#39; \u0026gt;\u0026gt;\u0026gt; a[3] # 取第3位(從0起算) \u0026#39;l\u0026#39; \u0026gt;\u0026gt;\u0026gt; a[0:4:1] # 切片slice: 從0開始，到4結束，每次跳1單位 \u0026#39;appl\u0026#39; \u0026gt;\u0026gt;\u0026gt; a[0:4:2] # 切片slice: 從0開始，到4結束，每次跳2單位 \u0026#39;ap\u0026#39; \u0026gt;\u0026gt;\u0026gt; len(a) # 取長度 5 \u0026gt;\u0026gt;\u0026gt; len(a[0:4:1]) # 剛剛切出的長度是4 4 \u0026gt;\u0026gt;\u0026gt; b = \u0026#39;An apple a day, keeps the doctor away.\u0026#39; \u0026gt;\u0026gt;\u0026gt; b.split() # 用括號內的字串來分割，預設是空白字元(換行/空格/位移tab) [\u0026#39;An\u0026#39;, \u0026#39;apple\u0026#39;, \u0026#39;a\u0026#39;, \u0026#39;day,\u0026#39;, \u0026#39;keeps\u0026#39;, \u0026#39;the\u0026#39;, \u0026#39;doctor\u0026#39;, \u0026#39;away.\u0026#39;] \u0026gt;\u0026gt;\u0026gt; b.split(\u0026#39;,\u0026#39;) # 用逗號來分割(留意用來分割的東西會不見) [\u0026#39;An apple a day\u0026#39;, \u0026#39; keeps the doctor away.\u0026#39;] \u0026gt;\u0026gt;\u0026gt; b.split(\u0026#39;.\u0026#39;) # 因為.的右邊沒東西，所以會多一個空字串 [\u0026#39;An apple a day, keeps the doctor away\u0026#39;, \u0026#39;\u0026#39;] \u0026gt;\u0026gt;\u0026gt; c = b.split() \u0026gt;\u0026gt;\u0026gt; c [\u0026#39;An\u0026#39;, \u0026#39;apple\u0026#39;, \u0026#39;a\u0026#39;, \u0026#39;day,\u0026#39;, \u0026#39;keeps\u0026#39;, \u0026#39;the\u0026#39;, \u0026#39;doctor\u0026#39;, \u0026#39;away.\u0026#39;] \u0026gt;\u0026gt;\u0026gt; d = \u0026#39;\\n\u0026#39;.join(c) # \u0026#39;字串\u0026#39;.join(要被接起來的串列) \u0026gt;\u0026gt;\u0026gt; d \u0026#39;An\\napple\\na\\nday,\\nkeeps\\nthe\\ndoctor\\naway.\u0026#39; \u0026gt;\u0026gt;\u0026gt; print(d) # 印出來的時候就知道\\n是拿來換行了！ An apple a day, keeps the doctor away. 程式碼內的註解應該足夠清楚，除了有幾點需要補充說明。\n首先留意到a[3]，在單獨中括號加上單一數字時，\n代表從頭開始數到索引值(index)為3的地方，取出那個字元。\n注意歐！這個算法中是從0開始數的！\n也就是’apple’中的’a’是a[0]，請讀者務必記得從0開始！\n就算沒有在異世界生活也一樣XD\n接著看到**[start:end:step]的切片部分，\n它代表著我們可以用定好的規則來取出字串的片段。\n其中：\nstart表示開始的位置；\nend表示結束的位置，但是不含end這個位置；\nstep代表每次移動多少單位。\n比方說剛剛的a[0:4:1]，\n就是從0開始，到4結束，每次移動1單位，但因為不包含4，\n所以只會取到’appl’。\n在step為正的情況下，start不寫的話，預設代表從0開始，\n而step不寫的話，預設代表每次移動1單位；\n所以a[0:4:1]也可以寫成a[:4:1]或者a[:4]** ，讀者可以嘗試看看。\n同理，end不寫的話代表預設到結束(包含尾端)，\n所以如**a[1:]就會是’pple’**。\n此外，slice還有特異功能：當step是負數 的時候，\n前面不寫則代表預設從字串尾往字串頭走，\n所以如a[::-1]會是’elppa’，相當於將a反轉 ；\n而a[4:1:-1]則是’elp’ 。\n而當start或end是負數的時候，\nPython會將負數視作從尾往頭起算，如-1代表倒數第1個字元。\n例如a[-2:0:-1]會是’lpp’ 。\n最後留意到split()作用過後，\n會產生一個用中括號框起來，及逗號分隔的東西，\n我們將其稱為list(串列，或稱列表) ，在接下來的文章中我們會介紹到它，\n現在只需要知道，它就是一連串列出來的東西即可：\nsplit會按照分割的字串將目標字串給切分開成列表；\njoin則會使用給定的字串將一個列表的所有東西按順序連接起來。\n好的，最後我們來做個練習吧！ 給定字串chs = ‘abcdefghijklmnopqrstuvwxyz’，請印出：\n1.1. 從z起算往回頭走，每次step為-2的字串\n1.2. 將索引值為16的字元，加上(索引值為14的字元重復2次)，\n並用一個空格將前者和字串’有種果汁真好喝~’連接起來。 已知bin()的方法可以將一個int值用二進位表示並轉為字串，\n請嘗試給出36的二進位字串，但須去除’0b’的部分。 給定a, b, c = ‘pen’, ‘apple’, ‘pine’ ，\n(註：沒錯，你可以在一行同時生成多個變數，使用逗號隔開即可)\n請用a, b, c組合出’penpineappleapplepen’。 那就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-18T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-4-type-conversion-and-string-basic/","title":"從零開始學Python (4) — 型態轉換及字串基礎：叫你印出來不是叫你開印表機阿！"},{"content":"Day 01 緒論：寫在前面 為了方便大家閱讀，這個系列也存成Medium的list囉！https://desolve.medium.com/list/python-6f7985967b68\n註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。https://ithelp.ithome.com.tw/articles/10237408\n一年又過去啦！\n不曉得各位過得如何呢？\n在寫了從LeetCode學演算法系列文章後，\nMedium上，\n陸續也寫滿了百篇(現在是105篇)的LeetCode系列的教學文章，\n也有出了兩門從LeetCode學演算法的教學課程。\n但想轉職的學生依舊很多，卻常常不得其門而入，\n從發問的同學來看，主要還是因為轉職時找不到一個好的入門途徑。\n對一個想入門程式語言的人來說，也許會有很多弄不懂的問題：\n我想學寫前端網頁，那我該從JavaScript開始嗎？\nCSS要不要會？要不要先懂一些HTML5的語法？\n我該用Vue, React, Angular還是什麼東西？\n看了一個範例寫購物車，要碰到資料庫，我是不是該碰一些後端？\n我想學後端，我該學什麼？\nSQL?NoSQL?該用什麼程式？該安裝什麼套件？\n我要做一個作品，呈現是不是要弄一個網頁？那我是不是該學一些前端？\n我想寫手機程式，該選Android還是iOS的系統？\nApp層更下面的東西，我該知道嗎？要知道的多深？\n我想寫一般程式，我該選Java/C++/C#/Python中的哪一個？\n(僅舉例，沒被列到的別生氣XD)\n怎樣應用？怎樣寫出視窗程式？\n最後，為什麼每個上來都寫Hello World?\n入門者最大的問題，就是選項很多，\n但他/她不知道這些選項代表什麼，也不知道選擇以後，\n該從哪邊開始起步。\n這就是這個系列文章的目的，\n筆者會嘗試以自己的觀點來表述，\n在眾多程式語言中，Python這個選項的優缺點，\n帶你學過一遍Python初學所需知道的東西並練習，\n並且指一條Python可能的發展路線給你。\n由於一個人的思慮總有疏漏的時候，\n若文章中有不理解或者筆誤/不小心講錯的時候，\n歡迎告訴筆者，筆者會再進行修改。\n除此以外，以下是本系列文章的閱讀重點：\n1. 只會列一到兩個選項給你\n做一件事情的方法有很多種，學Python也是，\n如果每個可能性都要列出來，對讀者來說太累了(對筆者也是XD)，\n在一般狀況下，筆者會只列一至兩種操作/撰寫方式，\n其他的變化或者選項，有興趣的讀者可以再自行深入研究。\n2. 盡量用容易解釋的方式，整組打包\n每一個函式都有它的用法，\n筆者會盡量將其變得較易理解，\n在避免太多定義的狀態下，\n將能組在一起的函式形成一起的範例來解釋。\n3. 練習範例及題目\n文章中的練習範例，請務必自行打一遍並執行成功才算數(不是複製貼上！)\n如果有練習的題目的話，會在隔天給出解答，\n但希望讀者當天就嘗試自己做出來，再來看答案呦！\n4. 前導知識及配備\n雖然本文不預設讀者有學過程式語言，\n但仍希望讀者能擁有一台可以上網的電腦，\n以及起碼會下載軟體並安裝。\n(恩…就是Next-\u0026gt;Next-\u0026gt;……-\u0026gt;Finished/Done)\n5. Python適合的讀者\n如果你想當前端工程師 -\u0026gt;\nPython+Flask可以做，但主流是JavaScript的系列框架，\n請找Web前端相關語言的學習資源，本篇不適合你 。\n如果你想當後端工程師 -\u0026gt;\nPython+MongoDB或其他資料庫(NoSQL/SQL的都有)可以做 ，\n其他常見的如Java, Golang, Node.js等也都可以做，\n所以你可以先看你將來想要找哪些公司的職缺，\n再看看他們要的是否為Python後端。\n如果你想當韌體工程師 -\u0026gt;\n通常這都是C/C++的工作，本篇不適合你 。\n如果你想當App工程師 -\u0026gt;\n通常這都是Kotlin/Swift的工作，最多加上比較偷懶的React Native，\n或是用Unity3D之類的軟體撰寫，本篇不適合你 。\n如果你想當網頁爬蟲工程師 -\u0026gt;\nPython有相關的好用的模組 可以使用，\n你可以從本篇開始入門基礎，同時可能需要會一些HTML的基礎。\n(通常這會跟大數據/輿情分析有關)\n如果你想當AI/機器學習/深度學習工程師 -\u0026gt;\n雖然也有Java/C++的框架，\n但目前最主流的就是Python 了！\n你可以從本篇開始入門基礎，\n接下來學習Tensorflow/Keras/PyTorch等深度學習框架，\n本篇後面有篇幅的話，會再推薦一些適合的學習資源。\n歡迎來到Python的世界，\n接下來一個月就讓我們一起加油吧！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-17T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-1-preface/","title":"從零開始學Python (1) — 緒論：寫在前面"},{"content":"Day 02 語言起源及安裝使用：偉大的東西常常是無心插柳柳橙汁 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。https://ithelp.ithome.com.tw/articles/10237509\n第二天的文章，我們來介紹Python的起源和基礎安裝流程。\nPython的創始人是吉多·范羅蘇姆(Guido van Rossum)，\n在1989年聖誕節打發時間開發出來的。\n後續經過一連串的發展，有興趣的可以Google一下，\n我們只需要知道幾個最簡單的點：\n主流版本有分Python 2.x和Python 3.x，\n但Python 2.x系列目前已經不再維護，\n所以如果沒有特別需求(例如使用先前別人用Python 2寫的程式)，\n直接選擇最新的Python 3.x版本 即可。 Python的開發演進標準是根據PEP系列 (Python Enhancement Proposals)\n一般而言，透過開發社群討論提議後，\n納入PEP的S系列(Standards Track PEP)匯總，\n最後再進行必要的修改/做出新功能並演進更新。\n這中間有可能出現吵不出個結果的狀況，\n這時候需要BDFL(仁慈的獨裁者) 來做最後裁決，\n首位的仁慈的獨裁者即為Guido本人。\n可想而知，這個壓力有點太大了XD\n畢竟每次跳出來喊:\n「你們不要打了，要打去練舞室打！」\n也是很累的，還要擔心自己撞上砲口QQ\n所以Guido後來在2018講說不幹啦！ 接著我們來介紹一下怎麼安裝Python吧！ 如果是Windows作業系統的話，請至\nhttps://www.python.org/downloads/windows/\n以撰寫當日來說最後一次的release為3.8.5\n(Latest Python 3 Release — Python 3.8.5)\n接著往下拉到底端，如果你的電腦是64位元就請選”x86–64\u0026quot;的選項，\n否則請選”x86\u0026quot;的選項。\n如果讀者使用Mac或Linux，就請依照各自對應的版本做下載。\n下載完成後打開進行安裝，將”Add Python 3.8 to PATH”打勾後，\n選擇”Customize installation”。\n-\u0026gt; Next\n-\u0026gt; 將Install for all users及Precompile standard library都打勾，\n並將安裝路徑選擇一個你記得住的名字。\n(一般會選在Program Files底下，讀者自訂也可)\n-\u0026gt; 允許UAC給權限後，進行安裝\n安裝完畢後(Close結束)，\n我們應該要能在命令提示字元下找到Python，先打開命令提示字元：\n(Win Key + R -\u0026gt; 輸入cmd後Enter)\n(或者按開始，在搜尋列打cmd後按Enter鍵)\n好啦，我知道這條很長XD\n在命令提示字元打入”python -V”，正常的話，\n應該會顯示我們剛剛安裝的版本。(3.8.5)\n在這個模式下輸入”python”，\n可以進入直譯器(REPL Read-Eval-Print-Loop，或稱Python Shell)，\n輸入指令或運算會在運算的同時將結果輸出到螢幕上。\n(但是一旦離開，所有記錄就會消失了)\n輸入”python [檔名]”的話，會嘗試將該檔案做為python的程式碼執行，\n通常我們會將副檔名命名為.py\n假設我們在現在這個資料夾有一個fromzero.py如下：\n那麼，在命令提示字元輸入”python fromzero.py”，\n其結果如下：\n讀者可以照著試打出來，中文想印出的部分可自己亂打沒關係XD\n簡單解釋這當中發生什麼事情：\n執行一段程式的順序是由第一行一路往下走到最後一行，\n所以我們會先看到有一個a，一個b，分別被設定為10跟5，\n然後被print(a * b)印出來，\n也就是先將結果算出來，再輸出到螢幕上，於是得到50。\n第四行則是將前面一串字印出來以後，串接上a和b相乘的結果，\nstr()的目的，則是將a和b算出來的數字轉換成字串，\n這樣才能和前面的字串進行串接。\n初學者可能還不太懂，沒關係，我們後面會再慢慢解釋XD\n那就明天見啦！\n註：\n對一般人來說，可能命令提示字元並不是很友善，\n因此，建議讀者可以另行安裝IDE來處理，\n能夠得到更多方便的提示，操作也比較容易上手。\n常見的如PyCharm 或VSCode 均可，安裝部分Google一下應該不會太困難，\n這邊就不再贅述了。\n或者，讀者想直接在線上作業也可以，\n可以使用如 https://repl.it/ 之類的平台即可。\n後續的文章中，將預設使用者是使用自己的文字編輯器，\n如Notepad++/VSCode/PyCharm/Vim/Atom/ …等，\n把程式碼完成後，使用**”python xxx.py”** 的形式來執行。\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-17T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-2-origin-and-install/","title":"從零開始學Python (2) — 語言起源及安裝使用：偉大的東西常常是無心插柳柳橙汁"},{"content":"Day 03 變數、型態、運算子：你的除法不是你的除法 註：本篇文章同步刊載於iT邦幫忙，為鐵人賽之系列文章。\nhttps://ithelp.ithome.com.tw/articles/10237877\n從前從前，有個聰明的小男孩叫高斯，\n有天老師有事情要忙，出了一道算術題給全班慢慢寫：\n1+2+3+…+100 = ?\n誰知道高斯馬上就將這個題目用簡單的乘法給迅速算出來了，\n答案是(1+100) * 100 / 2 = 5050。\n*這告訴我們，做人不要太白目XD *\n以下我們使用上一篇文章的直譯器，來試看看Python的計算。\n在Python中的四則運算，基本上跟我們所認知的四則運算大部分相同，\n那麼，要在Python中計算上面的式子的話，也許你會想這樣寫：\n1 2 \u0026gt;\u0026gt;\u0026gt; (1+100) * 100 / 2 5050.0 咦？為什麼多一個小數點呢？\n事實上，Python中在計算加減乘除的時候，只有除法比較特別，\n當使用單斜線的除法時，計算結果會預設帶有小數點，\n這種「型態」和原先的整數不同，\n在Python中整數稱作int，而帶小數點的數字則稱為float。\n所以說，你的除法不是你的除法XD\n要取得相除的整數，請使用雙斜線：\n1 2 \u0026gt;\u0026gt;\u0026gt; (1+100) * 100 // 2 5050 留意如果這當中你使用了帶小數點的數字，即便使用雙斜線，仍然會得到float的結果。\n1 2 \u0026gt;\u0026gt;\u0026gt; (1+100) * 100 // 2.0 5050.0 (註：和Python不同，其他如Java/C++等語言，單斜線反而是取整數)\n一般Python常見運算方式，除了加減乘除和整數除法外，\n還有幾個常見的如**% (取餘數運算子，如5 % 2會得到1)**\n\\ (取冪次，如a\\b會得到a的b次方)\n以及其他很多有的沒有的東西，以後我們有機會用到的時候再行介紹XD\n剛剛提到了型態(type) ，在Python中每個資料都有其型態，\n用來表明它是什麼種類的東西，我們可以使用type() 的方法，\n簡單列出一些常見的型態：\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026gt;\u0026gt;\u0026gt; type(10.0) # 浮點數 \u0026lt;class ‘float’\u0026gt; \u0026gt;\u0026gt;\u0026gt; type(10) # 整數 \u0026lt;class ‘int’\u0026gt; \u0026gt;\u0026gt;\u0026gt; type(‘25’) # 字串，可以用兩個單引號或兩個雙引號括住 \u0026lt;class ‘str’\u0026gt; \u0026gt;\u0026gt;\u0026gt; type(True) # 布林值，只分成True(真)或False(偽) \u0026lt;class ‘bool’\u0026gt; \u0026gt;\u0026gt;\u0026gt; type(False) \u0026lt;class ‘bool’\u0026gt; \u0026gt;\u0026gt;\u0026gt; type(None) # None，代表什麼都沒有，通常發生在東西不存在時 \u0026lt;class ‘NoneType’\u0026gt; 回到我們的1加到100，\n上面的公式我們知道，在國小的時候通常被稱為梯形公式 ：\n(上底 + 下底) * 高 / 2\n在1加到100中，由於下底和高相同，所以才會都是100，\n那麼今天如果連續要算不同的梯形面積呢？每次重複寫好像有一點點麻煩，\n這時候我們可以先將這三個不同的東西寫成「變數」。\n所謂的變數就是會變的數(廢話)\n讀者可以想像成一個箱子，這個箱子將用來存放資料，\n並且為了知道我們在找哪個箱子，我們會為它貼上標籤並取名。\n舉例來說：\n1 2 3 4 5 \u0026gt;\u0026gt;\u0026gt; top = 1 \u0026gt;\u0026gt;\u0026gt; bottom = 100 \u0026gt;\u0026gt;\u0026gt; h = 100 \u0026gt;\u0026gt;\u0026gt; (top + bottom) * h // 2 5050 「變數名稱 = 值」的意義是將等號右邊的值(也可以是運算式)，\n存放到貼有等號左邊標籤的箱子中。它並不是我們數學中的兩者相等\n讀者可以嘗試，如果這時候將bottom改變的話，計算結果應該也會改變：\n1 2 3 4 5 6 7 8 \u0026gt;\u0026gt;\u0026gt; bottom = 200 \u0026gt;\u0026gt;\u0026gt; (top + bottom) * h // 2 10050 \u0026gt;\u0026gt;\u0026gt; type(bottom) # type()的方法也可以拿來看變數 \u0026lt;class ‘int’\u0026gt; \u0026gt;\u0026gt;\u0026gt; bottom = “XD” # 改動bottom的值並不會受限於原先的型態 (對了，井字號是註解，包含它及其身後的整行都不會被執行到喲！) \u0026gt;\u0026gt;\u0026gt; print(bottom) XD 請讀者留意，前面執行bottom=100時，\n我們生成了一個名為bottom的變數，\n後面執行到bottom=200時，則是生成另一個變數，\n再將bottom這個標籤貼到上面去。\n在Python中更動內容這件事情相對來說十分自由，\n即便現在bottom是整數，\n你仍然可以透過前面的賦值來改變成別的東西。(因為這是新的東西)\n(如上面最後就改成字串了)\n同時，當我們將兩個變數用等號相連時，\n只相當於將標籤名稱貼到同一個箱子上。\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 \u0026gt;\u0026gt;\u0026gt; a = 10 \u0026gt;\u0026gt;\u0026gt; b = a \u0026gt;\u0026gt;\u0026gt; b # 直譯器中直接打變數名字，可以將其輸出到螢幕上 10 \u0026gt;\u0026gt;\u0026gt; id(a) # id()方法，可以將一個變數所存放在的記憶體(就是存箱子的空間)位置印出來 140733754578720 \u0026gt;\u0026gt;\u0026gt; id(b) # 看吧！兩個一模一樣 140733754578720 \u0026gt;\u0026gt;\u0026gt; a = 123 # a的標籤從…..720的位置拔掉，貼到存放有123的新箱子 \u0026gt;\u0026gt;\u0026gt; id(a) 140733754582496 \u0026gt;\u0026gt;\u0026gt; id(b) # b的標籤還在原地 140733754578720 \u0026gt;\u0026gt;\u0026gt; b # b不改變 10 講到這邊好像有點多吼？會不會難消化呢？\n再加一點點就為今天做個收尾吧！\n我們剛剛學到了變數、型態、及運算子，\n假設你是班代，要幫系上同學訂書收錢，跟小明收300，跟小華收500……\n這時候，你希望有一個變數能夠儲存收款的狀況。\n對於第一筆款項也許你會這樣寫：\n1 2 3 4 \u0026gt;\u0026gt;\u0026gt; total = 0 \u0026gt;\u0026gt;\u0026gt; total = total + 300 \u0026gt;\u0026gt;\u0026gt; total 300 但太麻煩了，你要寫兩次total，有沒有簡單一點的寫法呢？\n有的，那就是「+=」。a += b的效果，等同於a = a + b。\n1 2 3 \u0026gt;\u0026gt;\u0026gt; total += 500 \u0026gt;\u0026gt;\u0026gt; total 800 假定你收完了錢，廠商跟你說我們這次沒有特價了，\n所以書錢變為兩倍(WTF?)：\n1 2 3 \u0026gt;\u0026gt;\u0026gt; total *= 2 # 總共應收款項，只好再去討錢囉！a *= b 和 a = a * b相同 \u0026gt;\u0026gt;\u0026gt; total 1600 上面這類型的運算子稱之為指定運算子 ，\n可以達到省略多寫一次第一個變數的目的，看起來比較簡潔。\n+=, -=, \\*=, /=, //= …… 讀者可以自行運用。\n特別強調，a = a + b的意義，\n是將a + b算完後，置入到貼有a標籤的箱子，\n請不要將其當成一般數學意義的等號來看待。\n我們來做個練習吧！ 假設圓周率為3.14，一個圓的半徑是7.77\n請用上面的所學及print()方法，\n在直譯器中印出該圓的周長和面積。\n(註：print()內可以放計算式子呦！)\n承1，如果有另外兩個圓的半徑分別是5.3和2.5，\n請計算出這三個圓的周長的和和總面積。\n那就明天見囉！\n工商時間： 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n","date":"2020-09-17T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/python-zero.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-python-from-zero-3-variable-type-operator/","title":"從零開始學Python (3) — 變數、型態、運算子：你的除法不是你的除法"},{"content":"0437. Path Sum III (Medium)\n寫在前面 容筆者工商一下， 「從Leetcode學演算法｜進階篇」及 加贈的**「從Leetcode學演算法｜面試篇」已經全數上傳完囉！**\n目前只剩下給讀者的進階篇+面試篇(3150) 和全套同捆優惠(3990) 了QQ\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\n內容介紹：\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\nQuestion You are given a binary tree in which each node contains an integer value.\nFind the number of paths that sum to a given value.\nThe path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).\nThe tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.\nExample:\n1 root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 1 2 3 4 5 6 7 10 / \\ 5 -3 / \\ \\ 3 2 11 / \\ \\ 3 -2 1 1 Return 3. The paths that sum to 8 are: 1 2 3 1. 5 -\u0026gt; 3 2. 5 -\u0026gt; 2 -\u0026gt; 1 3. -3 -\u0026gt; 11 分析/解題 給定一個二元樹，當中每個節點均含一個整數，\n找出所有可以加總等於目標總和的路徑數量。\n一個路徑不需要從根節點開始，也不必一定要到葉節點結束，\n但是路徑只能往下走(也就是說只能從父節點往子節點走)；\n另外，這棵樹最多只會有1000個節點，\n且其值均在-1000000~1000000之間。\n這一題是一整組Path Sum系列題的第三題。\n由於題目提示節點數不會超過1000個，\n所以基本是無法超過各程式的Call Stack限制，可以放心使用遞迴。\n那麼，我們看看另一個重點：\n路徑只能往下走，會有什麼特點呢？\n舉例來說，以上面的二元樹，當我們走到某個節點2時，\n所有終點是2的路徑有以下三種：\n10 -\u0026gt; 5 -\u0026gt; 2 5 -\u0026gt; 2\n2\n再往下走到1的時候，路徑有以下四種：\n10 -\u0026gt; 5 -\u0026gt; 2 -\u0026gt; 1\n5 -\u0026gt; 2 -\u0026gt; 1\n2 -\u0026gt; 1\n1\n我們可以發現，走到1的路徑和到底有沒有符合target的解這件事情，\n可以透過兩點知道：\n從root起算走到現在這個節點的總和是否和target相等 從root起算走到現在這個節點的總和-target是否在過往出現過 第2點比較抽象，我們稍微舉一下簡單的例子：\n假設我們要找的目標是8的話，\n那麼直接看我們當然知道是5-\u0026gt;2-\u0026gt;1，\n但如果不能回頭重算的話，要怎麼辦呢？\n我們可以得到5-\u0026gt;2-\u0026gt;1的路徑，\n其實相當於從根節點10走到1的路徑和，減去節點10。\n換句話說，如果我們每走到一個節點，都將路徑和記錄下來，\n那麼我們就可以用前面過往的路徑和，\n來表達出所有達到現在這個節點的路徑和。\n例如：\n1其實等於10 -\u0026gt; 5 -\u0026gt; 2 -\u0026gt; 1 去掉** 10 -\u0026gt; 5 -\u0026gt; 2\n2** -\u0026gt; 1等於** 10 -\u0026gt; 5 -\u0026gt; 2** -\u0026gt; 1去掉** 10 -\u0026gt; 5\n5 -\u0026gt; 2** -\u0026gt; 1等於** 10 -\u0026gt; 5 -\u0026gt; 2** -\u0026gt; 1去掉** 10**\n這樣足夠清楚了嗎XD？\n因此，我們要做的事情有：\n0. 建一個dictionary或hashmap，\n當中key/value分別代表路徑和/路徑和出現的次數。\n同時，將(0, 1)置入字典當中。(這裡稱之為preSum)\n(方便我們在剛好等於根節點到當前節點總長時計算)\n呼叫遞迴DFS函式並回傳其結果。\n在DFS函式中，遍歷整棵二元樹：\n2.0. 檢查節點是否存在，不存在則回傳0\n2.1. 將當前的節點值加上根節點的値，做為現在的總和(currSum)\n2.2. 初始化res，其值為currSum-target在preSum中出現的次數\n2.3. 分別向左右節點遞迴呼叫DFS函式，將得到的結果加到res\n2.4. 由於這條路徑只能一路向下，\n所以要回到上一層前，\n需將剛剛加過的1次記錄從preSum中扣掉(backtracking)。\n2.5. 回傳res\n依此，寫成程式碼如下：\nJava Java的部分preSum使用HashMap，留意先進行一次put，\n再放入helper函式中做DFS；\nhelper函式中的部分，由於HashMap本身找不存在的值會出錯，\n別忘了使用getOrDefault來給定預設值(當然，你要用containsKey也行)。\n在遞迴取得左右兩邊節點的符合路徑數加總後，\n別忘記回傳前要將加上去的刪掉，才符合回溯法的要件。\nPython Python的部分大同小異，\n不同的是我們可以用defaultdict來將預設值當作0，\n從Python的寫法中應該可以更清晰看見回溯法的樣貌。\n(先加1後減1)\n這邊的helper直接寫成子函式，\n所以我們就不需使用self.xxx的形式來呼叫了。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N*樹深)，每個節點均需要經過一次，\n每個節點最多可以成立d個preSum值，\nd為樹的深度，以平衡樹來說則是log(N))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-09-14T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-105-tree-18-dfs-15-backtracking-7/","title":"從LeetCode學演算法 -  105 Tree (18) / DFS (15) / Backtracking (7)"},{"content":"0113. Path Sum II (Medium)\n寫在前面 容筆者工商一下， 「從Leetcode學演算法｜進階篇」及 加贈的**「從Leetcode學演算法｜面試篇」已經全數上傳完囉！**\n目前只剩下給讀者的進階篇+面試篇(3150) 和全套同捆優惠(3990) 了QQ\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\n內容介紹：\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\nQuestion Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum.\nNote: A leaf is a node with no children.\nExample:\nGiven the below binary tree and sum = 22,\n1 2 3 4 5 6 7 5 / \\ 4 8 / / \\ 11 13 4 / \\ / \\ 7 2 5 1 Return:\n1 2 3 4 [ [5,4,11,2], [5,8,4,5] ] 分析/解題\n給定一個二元樹以及目標的和(sum)，找出所有根節點到葉的路徑，這些路徑各自的和要等於給定的和。\n這一題是一整組Path Sum系列題的第二題。\n由於要找出路徑，所以我們需要一組記錄當前路徑current的位置的list。\n同時，要能夠判定是否要確認這條路徑OK的狀態，\n只取決於現在是否走到葉節點(因為題目要求)；\n並且走到葉節點時，左右也都沒有節點了，就無法往下走。\n我們可以用一個result的list記錄最終處理完的結果，\n接著使用DFS 的方式往下找。\n那麼自然我們每走過一個節點，\n就要將sum減去現在root的値，同時記錄到current上。\n接下來要往下走還是檢查呢？\n當然就是看左右節點是否為NIL且sum和root的値是否相等啦！\n如果是的話，可以將result加上走到現在的路徑；\n如果不是的話，則以DFS往左和往右走(不要忘記去檢查NIL的狀況)。\n這整段走完要回到上一層的時候，表示已經處理完了，\n不要忘記我們先前將這層root的値放進了current裡面，\n所以我們應該要將其移除。(** Backtracking**的部分)\n依此，寫成程式碼如下：\nJava Java的部分我們可以使用同名但不同參數長度的函式，\n直接利用開頭檢查root，\n來順便處理後續帶入root.left/root.right所需要的檢查。\nBacktracking的部分，\ncurrentResult先加上root.val後，後續再進行remove即可；\n而留意由於我們不斷地在變換currentResult，\n不要忘記要將其複製一份以加到result裡面，而非直接用加的。\n(使用new LinkedList(currentResult) )\nPython 同理，Python的部分一樣需要複製，\n我們可以寫成curr[:]以複製一份用來讓res進行附加。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(logN)，因為整棵樹要遍歷過一遍，\n然後平均而言，樹的深度會到O(logN)，\n所以空間複雜度所以空間複雜度，這個部分不包含result的占用空間)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-08-18T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-104-tree-17-dfs-14-backtracking-6/","title":"從LeetCode學演算法 - 104 Tree (17) / DFS (14) / Backtracking (6)"},{"content":"0112. Path Sum (Easy)\n寫在前面 容筆者工商一下， 「從Leetcode學演算法｜進階篇」及 加贈的**「從Leetcode學演算法｜面試篇」已經全數上傳完囉！**\n目前只剩下給讀者的進階篇+面試篇(3150) 和全套同捆優惠(3990) 了QQ\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\n內容介紹：\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛…就延長到滿人數吧XDD (不然也沒辦法哈哈)\nQuestion Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.\nNote: A leaf is a node with no children.\nExample:\nGiven the below binary tree and sum = 22,\n1 2 3 4 5 6 7 5 / \\ 4 8 / / \\ 11 13 4 / \\ \\ 7 2 1 return true, as there exists a root-to-leaf path 5-\u0026gt;4-\u0026gt;11-\u0026gt;2 which sum is 22.\n分析/解題 給定一棵二元樹，試決定該二元樹是否有一個從根到葉的路徑，\n使得路徑上的節點總和恰等於給定的目標和。\n這一題是一整組Path Sum系列題的第一題，\n除了接下來幾篇會陸續談到系列題外，這篇也想著重給讀者一個提醒：\n很多時候能用DFS解的題目，通常也能用BFS解 (反之亦然)\n所以當下遇到一個題目的時候，除非有限定要求，\n否則只要能想到的解法就是好解法 ，\n不要硬逼自己一定要用DFS或一定要用BFS。\n(練習的時候，當然還是可以自我挑戰兩種都想出解來就是了XD)\n首先我們要留意到一件事情：\n由於是從根到葉，\n所以我們只需要在走到左右均無節點時再檢查總和是否相符即可，\n千萬不要沿途檢查呀XD！\n再者，由於路途經過的都會算做計入的總和，\n所以我們可以沿路將往下走所需的總和減去當前經過的節點。\n依照這個概念，我們可以蠻直觀地寫出一個DFS的解：\n先檢查root如果是NIL -\u0026gt; 直接回傳False 檢查root.left/root.right 是不是都為NIL -\u0026gt; 若均為NIL，\n若root.val等於所需和 則回傳True ，否則回傳False 將往下走的剩下的和next定為sum — root.val(剩下需要湊的和) 回傳hasPathSum(root.left, next) || hasPathSum(root.right, next) (因為只要存在一條路徑即為True，所以兩者用或 來連接) 由上可知，用來判定這個位置能不能成為我們要的路徑和，\n只取決於兩點：\n現在這個位置是否已經是葉(leaf) 現在這個位置的値是否是剩下需要的和 所以我們也可以用BFS的方式，搭配前面講過的Queue來處理：\n同樣先檢查root及處理回傳 將**[(root, sum - root.val)]** 放入Queue當中 進行迴圈，每次從Queue中取出一組**(curr, val)** 並檢查：\n3–1. 若curr.left/curr.right均為NIL -\u0026gt; ** 若val為0，回傳True**\n3–2. 檢查curr.left，若存在 -\u0026gt; 將**(curr.left, val - curr.left.val)放入Queue** 中\n3–3. 對curr.right做相同處理 若迴圈結束仍未回傳，則回傳Fals e(找不到適合的路徑) 依上面的方式，我們分別在Java/Python演示不同的方法：\n(讀者也可以自行嘗試完整練完單一語言的DFS/BFS的方法)\nJava Java的部分，使用了DFS，所以整體而言看起來很簡單，\n不過原則上有用遞迴的題目，就盡量要留意call stack的深度會不會超過。\nPython Python的部分則使用了BFS，搭配deque做為queue使用，\n留意當val != 0的時候記得要繼續操作，因為你可能會有其他節點符和XD，\n這點和DFS時不一樣，請特別留意不要直接在那邊回傳False呦！\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(log N)或O(N)(平均)，\n因為DFS的話記憶體計算call stack深度，\nBFS的話則是要用最底部的橫向長度來看；\n如果極端的狀況的話DFS也有可能到O(N)，因為樹可能不平衡)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-08-08T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-103-tree-16-dfs-13-bfs-3-queue-4/","title":"從LeetCode學演算法 - 103 Tree (16) / DFS (13) / BFS (3) / Queue (4)"},{"content":"1530. Number of Good Leaf Nodes Pairs (Medium)\n寫在前面 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n期限嘛\u0026hellip;就延長到滿人數吧XDD (不然也沒辦法哈哈)\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\nQuestion Given the root of a binary tree and an integer distance. A pair of two different leaf nodes of a binary tree is said to be good if the length of ** the shortest path** between them is less than or equal to distance.\nReturn the number of good leaf node pairs in the tree.\nExample 1 1 2 3 Input: root = [1,2,3,null,4], distance = 3 Output: 1 Explanation: The leaf nodes of the tree are 3 and 4 and the length of the shortest path between them is 3. This is the only good pair. Example 2 1 2 3 Input: root = [1,2,3,4,5,6,7], distance = 3 Output: 2 Explanation: The good pairs are [4,5] and [6,7] with shortest path = 2. The pair [4,6] is not good because the length of ther shortest path between them is 4. Example 3 1 2 3 Input: root = [7,1,4,6,null,5,3,null,null,null,null,null,2], distance = 3 Output: 1 Explanation: The only good pair is [2,5]. Example 4 1 2 Input: root = [100], distance = 1 Output: 0 Example 5 1 2 Input: root = [1,1,1], distance = 2 Output: 1 Constraints The number of nodes in the tree is in the range [1, 2^10]. Each node’s value is between [1, 100]. 1 \u0026lt;= distance \u0026lt;= 10 分析/解題 這題是2020/07/26舉辦的199th LeetCode Weekly Contest的第3題。\n給定一個二元樹的根節點root和一個整數距離distance，\n如果兩個不同的葉節點配對，其最小距離小於等於distance，\n我們就將其稱之為好(good)。\n試回傳這棵樹好的葉節點配對的總數。\n我們先前應該已經提到過葉節點就是指左右都沒有連接節點的節點 ，\n那麼，這題要怎麼思考呢？\n我們不妨先留意一下題目給定的條件：\n節點數量是1~2¹⁰，由於2¹⁰=1024 ，所以最壞的狀況，\n遞迴的數量也就1024而已，所以應該可以不會超過call stack的上限。\n接著，1≤distance≤10決定了我們在遞迴時，\n可以適度修剪我們要處理的節點。\n那這題該怎麼思考呢？\n由於我們在求的是最短距離，假定我們要看兩個節點x, y，\n那麼最短路徑肯定是從x往上走到x, y的最低共同祖先，\n再往下走到y的位置。\n如果我們知道x, y的LCA(最低共同祖先)n，\n又知道n的左子樹的所有葉節點各自的深度，\n及右子樹的所有葉節點各自的深度，\n那麼我們就可以知道以n為LCA時，正確的節點對有哪些。\n怎麼知道？就迴圈加起來就好了嘛！\n那我們又怎麼知道某個節點n的左右子樹的葉節點深度呢？\n我們可以先用dfs往深處走，走到出現葉節點的時候，\n將其記錄為距離1並往上傳(因為這時候左右也都沒得走了)；\n那在某個非葉節點的n 時，我們應該可以從dfs的結果，\n分別獲得左右子樹的各個葉節點離n的距離 。\n我們將兩個距離的列表分別叫作llt跟rlt (left list, right list)，\n從llt跟rlt分別成對取出來相加，\n每發現一組葉節點距離相加小於等於10，全局的解就加1 。\n做完檢查以後該做什麼呢？\n裡面所有的葉節點應該可以往上通用，對吧？\n可是我們左子樹和右子樹往上都導到當前的節點再往上，\n再往上的深度應該都要加1 才對！\n所以我們應該將llt和rlt裡面的所有值都分別+1以後，\n放入一個新的list，這裡命名為merge，再將其往上傳。\n因此，整個流程會大致如下：\n定一個class變數cnt，用來記錄成功配對的葉節點對的總數 在主函式裡，先檢查root是否為NIL，是的話直接回傳0 將root和distance帶入遞迴函式dfs中 回傳cnt 而在dfs函式中，我們要做的事情是：\n若n為NIL，回傳空的串列 若n的左右節點均為NIL ，則回傳一個裡面只含一個1的串列 呼叫dfs(n.left, distance) 及dfs(n.right, distance) 進行遞迴，\n取得回傳的llt 跟rlt (記錄兩邊葉節點深度的串列) 初始化一個空的串列merge 雙重迴圈，每當遇到llt和rlt的値**，\n兩兩相加會小於等於distance的狀況，就將 cnt遞增1** 分別將llt和rlt的値全數+1後，加到merge 裡\n(這邊可以檢查值必須小於distance ，超過的話因為總路徑肯定超過， 所以不符的不用放到merge內) 回傳merge 依此，寫成程式碼如下：\nJava 由於需要一個一個取出，並且重複使用，\n所以我們使用ArrayList 並使用get 來取得當中的值。\n在雙重迴圈的時候，我們可以順便將外層的値處理一下放到merge內 ，\n這樣後面就不用再重複一個新的迴圈處理。\n(但內層的不能這麼做，因為會被重複執行)\nPython Python的部分，cnt的累計可以使用list comprehension，\n處理符合的配對再來取len() ，這樣寫起來會比雙重迴圈方便許多。\nllt和rlt則可以用類似的方式，最後將串列用加號組起來回傳。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O((log N)³)/O(log N)，因為只有葉節點需要被記錄，\n空間應該跟最底層的節點數有關，而除了雙重迴圈外，\ndfs的深度也跟這棵樹的深度有關，但這個部分會受到distance的制約，\n所以實際應該比這個複雜度快不少)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-07-31T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-102-tree-15-dfs-12/","title":"從LeetCode學演算法 - 102 Tree (15) / DFS (12)"},{"content":"1529. Bulb Switcher IV (Medium)\n寫在前面 抽獎活動還在繼續累積人數(現在好像沒有人想抽XD)\n在Python Taiwan的連結第100篇的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n截止時間為7/31 23:59:59，這之後的留言問題我有看到還是會回答，\n但就不會納入抽獎資格歐！\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n當前面試篇以上傳完畢，進階篇則會在8/31前陸續上傳完成呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\nQuestion There is a room with n bulbs, numbered from 0 to n-1, arranged in a row from left to right. Initially all the bulbs are turned off .\nYour task is to obtain the configuration represented by target where target[i] is \u0026lsquo;1\u0026rsquo; if the i-th bulb is turned on and is \u0026lsquo;0\u0026rsquo; if it is turned off.\nYou have a switch to flip the state of the bulb, a flip operation is defined as follows:\nChoose any bulb (index i) of your current configuration. Flip each bulb from index i to n-1. When any bulb is flipped it means that if it is 0 it changes to 1 and if it is 1 it changes to 0.\nReturn the minimum number of flips required to form target.\nExample 1 1 2 3 4 5 6 7 Input: target = \u0026#34;10111\u0026#34; Output: 3 Explanation: Initial configuration \u0026#34;00000\u0026#34;. flip from the third bulb: \u0026#34;00000\u0026#34; -\u0026gt; \u0026#34;00111\u0026#34; flip from the first bulb: \u0026#34;00111\u0026#34; -\u0026gt; \u0026#34;11000\u0026#34; flip from the second bulb: \u0026#34;11000\u0026#34; -\u0026gt; \u0026#34;10111\u0026#34; We need at least 3 flip operations to form target. Example 2 1 2 3 Input: target = \u0026#34;101\u0026#34; Output: 3 Explanation: \u0026#34;000\u0026#34; -\u0026gt; \u0026#34;111\u0026#34; -\u0026gt; \u0026#34;100\u0026#34; -\u0026gt; \u0026#34;101\u0026#34;. Example 3 1 2 Input: target = \u0026#34;00000\u0026#34; Output: 0 Example 4 1 2 Input: target = \u0026#34;001011101\u0026#34; Output: 5 Constraints 1 \u0026lt;= target.length \u0026lt;= 10^5 target[i] == '0' or target[i] == '1' 分析/解題 這題是今天(2020/07/26)舉辦的199th LeetCode Weekly Contest的第2題。\n房間裡有n個燈泡**(0~n-1)** ，從左至右排列，初始全數是關的 。\n我們的目標是將燈開關成target 的狀態，在index i的位置上，\ntarget[i]如果是'1\u0026rsquo;的話就表示開，target[i]如果是'0\u0026rsquo;的話就表示關。\n所能夠做的操作只有一種叫flip 的方法。\nflip方法的操作是選取一個index i，\n接著會將i~n-1的所有燈泡狀態反轉，1變成0，0變成1 。\n我們要作的事情是找出最少完成target的flip次數。\n是說每次碰到稍微生活化一點的題目，就會覺得有點87：\n像這題亮燈就亮燈，搞那麼麻煩的開關方式幹嘛啦！！！\n不怕燈泡壞掉逆？？？\n這題乍看之下好像不容易，\n但仔細一看，flip的操作只影響該點及其右側的燈泡，\n所以我們由左往右看的話，只需要考慮當前該燈泡需不需要翻轉 即可，\n因為某個點右側的燈泡flip不會影響該點。\n由於右邊的會一起反轉 ，所以我們可以定位一個flag=1 ，\n一開始大家都是0，所以第一次我們要翻轉的狀況，\n就是碰到target[i]和flag相等時。 把右側翻過來以後，我們可以將flag從'1\u0026rsquo;變成'0\u0026rsquo;，\n因為我們只要考慮翻或不翻 ，所以使用flag的變化 ，\n和target[i]碰到的値來作對照 會相當方便：\n只要碰到和flag相同的就代表要加翻一次 ，\n不同的就代表不用翻 ，這樣沿路走到尾端，就可以得到計數的答案。\n依此，寫成程式碼如下：\nJava Java的部分使用charAt可以按char來取出每個字元，\n請留意要比較的時候要取成int，這邊直接減去’0’即可。\nPython Python的部分直接用int進行轉換字元成整數即可。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(len(target))/O(1)，除了flag跟cnt以外並未額外再多用到其他空間)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-07-26T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-101-string-6/","title":"從LeetCode學演算法 - 101 String (6)"},{"content":"1510. Stone Game IV (Hard)\n寫在前面 扣掉第0篇外，這篇是100篇啦！！！**從開始寫以來，一路到現在其實也不容易，\n雖然頻率因為工作和開課的關係降低很多，\n但希望大家仍然從文章中能有所收穫。\n100篇好像應該要來個感恩回饋(?)\n那這樣好了，如果有任何問題，\n歡迎在本篇底下發問(Python Taiwan也可以)，\n同時請在Python Taiwan的連結本篇文的文章 底下，\n公開分享到你的臉書、按讚該篇文章、並留言告訴我說，\n「你最喜歡這一整個系列的哪一篇？為什麼？」或\n「除了從LeetCode學演算法系列以外，\n你還想要看到關於什麼方向的文章？」\n超過20則留言的話 (有完成以上步驟的才算)，我們就抽一組\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」\n課程的免費兌換券進行贈送！\n截止時間為7/31 23:59:59，這之後的留言問題我有看到還是會回答，\n但就不會納入抽獎資格歐！\n如果留言人數不足的話，\n那我可能就以一篇文章的形式來回應大家的問題，\n就不會進行抽獎囉XD\n感謝大家的支持與肯定，期待我們都能從這當中(我寫文章，你們讀文章XD)\n不斷成長，進而提升自己的程式能力！\n容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！面試篇已經全數上傳啦~\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\nQuestion Alice and Bob take turns playing a game, with Alice starting first.\nInitially, there are n stones in a pile. On each player\u0026rsquo;s turn, that player makes a move consisting of removing any non-zero ** square number** of stones in the pile.\nAlso, if a player cannot make a move, he/she loses the game.\nGiven a positive integer n. Return True if and only if Alice wins the game otherwise return False, assuming both players play optimally.\nExample 1 1 2 3 Input: n = 1 Output: true Explanation: Alice can remove 1 stone winning the game because Bob doesn\u0026#39;t have any moves. Example 2 1 2 3 Input: n = 2 Output: false Explanation: Alice can only remove 1 stone, after that Bob removes the last one winning the game (2 -\u0026gt; 1 -\u0026gt; 0). Example 3 1 2 3 Input: n = 4 Output: true Explanation: n is already a perfect square, Alice can win with one move, removing 4 stones (4 -\u0026gt; 0). Example 4 1 2 3 4 5 Input: n = 7 Output: false Explanation: Alice can\u0026#39;t win the game if Bob plays optimally. If Alice starts removing 4 stones, Bob will remove 1 stone then Alice should remove only 1 stone and finally Bob removes the last one (7 -\u0026gt; 3 -\u0026gt; 2 -\u0026gt; 1 -\u0026gt; 0). If Alice starts removing 1 stone, Bob will remove 4 stones then Alice only can remove 1 stone and finally Bob removes the last one (7 -\u0026gt; 6 -\u0026gt; 2 -\u0026gt; 1 -\u0026gt; 0). Example 5 1 2 3 Input: n = 17 Output: false Explanation: Alice can\u0026#39;t win the game if Bob plays optimally. 分析/解題 Alice和Bob玩不膩的撿石頭遊戲又來啦！\n這次一樣是Alice先開始，一堆石頭裡面有n個石頭，每次玩家行動時，\n可以選擇拿走某個非0的平方數的石頭數量，稱為一次行動。\n(也就是1的平方、2的平方、3的平方\u0026hellip;等)\n當有人無法作任何行動的時候(也就是沒有任何石頭能拿)，就輸惹QQ\n給定正整數n代表石頭的個數，如果Alice確定可以贏遊戲的話，\n就回傳True，反之則回傳False。(假定雙方都採最佳的策略來進行)\n由於每次要拿非0的平方數，所以不能pass，\n這就保證了遊戲一定會結束，\n因為最後一定會拿到空掉，下一個人會輸掉。\n我們來考慮一下前面幾個狀況，來觀察一下有沒有什麼規律：\nn = 0: False -\u0026gt; 顯然就是輸了嘛XD\nn = 1: True -\u0026gt; Alice拿走1顆(1²)，由於拿光了，所以Alice贏。\nn = 2: False -\u0026gt; Alice只能選擇拿1顆，Bob再拿1顆就沒了，Alice輸掉。\nn = 3: True -\u0026gt; 只有1, 1, 1的選擇，所以Alice贏\nn = 4: True -\u0026gt; Alice拿走4顆(2²)，直接獲勝\n看起來好像沒有很明顯對吧？\n但這邊可以從題目中思考到一個關鍵，由於雙方都是以最好的策略，\n也就是Bob不會該贏卻沒贏 ，所以以下兩點是我們可以確定的：\n1. 當n直接是完全平方數時，Alice可以贏\n2. 當n=x會讓Bob贏(Alice輸)的時候，n在以下狀況時Alice會贏：\nx+1, x+4, x+9, x+16…\n因為這時候Alice只要拿掉對應的石頭，讓Bob碰到x的狀況，\n這時候就反而變成Bob會輸了！\n(Alice先拿會輸的狀況，換成Bob先拿也會輸)\n由於這個狀況只限定於我們發現前一個False，\n所以我們必須從已經確定的值去推論，\n假設今天我們想要知道n = i的值是否為True ，\n我們需要先知道n=0~i-1的值 ，\n接著檢查是否有任何一個n=i-j² 的結果是False (留意j²要小於等於i )\n只要有一個符合，那n=i的值就是True，\n如果全部檢查完都沒有的話，n=i的值即為False。\n由於n=i的值會跟前面n=i-j²的結果有關係，\n這是一個很明顯的動態規劃的題目。\n因此，我們的程式流程應該像這樣：\n先初始化dp的陣列 ，其長度為n+1，並先全初始化成False。 執行一個迴圈，讓i從1~n (0已經是False了直接跳過) ：\n2-1. 在裡面再開一個迴圈，讓j從1遞增到最大j² == i 為止\n2-2. 若dp[i - j²]為False，將dp[i]設為True 並且break 離開這層迴圈\n(已經確定True就不用往下找了) 整個雙層迴圈完成後，我們應該處理完成了整個dp的陣列，\n只要回傳dp[n] 即可。 依此，寫成程式碼如下：\nJava Java的部分，由於boolean陣列初始化的預設值就是False，\n就不用額外作初始化了。(C++的話還是記得要初始化啊！)\n要使用ArrayList也可以，但長度確定固定的話，其實直接開陣列比較快。\nPython Python的部分，我們當然也可以一路append，\n但直接初始化串列比較乾脆，內層的迴圈則使用while來檢查條件，\n不要忘記每次將j遞增。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n^(3/2))/O(n) 外層迴圈要跑n次，內層最大是根號n；\n空間上使用dp的陣列/串列外，沒有額外的需求了)\n相似及延伸 1140. Stone Game II (Medium)\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n別忘了，要抽獎的讀者記得去Python Taiwan按讚留言分享歐！\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-07-20T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-100-dynamic-programming-14/","title":"從LeetCode學演算法 - 100 Dynamic Programming (14)"},{"content":"0404. Sum of Left Leaves (Easy)\n寫在前面 容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\nQuestion Find the sum of all left leaves in a given binary tree.\nExample:\n1 2 3 4 5 3 / \\ 9 20 / \\ 15 7 1 There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24. 分析/解題 給定一個二元樹，試求所有左葉子的總和。\n我們很久以前有提過二元樹的定義，\n忘記的話，請再複習一下XD\n而葉子的定義，就是它左右都沒有連接節點(NIL)！\n這時候，你可能會說：\n我知道，那我只要一直往左邊看就好啦！\n呃\u0026hellip;\u0026hellip;同學，你忘記了你的右子樹也可能產生左葉子 嗎XD？\n範例中的15，不就是先從3的右節點20，\n再往左節點來到15所得到的嗎？\n那怎麼辦呢？\n所以我們在檢查所在節點是不是葉子的時候，\n還需要看看這個節點是不是從它的根節點往左邊走下來 的。\n因此，我們可以每次分支往左右走，給出一個參數from，\n分別給往左子樹走的函式1，給右子樹走的函式-1 ，\n用來代表下一層的時候拿來判定是不是左葉子的前置依據。\n當我們看到from == 1且左右節點均為NIL時，\n就可以將當前的節點值回傳，\n否則的話，就繼續遞迴往下找底下子樹當中左葉的和。\n依此，寫成程式碼如下：\nJava Java的部分，每次先檢查root是否為null，\n接著我們的答案就用\nsumOfLeftLeaves(root.left, 1) + sumOfLeftLeaves(root.right, -1)\n來取得。\n其他的寫法概念如前所述。\nPython Python的部分寫一個子函式，因為這邊沒有用self，\n所以可以不用self.getSum來算。\n(也可以把add設定預設値-1，\n使用單個sumOfLeftLeaves來解此題，\n這個化簡方式很簡單，就留給讀者來練習看看XD)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，因為要經過每個節點，\n而如果考慮call stack的話，\n空間複雜度會是O(depth of Tree))\n相似及延伸 0235. Lowest Common Ancestor of a Binary Search Tree (Easy)\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-07-13T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-99-tree-14-dfs-11/","title":"從LeetCode學演算法 - 99 Tree (14) / DFS (11)"},{"content":"透過聆聽不同的工程師訪談，培養能力並抓住面試的機會\n由於剛好上架完了面試篇的所有內容，所以想來跟大家介紹一下。\n在面試篇當中，我們整理了一些各種面試常出現的題型，\n以及幫助你初步推測解題方向的方法；\n同時，我們訪問了四位工程師：\nLiuLiu , HiSKIO的後端工程師，主要使用PHP+Laravel Andy , Aimazing的前端工程師，主要使用Javascript+Vue.js Mike , 資深前端工程師，\n也是擁有7門線上課程 和YouTube頻道 的前端講師 Kenji , 資深軟體工程師，目前在矽谷的Square工作\n(一家FinTech電子支付公司)\n(同時他也有一個Podcast: Just Kidding Tech 輕鬆談科技) 由於涵蓋了不同資歷和定位的工程師的視角，\n你可以從不同的受訪者身上，看到他們的觀點的差異，\n以及不同時期的工程師所需要的技能有什麼。\n這門面試課是和進階課綁定，不另行收費 ，個人覺得相當之划算。\n當初原本只是一個附帶的構想，但為了想要給出足夠完整的東西，\n最後就變得反而讓我做到很崩潰XD\n當然，成果也是可喜的，我從訪談的交流過程中，\n除了得到有用的資訊外，也常常被逗樂。\n比方說Mike就告訴我們：\n我就是Code我就會忘阿，我就是靠編輯器來幫我提示阿，\n我就是哪有辦法這樣寫得出來，我就覺得莫名其妙耶你知道嗎？\n工程師考試那沒有提供電腦，那叫我拿紙筆寫，又不是在寫作文。\n+1\nKenji則說：\n你看太看重那個失敗本身，你太看重你被拒絕這件事情的話，\n你反而會很難再繼續面試，因為你這個東西就是一個拒絕的過程。\n人總會有被打槍的時候嘛XD\n面試如是，人生如是，總會有種種的挫折，\n但我由衷希望，我的文章和課程，\n能帶給所有正準備挑戰工程師的面試的人幫助。\n所以，有興趣的話，就考慮一下吧！\n如果有希望我開什麼樣的內容或寫什麼方向的文章的話，\n也可以留言告訴我～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-07-12T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-chapter-interview/","title":"從LeetCode學演算法 - 面試篇宣傳"},{"content":"0129. Sum Root to Leaf Numbers (Medium)\n寫在前面 容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/advleetcode\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/allleetcode\nQuestion Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.\nAn example is the root-to-leaf path 1-\u0026gt;2-\u0026gt;3 which represents the number 123.\nFind the total sum of all root-to-leaf numbers.\nNote: A leaf is a node with no children.\nExample:\n1 2 3 4 5 6 7 8 9 Input: [1,2,3] 1 / \\ 2 3 Output: 25 Explanation: The root-to-leaf path 1-\u0026gt;2 represents the number 12. The root-to-leaf path 1-\u0026gt;3 represents the number 13. Therefore, sum = 12 + 13 = 25. Example 2 1 2 3 4 5 6 7 8 9 10 11 12 Input: [4,9,0,5,1] 4 / \\ 9 0 / \\ 5 1 Output: 1026 Explanation: The root-to-leaf path 4-\u0026gt;9-\u0026gt;5 represents the number 495. The root-to-leaf path 4-\u0026gt;9-\u0026gt;1 represents the number 491. The root-to-leaf path 4-\u0026gt;0 represents the number 40. Therefore, sum = 495 + 491 + 40 = 1026. 分析/解題 給定一個二元樹，當中只有數字0~9，\n每個根到葉子的路徑可以表達一個數。\n舉例來說，1-\u0026gt;2-\u0026gt;3可以表達123。\n找出所有的根到葉的數字的總和。\n(葉的定義是沒有子節點的節點)\n這題雖然標註為Medium，但其實並不那麼難思考，\n只是定義要弄清楚而已。\n首先，假設我們在某個節點n，它如果左節點和右節點都沒有的話，\n意味著它是葉(leaf)，這時數字就要計入總和；\n如果有其中一個成立的話，我們應該要往下走，\n並記錄之前經過的節點値，這樣子在遇到葉的時候才能夠結算。\n那麼自然，由於每棵樹只有0~9，\n所以從一層樹到下一層的時候，原先經過的數字的作用會放大10倍。\n也就是說，從上一層下來的時候，如果所在是葉的話，\n我們應該要把這個數字乘以10以後，加上現在的節點値 。\n因此，我們只要遍歷完整棵樹，將葉子加總 起來即可。\n寫成流程應該如下：\n檢查根節點是否為NIL，如果是，直接回傳0(此路不通) 計算上面下來的值(last)到當前根節點的值(now)的結果，\nnow = last * 10 + root.val 如果左右節點均為NIL，直接回傳now 即可(當前節點為葉) 將root.left, now及root.right, now 分別傳入做遞迴計算左右子樹的和 ，\n最後加總起來並回傳 。 所以我們會先沿著最左邊一路到最底，然後依序將所有節點走過，\n這樣子是先往深處走，所以是所謂的深度優先搜尋(DFS)的方法。 另外一方面，留意由於我們最開始已經檢查了root是否為NIL，\n所以在傳入左右子節點時，可以讓前面這條檢查來確認NIL的狀況，\n也就不用再先檢查節點是否為空了。\n依此，寫成程式碼如下：\nJava Java可以使用相同的函式名稱，傳入不同長度的參數 來處理。\nPython Python的部分，我們直接設定預設值 ，這樣就可以通用了XD\n當從根節點開始時，由於只傳入root, 自然last會是0。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1), 如果算上call stack的部分的話，\n平均空間複雜度是O(logN) (DFS的深度))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-06-27T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-98-tree-13-dfs-10/","title":"從LeetCode學演算法 - 98 Tree (13) / DFS (10)"},{"content":"0368. Largest Divisible Subset (Medium)\n寫在前面 容筆者工商一下，\n「從Leetcode學演算法｜進階篇」 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://bit.ly/2desolve\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/adesolve\nQuestion Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies:\nSi % Sj = 0 or Sj % Si = 0.\nIf there are multiple solutions, return any subset is fine.\nExample 1 1 2 Input: [1,2,3] Output: [1,2] (of course, [1,3] will also be ok) Example 2 1 2 Input: [1,2,4,8] Output: [1,2,4,8] 分析/解題 給定一個內含不同正整數的集合，找出最大的子集合，使得當中任取一對元素(Si, Sj)出來均能符合Si整除Sj或Sj整除Si。\n如果有多個不同的解，回傳當中任何一個都可以。\n首先我們可以先想到，在這個題目當中顯然nums是沒有被排序的，\n如果以最笨的辦法來說的話，一個集合會擁有2^N個子集合\n(因為每個元素都可以選擇要在這個子集合或不在這個子集合內)，\n而每個組合當中如果又要兩兩檢查的話，又要各自花上n(n-1)/2的時間。\n(n為該子集合的元素數量)\n顯然直接考慮是非常不符合的，所以只好嘗試先排序過後，\n看看能得到什麼可以用的特性。\n那在排序過後，我們會想到一個點是，如果我們由小到大看的話，\n假設前面選取了a跟b，那下一個選取的數c只需要確定能被b整除即可。\n為什麼？因為按順序由小到大排，所以當我們選b的時候，\n一定是要b能被a整除才行，於是後面接續的選擇，\n只要確保能被最後一個數整除，就會符合能被前面的其他數整除了！\n接著下來，假設我們觀察一下數列的規律：\n假設有一個數列是1, 2, 3, 4, 6, 8, 12, 18，\n我們可以稍微列出幾串能成立Divisible Subset的內容\n(先不考慮有沒有最大個數)：\n1, 2, 4 , 8\n1, 3, 6, 12\n1, 3, 6, 18\n1, 2 , 6, 12\n1, 2, 6, 18\n有沒有發現，當中間選的不一樣，後面能接的數字也就不一樣，\n從最大的數字往回推的時候，上一個index就有可能因而改變。\n由於我們在考慮的是如何去找前面已經選取的子集合，\n和下面要選取的數的關係，所以這基本上就是動態規劃的題目跑不了XD!\n那麼，該怎麼樣定這中間的關係呢？\n首先選取我們的dp，這個值要能夠拿來比較哪個子集合是擁有最多元素的，\n那我們不妨這麼定義：\ndp[i]就是從已經排序好的nums中，從index 0~i的數字中，\n選取出來最大可整除的子集合其元素的個數，且這個子集合當中必須包含nums[i]。為什麼要定義必須包含nums[i]呢？因為不管怎麼樣，\n最起碼可以選取index i，這樣子我們就可以將所有dp[i]先初始化為1 ，\n因為這是它的保底。\n接下來，我們要怎麼去紀錄當確立一個子集合的時候，\n整個子集合的長相呢？\n可以利用每個比較大的數只需要看前面一個數是否能將其整除的特性，\n定義一組陣列或串列，當中存放符合前面dp定義的時候，\nnums[i]的對應到前面一個數的index在哪裡 ，\n將其稱呼為lidx(last index)。我們在找到最大的解的時候，\n後續可以利用lidx來列出整個解。因此，將lidx全部初始化為-1 ，\n當我們最後迴圈找尋遇到-1的時候，就表示整個解都被我們列出來了。\n那接下來就簡單了，定義一個全局最大解所在的索引值max_idx，\n以及最大解的元素總數max_dp，分別初始化成0跟1。\n接下來我們需要一個雙層的迴圈，第一層迴圈是i從0開始到nums尾端 ，\n以nums[i]做為當下這個子集合的最大值。\n而第二層迴圈則是j從i-1開始到0 ，\n目的是要一路往回找nums[i]是否整除nums[j]。\n如果整除的話，代表有一個子集合的排列方式是：\n\u0026hellip;\u0026hellip; , nums[j], nums[i]\n這個子集合是不是對i來說是最好的狀況呢？\n那就要看dp[j]+1是不是比dp[i]還要大 ，\n如果比較大，才表示i的排列要換成走j這條線對吧XD？\n所以比較大 的話，我們就應該要把dp[i]的值改成dp[j] + 1 ，\n並且lidx[i]要改成j (因為改成走nums[j]這條路了)。\n每次將j走完以後，dp[i]有可能被改變，\n自然全局最大的解也有可能被改變，所以我們要檢查看看，\n如果需要更動，就進行更動。\n如此完成了雙層迴圈後，\n最後就從max_idx開始以一個單層迴圈將解列出來 ，\n記得迴圈的結束條件是index碰到-1 (代表已經到頭了)。\n依此，寫成程式碼如下：\nJava Java的部分，可以用Arrays.fill來進行填充初始值的動作，\n其他則是使用ArrayList來將res一個一個加入(要用LinkedList也可以)。\n最後一個for迴圈的部分，如果使用者不想留max_idx，\n也可以直接使用while來操作，\n每次的下一步則是max_idx = lidx[max_idx] 。\nPython Python的部分則是用[x] * n的方式來初始化，其他的部分跟Java並無不同。\n請留意將串列原地排要用nums.sort() ，\n如果用sorted(nums) 的話則是會回傳一個新的排序好的串列 。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N²)/O(N)，因為時間用到雙層迴圈，每層都是O(N)要相乘，\n而O(N²)會大於排序用的O(NlogN)，所以就取O(N²)；\n空間上則用到dp跟lidx，均為O(N))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」 已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算 (差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊：\nhttps://bit.ly/1desolve\n","date":"2020-06-17T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-97-dynamic-programming-13/","title":"從LeetCode學演算法 - 97 Dynamic Programming (13)"},{"content":"1008. Construct Binary Search Tree from Preorder Traversal (Medium)\n寫在前面 容筆者工商一下，\n「從Leetcode學演算法｜進階篇」在今天(6/9)中午12點 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友可以使用下面的早鳥優惠～\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」 ：\nhttps://hiskio.com/packages/YoRY45yZm\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://hiskio.com/packages/MByQ4pw3W\n另外，\nQuestion Return the root node of a binary search tree that matches the given preorder traversal.\n(Recall that a binary search tree is a binary tree where for every node, any descendant of node.left has a value \u0026lt;``node.val, and any descendant of node.right has a value \u0026gt;``node.val. Also recall that a preorder traversal displays the value of the node first, then traverses node.left, then traverses node.right.)\nIt’s guaranteed that for the given test cases there is always possible to find a binary search tree with the given requirements.\nExample 1 1 2 Input: [8,5,1,7,10,12] Output: [8,5,10,1,7,null,12] Constraints 1 \u0026lt;= preorder.length \u0026lt;= 100 1 \u0026lt;= preorder[i] \u0026lt;= 10^8 The values of preorder are distinct. 分析/解題 從給定的前序走訪 一棵二元搜尋樹的結果，\n重建一棵符合的二元搜尋樹，並回傳其根節點。\n題目給出的測試資料均保證可以找到一個符合的二元搜尋樹。\n我們很早以前已經解說過二元搜尋樹的特性 了，\n前序走訪(preorder) 表示順序是根-左-右 ，\n不像是中序走訪(inorder) 會剛好是左-根-右，順序會剛好由小到大排列 。\n那麼，我們要怎麼樣才能架構一個合理的BST(二元搜尋樹)呢？\n由於BST和preorder的特性，當我們一路往左走的時候，\n我們會越走碰到的值越小 ，這表示我們是一路看到當下的根節點 ，\n接著往左走看到左節點 才會發生這樣的狀況；\n如果我們當下碰到了比根節點還要大的狀況呢？\n代表這段往左已經走完了，現在看到的是右節點。\n那麼怎麼知道是不是當下這個位置的右節點 呢？\n我們必須要比較現在所在的位置的前面的根節點值 才行。\n如果比根節點值小 ，代表它是被包含在當下這個子二元樹，\n反之，則代表它應該在上一層或更上層 才對。\n此外，我們可以設定一個class的變數i，\n用來紀錄現在我們建立二元樹的過程走到哪個index。\n那麼我們來整理一下流程：\n0. 初始化一個class變數 i = 0 。\n先檢查當前的陣列/串列是不是沒東西 ，沒東西的話就回傳null/None。 將int的最大值 作為邊界值 bound，\n傳入用來建立二元樹的函式(這裡命名為build ) 在build函式中，檢查如果i走完全長了 或者preorder[i] \u0026gt; bound，\n前者表示整個樹重建完了，後者表示這個子樹底下對於preorder[i]來說不可能放在任何一個地方了，所以回傳null/None回到上一層。4. 在這層建立一個 根節點root，** 其值為preorder[i]，完成後 將i遞增**。 接下來要建立root.left，呼叫build函式，\n將preorder及邊界值root.val 傳入。\n(因為root的左子樹所有值都要小於root的值) 再來建立root.right，呼叫build函式，\n將preorder及邊界值bound傳入。\n(因為root的右子樹裡的所有值要介於root的值 和上一層限制的bound 之間) 這層等於建立完畢了，將root回傳 。 我們簡單拿Example 1為範例來嘗試推導看看：\n(i, preorder[i], bound) = (0, 8, Integer.MAX_VALUE)\n=\u0026gt; root節點建立，其值為8，i遞增，呼叫build(preorder, 8)以建立左節點。\n(i, preorder[i], bound) = (1, 5, 8)\n=\u0026gt; 建立根節點，其值為5，i遞增，呼叫build(preorder, 5)以建立左節點。\n(i, preorder[i], bound) = (2, 1, 5)\n=\u0026gt; 建立根節點，其值為1，i遞增，呼叫build(preorder, 1)以建立左節點。\n(i, preorder[i], bound) = (3, 7, 1)\n=\u0026gt; 7\u0026gt;1，所以表示這層沒辦法放了，回傳null到上一層。\n(i, preorder[i], bound) = (3, 7, 5)\n=\u0026gt; 走到root.right這行，呼叫build(preorder, 8)以建立右節點。\n(i, preorder[i], bound) = (3, 7, 8)\n=\u0026gt; 建立根節點，其值為7，i遞增，\n呼叫root.left及root.right兩行都會回傳null，\n所以回傳該節點到上一層。\n(i, preorder[i], bound) = (4, 10, 8)\n=\u0026gt; 在5的底下建立完7的右節點了，這邊也完成了，\n回傳5的節點回到上一層。\n(i, preorder[i], bound) = (4, 10, Integer.MAX_VALUE)\n=\u0026gt; 走到root.right這行，呼叫build(preorder, Integer.MAX_VALUE)。\n(i, preorder[i], bound) = (4, 10, Integer.MAX_VALUE)\n=\u0026gt; 建立根節點，其值為10，i遞增，\nroot.left這行會回傳null，\nroot.right傳入build(preorder, Integer.MAX_VALUE)。\n(i, preorder[i], bound) = (5, 12, Integer.MAX_VALUE)\n=\u0026gt; 建立根節點，其值為12，i遞增。\n後面的部分由於i已經到達6，所以會往上層回到8的這層，\n最後回傳根節點(值為8)，結束。\n請讀者嘗試在紙上畫出來推過一遍，有助於更了解整個程式運行。\n由於我們是先一路往左深入並建立節點，碰到無法建立時，\n才回到上一層並嘗試往右走，\n所以這樣子的方式是DFS(深度優先搜尋) 的模式。\n依此，寫成程式碼如下：\nJava Java的部分，\n使用int時可以用Integer.MAX_VALUE作為初始邊界(即int能表示的最大值)。\nPython Python的部分，我們可以設定bound在未傳入值時預設值當作float(\u0026lsquo;inf\u0026rsquo;) ，\n即可使用同一個函式進行遞迴。\n此外，還是不要忘記Python並沒有++或\u0026ndash;，請自己換成用**”self.i += 1\u0026quot;** 。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(length of array)/O(1), 如果計算call stack的話則是O(BST的深度))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n另外，「從Leetcode學演算法｜基礎篇」已經回原價囉，\n先前的優惠碼會失效，但這邊仍然為讀者保留了300塊的折抵，\n雖然整捆一起買總體比較划算(差290而已就有整組了阿XD)，\n如果你還是想先試試基礎課的話，\n300元折抵的連結 在這邊： https://hiskio.com/courses/319?promo_code=NEXLJXE\n","date":"2020-06-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-96-bst-5-dfs-10/","title":"從LeetCode學演算法 - 96 BST (5) / DFS (10)"},{"content":"1143. Longest Common Subsequence (Medium)\n寫在前面 容筆者工商一下，\n接下來**「從Leetcode學演算法｜進階篇」** 即將於6/9 開放預購啦！\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\n有興趣的朋友請留意下一篇貼文的早鳥優惠～\n另外，\nQuestion Given two strings text1 and text2, return the length of their longest common subsequence.\nA subsequence of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, “ace” is a subsequence of “abcde” while “aec” is not). A common subsequence of two strings is a subsequence that is common to both strings.\nIf there is no common subsequence, return 0.\nExample 1 1 2 3 Input: text1 = \u0026#34;abcde\u0026#34;, text2 = \u0026#34;ace\u0026#34; Output: 3 Explanation: The longest common subsequence is \u0026#34;ace\u0026#34; and its length is 3. Example 2 1 2 3 Input: text1 = \u0026#34;abc\u0026#34;, text2 = \u0026#34;abc\u0026#34; Output: 3 Explanation: The longest common subsequence is \u0026#34;abc\u0026#34; and its length is 3. Example 3 1 2 3 Input: text1 = \u0026#34;abc\u0026#34;, text2 = \u0026#34;def\u0026#34; Output: 0 Explanation: There is no such common subsequence, so the result is 0. Constraints 1 \u0026lt;= text1.length \u0026lt;= 1000 1 \u0026lt;= text2.length \u0026lt;= 1000 The input strings consist of lowercase English characters only. 分析/解題 給定兩個字串text1及text2，\n回傳他們的最長共同子序列(Logest Common Subsequence, LCS)。\n一個字串的子序列是指一個字串從字串中原始的一些字母得來，\n當中刪去原字串的一些字元(也可以都不刪)，\n但保持相對於在原字串中的排列順序。\n舉例來說 ，”ace ”是**”a** bc de” 的子序列，但”ae c”不是。\n(排列相對順序已經不一樣了)\n兩個字串的共同子序列是指這個字串分別都是兩個字串的子序列。\n如果沒有共同子序列，則回傳0。\n當我們看到題目乍看之下沒有明顯的簡單解法時，\n就要考慮一下先找出前後之間的關聯 。\n也就是說，\n我們要先考慮從某一步推往下一步的算式。\n由於我們要求的是LCS，這個要求對應順序的特性，\n會導致一點：\n前面經過的字母，後面就不能用了。 比方說\u0026quot;abec drr\u0026quot;跟”ac e”，假設我們已經找到了 a 跟 c ，\n接下來我們只會從”drr”跟”e”之間作找尋，\n因為\u0026quot;abec\u0026quot;中的 e 沒辦法跟第二個字串對應(順序會亂掉)。\n這也表示，分別對兩個字串取出兩個子字串的LCS，\n只會跟它們更前面的部分有關聯 ，而和後面的字元沒有關係。\n思考到這裡，顯然這極有可能是Dynamic Programming了XD\n那麼，我們不妨將t1和t2兩個子字串的記法用 i 和 j 表示，\n當中0代表完全空字串，最大則分別到l1, l2。\n(也就是i, j就代表現在在t1, t2的第幾個字元，從1開始 )\n我們假設每個值互相關聯，那麼可以寫成一個二維陣列或串列dp。\n所以我們知道dp[0][0] == dp[i][0] == dp[0][j] == 0。\n(因為至少有一邊是空字串)\n下一步呢？\n如果我們在分別取 i, j 的字元數，那麼會分兩種狀況：\n1. t1[i-1] == t2[j-1] (i, j 的位置上的字元一模一樣)\n=\u0026gt; dp[i][j] = dp[i-1][j-1] + 1 因為對應的位置上得到相同字元，所以可以納入子序列中，\n所以假設我們知道dp[i-1][j-1]，那麼dp[i][j]應該就恰好多1。\n*這邊很容易搞混，請留意因為計算 index 的時候是從0 開始，\n所以我們的dp[i][j] 指的是比較 t1 的 0 到 i-1 及 ** t2** 的 ** 0 到 j-1兩個子字串。**\n2. i, j位置上的字元不同 =\u0026gt; 往回推一個字元\n由於i, j上的字元不同，所以dp[i][j]要嘛和dp[i][j-1]相同，\n要嘛和dp[i-1][j]相同。也就是說，兩個子字串其中一個 往回退一格所得到的結果，\n當中取比較大 的就可以了。(因為我們在找最大的解嘛XD)\n為什麼不能同時退？\n因為可能一邊對到的是前一個阿！\n比方說：\n“a bce ffz”跟”ac rrre”， 假設我們現在正在比較”abcef”跟”acrrre”，\n由於f和e不一樣，所以我們要改成比較\u0026quot;abce \u0026ldquo;-”acrrre ”和”abcef ”-”acrrr ”。\n如果我們直接各退一格，去比較”abce”跟\u0026quot;acrrr\u0026rdquo;，\n那e的對應不就被我們去掉了嗎？所以顯然要去除掉沒有對應到的字元，\n一次只能從其中一邊倒退一格才行。\n按照這個方式，我們可以使用雙層的迴圈，\n就可以將整個dp陣列或串列算完，最終dp[l1][l2]就會是我們想要的答案。\n回顧一下，我們利用了順序必須不變 的特性，\n確定了某個位置的值只跟前面的結果 有關；\n接著，判定當下對到的字元是否相同 ，\n相同的話 可以計入並用各自的前一格 的結果表示，\n不同的話 則要看誰退一格比較好 。\n因此所有的值彼此環環相扣，某個位置的值可以用前面的位置的值來表達，\n所以這的確是動態規劃 的問題無誤。\n依此，寫成程式碼如下：\nJava Java的部分除了要留意index的計算不要搞錯以外，\n整個程式碼相當簡單。\nPython Python的部分不要忘記二維串列不要連續用 * 的方式，\n(記憶體使用會重疊而不是開新的串列，這個之前有提到過)\n其他基本一模一樣。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(l1 * l2), O(l1 * l2))\n相似及延伸 這題依照不同的起始方式，解也有不同的寫法，\n讀者可以嘗試看看有沒有別的寫法。\n同時，讀者可能會發現只要前一層的數據，\n就可以拿來算下一層了，那麼，儲存的空間可以再進行精簡，\n請想想看，這樣子空間複雜度會變成多少呢？\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經快回原價啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\n想要一次全包的話，請等待下一篇貼文提供的同捆包 XD\n如果不太確定這是不是你想要的，\n底下是最後一波優惠連結(下次就回原價囉)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-06-06T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-95-dynamic-programming-12/","title":"從LeetCode學演算法 - 95 Dynamic Programming (12)"},{"content":"0438. Find All Anagrams in a String (Easy)\nQuestion Given a string s and a ** non-empty** string ** p**, find all the start indices of ** p**’s anagrams in ** s**.\nStrings consist of lowercase English letters only and the length of both strings s and ** p** will not be larger than 20,100.\nThe order of output does not matter.\nExample 1 1 2 Input: s: \u0026#34;cbaebabacd\u0026#34; p: \u0026#34;abc\u0026#34; 1 2 Output: [0, 6] 1 2 3 Explanation: The substring with start index = 0 is \u0026#34;cba\u0026#34;, which is an anagram of \u0026#34;abc\u0026#34;. The substring with start index = 6 is \u0026#34;bac\u0026#34;, which is an anagram of \u0026#34;abc\u0026#34;. Example 2 1 2 Input: s: \u0026#34;abab\u0026#34; p: \u0026#34;ab\u0026#34; 1 2 Output: [0, 1, 2] 1 2 3 4 Explanation: The substring with start index = 0 is \u0026#34;ab\u0026#34;, which is an anagram of \u0026#34;ab\u0026#34;. The substring with start index = 1 is \u0026#34;ba\u0026#34;, which is an anagram of \u0026#34;ab\u0026#34;. The substring with start index = 2 is \u0026#34;ab\u0026#34;, which is an anagram of \u0026#34;ab\u0026#34;. 分析/解題 給定一個字串s及一個非空的字串p，\n試找出所有在p在s內的所有異位構詞(anagram)的起始的索引值。\n本題當中的字串僅含小寫英文字母，且s和p的長度分別不會大於20, 100.\n(但不用在意輸出的順序)\n我們先前已經提過anagram的定義了，詳情可見0242. Valid Anagram (Easy) 。簡單來說，anagram是指說兩個字串是由相同的字元組成的，\n只有順序可能不同而已。\n我們先假設我們拿到兩個字串，要檢查它們是不是互為anagram，\n端看它們的’a’出現的次數，’b’出現的次數，’c’出現的次數\u0026hellip;, \u0026lsquo;z\u0026rsquo;出現的次數是否相同即可。\n這個儲存兩者出現的次數，可以使用HashTable來計算，\n而且由於我們要分的內容很簡單，所以只需要小寫字母個數26個即可，\n也就是Java可以使用一個長度為26的一維陣列，\nPython可以使用串列，要使用字典也行(相當於HashMap)。\n回到我們的問題，我們想要在s當中找到一個子字串，\n使得這個子字串和p互為anagram，\n這時候應該可以先將p的各字母出現次數先行記錄下來。\n接下來從s的index 0開始往右 ，一路計算走到可以取p的長度為止，\n如果這段能和p的組成內容相同，那就可以記做其中一個解。\n為了要比對是否組成內容相同，\n我們可以將每次看到的字母從p的hash table中扣除掉 ，\n當所有整個hash table都歸零的時候，我們就知道當前的組成相同了。\n但為了不需要每次都檢查整個hash table，\n我們可以先行設定一個cnt變數，其值等於p的長度。\n每次碰到可以扣除的組成就將cnt遞減，\n這樣當cnt為0且當前長度為和p長度相等時，就知道取得一個解了。\n接下來，我們需要一個left和一個right的索引值來記錄。\n由於長度固定就這麼長，當我們已經來到左右距離p的長度時，\n我們可以將left和right各自往右移動一格 。\n同時left移出\n舉例來說假設：\ns: “ecba ebabac d” p: “abc” (這邊將Example 1前面多加一個字元比較容易看出不同)\n(left, right, cnt) : (0, 0, 3) -\u0026gt; (0, 1, 3) -\u0026gt; (0, 2, 2) -\u0026gt; (0, 3, 1)\n沿路會檢查\u0026rsquo;e\u0026rsquo;, \u0026lsquo;c\u0026rsquo;, \u0026lsquo;b\u0026rsquo;，每次碰到的字母會從p的hash table中扣掉，\n不過cnt這樣只會降到1，表示沒有成立anagram 。 (left, right, cnt) : (0, 3, 1) -\u0026gt; (1, 4, 0)\n將left往右移一格，’e’就出範圍外了(hash table要加回來)，\n接著right往右移一格，’a’進入範圍內，且符合p的hash table擁有的子母，\n所以cnt會從1降為0，同時範圍長度相符，\n表示這是其中一個解，將1加入到我們的答案範圍中。 (left, right, cnt) : (1, 4, 0) -\u0026gt; (2, 5, 1) -\u0026gt; (3, 6, 2) -\u0026gt; (4, 7, 3)\n依序移出範圍，如果發現加上去前hash table該值有≥0的話，\n表示有移出p原有的字母，所以我們要將cnt進行遞增。 (left, right, cnt) : (4, 7, 3) -\u0026gt; (5, 8, 2) -\u0026gt; (6, 9, 1) -\u0026gt; (7, 10, 0)\n同樣經歷了一個cnt等於0且長度等於p的範圍，\n將7 加入答案當中。 (left, right, cnt) : (8, 11, 1) -\u0026gt; right超過，停止檢查。 所以按上面這個範例的output就會是[1, 7]。\n這個題目由於我們中途開始的left和right呈現一個固定距離的狀態，\n只是隨著遞增滑動 ，所以這種固定窗口大小並且移動的方式，\n一般稱為Sliding Window 。\n(也可以視為Two Pointer在某種狀態的條件限定)\n依此，我們可以寫成程式碼如下：\nJava Java的部分，參考了一位leetcode上的解法，\n我們使用一個ArrayList來儲存我們的答案，\n並且前期的檢查可以分別檢查s, p是否為null或空，\n以及s的長度不能小於p的長度才行(不然要怎麼組對吧XD)\n接著，我們使用一個長度26的一維陣列，\n也可以使用ASCII長度256直接存，我們使用26的長度時，\nindex使用c-’a’即可對應。\n初始化left, right, count後，迴圈條件設定為right還沒有超出去範圍。\n迴圈內的判斷式則利用++和\u0026ndash;的特性，\n(放後面時會先進行完整個操作才遞增/遞減)，\n其他的重點做法跟前面的描述是一樣的，\n讀者可以再自己嘗試在紙上推導一次，會更加清楚。\nPython Python的部分我們示範使用字典來處理，\n由於我們不想要每次在取值時都先檢查值有沒有存在的問題，\n(不論是get或者是用[]取值，字典都不會有預設值)\n所以這邊先行將26個字母的對應都置入0，後續就不需要再檢查了。 其它的部分跟Java的寫法基本相同，只是沒有++跟- -能用而已XD!\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，\n空間複雜度如果要算上答案的部分的話則為O(N)，N為s的長度)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-05-24T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-94-hash-table-10/","title":"從LeetCode學演算法 - 94 Hash Table (10)"},{"content":"0687. Longest Univalue Path (Easy)\nQuestion Given a binary tree, find the length of the longest path where each node in the path has the same value. This path may or may not pass through the root.\nThe length of the path between two nodes is represented by the number of edges between them.\nExample 1 Input:\n1 2 3 4 5 5 / \\ 4 5 / \\ \\ 1 1 5 Output: 2\nExample 2 Input:\n1 2 3 4 5 1 / \\ 4 5 / \\ \\ 4 4 5 Output: 2\nNote: The given binary tree has not more than 10000 nodes. The height of the tree is not more than 1000.\n分析/解題 給定一個二元樹，尋找其最長的路徑長，\n當中的所有節點必須擁有相同的值。\n這條路徑通過或沒有通過根節點均可。\n(路徑長度的定義為兩個節點之間經過的邊(edge)的數量)\n由於很早我們就介紹過樹的基本性質了，\n(印象模糊的讀者請回頭參照0100. Same Tree)，\n在此就不再贅述。這題嘗試要找相同值的路徑，\n但又不限定要通過root，該怎麼思考呢？\n我們可以先考慮怎樣可以算一條相同值的路徑 。\n一條相同值的路徑有可能有以下兩種狀況：\n從一個頂點下來，\n每次選擇往左節點走或往右節點走，到一個位置停下。\n例如： 1 2 3 4 5 5 / \\ 4 5 / \\ \\ 1 1 5 當中的5-5-5就是一條相同值的路徑。\n從一個頂點進行分岔，左右各自走到一個位置停下。\n例如： 1 2 3 4 5 4 / \\ 4 5 / \\ \\ 4 4 5 當中的粗斜體的4-4-4 就是一條從頂點往左右分岔所得到的路徑，\n可以選擇從左下的4 -\u0026gt; 中間的4 -\u0026gt; 再到右邊的4 ，這樣連成一個路徑。\n但從這邊來看可以發現，這條路徑就無法把root的4算在內，\n因為不管怎麼連，我們都沒辦法一筆不重複將這4個4走完。\n因此，我們可以得知：\n對於某個節點來說，有經過它所能得到的最長路徑，\n有可能是從它的上面連下來(分岔點在它的上面 )，\n也可能是以它自己為分岔點 ，左右各自找完和它值相同的節點路徑。\n在第一個情況來說，要求它的上一個節點值和它的值相同；\n第二個情況來說，則要將左右和它的值相同的路徑長相加 。\n所以我們可以定義一個count函式，\n回傳以某個節點值來說，其下的最長所能得到的相同值的路徑長，\n當中計算的時候一邊留意當下最長的路徑長並進行更新。\n我們將整個題目的答案(相同值的最長路徑長)叫做mx(叫result也可以)，\n流程順序應為：\n一開始應該先檢查root是否為NIL ，\n如是，回傳0 (因為沒有路徑)，否則呼叫count函式，\n檢查它所能得到的相同值的最長路徑長 。\n(傳入root節點，及當下的路徑節點值root.val ) 在count當中，\n同樣應先檢查傳入的節點值是否為null，\n接下來為了要知道左右路徑的相同值的最長路徑長，\n應該要分別帶入其left/right節點及當前節點的值 進去檢查，\n假設得到的結果分別為l/r 。 依照2的定義，l + r的值代表了一條可能的相同值路徑，\n所以要拿它和mx比較，將較長的路徑值更新。 如果當前的節點值 和**傳進來的路徑節點值兩者相同，\n代表有機會可以考慮上面提到過的\n「從一個頂點下來，每次選擇往左節點走或往右節點走，\n到一個位置停下。」的狀況，\n這時候要回傳的值會是左右路徑長較長的部分+1。\n(因為要包含左節點/右節點到當前節點的這個路徑) 上面的判斷不成立的話，代表路徑從上面下來到這邊斷掉了。\n(值不相同)，這時候應該回傳0，代表相同值路徑到這邊沒辦法繼續。** 上面的流程順序，請讀者務必自行畫圖推導，\n會比較清楚整個思考過程。\n依此，寫成程式碼如下：\nJava Java的部分mx直接宣告一個class變數即可，其它就是使用Math.max，\n及檢查null的部分，並不複雜。\nPython Python的話，可以使用self.mx來宣告，\n並且在__init__時進行處理，\n其它就是一樣注意呼叫時不要忘記用self 即可。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，如果空間要算上call stack的部分的話，\n則是O(TreeNode的高度)。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-05-10T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-93-tree-12-dfs-9/","title":"從LeetCode學演算法 - 93 Tree (12) / DFS (9)"},{"content":"0680. Valid Palindrome II (Easy)\nQuestion Given a non-empty string s, you may delete at most one character. Judge whether you can make it a palindrome.\nExample 1 1 2 Input: \u0026#34;aba\u0026#34; Output: True Example 2 1 2 3 Input: \u0026#34;abca\u0026#34; Output: True Explanation: You could delete the character \u0026#39;c\u0026#39;. Note:\nThe string will only contain lowercase characters a-z. The maximum length of the string is 50000. 分析/解題 給定一個非空白的字串s，最多可以從當中刪除掉一個字元，\n試判斷你能否讓這個字串變成一個回文。\n回文(Palindrome)先前已經介紹過了 ，\n就是符合「從尾到頭和從頭到尾看起來相同」即可，\n所以它可以是像是abcba 的形式(中間有一個單獨的字元)，\n或者是abba (成對兩兩相對)，這個概念在很多回文的題目都有用到，\n讀者可以多加留意。\n假設今天不能刪除任何字元的話，\n問題就會直接變成檢查字串是否是回文，\n那麼我們就可以直接設定兩個index i, j，\n當中i從0開始遞增，j從s.length()-1(或len(s)-1)開始遞減 ，\n依序對照對稱的位置檢查字元是否相等 即可。\n(檢查到i, j交會都還兩兩對稱相等，則為回文)\n好，那麼問題來了：\n如果原先不是回文，需要刪掉一個字元才能變成回文呢？\n該刪哪個？\n有一句話說得好：\n「解決不了問題，就解決產生問題的人」(大誤)，\n既然我們只有一個可以刪的空間，\n那麼就只能等到有無法對應到的狀況才處理。\n舉例來說：\nabcce ba -\u0026gt; a-a, b-b, 在c-e這個地方沒有對應到，\n那麼有可能是c有問題，也有可能是e有問題，\n所以我們可以分成刪掉c或刪掉e的狀況來檢查。\n(因為實際上我們不會預先知道是誰有問題，也有可能都有問題)\n也就是說，\n當i, j沒辦法對應到時，我們可以選擇略過i 的位置上的字元，\n或者略過j 的位置上的字元。(因為只是要檢查，所以不用真的作刪除)\n略過i 的話，我們就要嘗試拿i+1來和j做對應 ；\n略過j 的話，則是拿i和j-1做對應 。\n剩下的狀況，就是按照前面一般檢查回文的流程依序檢查，\n只要這兩條路其中一種 可以讓s變為回文，答案就會是true 。\n那麼，如果又碰到沒對應到的呢？\n那我們就只能說抱歉了XD~\n我們已經用掉了一次刪除的機會，\n後面再碰到對應不上的，當然就是不能成為回文囉！\n所以這題看似會產生分支，其實只會產生一次而已，\n因為我們只能刪一次而已，所以這題的時間複雜度並不高。\n依此，我們寫成程式碼如下：\nJava Java的部分求方便起見，使用了toCharArray()，\n我們將後續略過1個字元檢查的函式稱為isp(isPalindrome)，\n當validPalindrome內的迴圈檢查到不符合的時候，\n便呼叫isp來分支檢查；進入isp時，則只有所有剩下的字元兩兩對應，\n才會回傳true，否則一定會回傳false。\nPython Python的部分，一樣不要忘記被用到的子函式要先宣告在前面，\n其它和Java的解大同小異。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(len(s))/O(1)，\n由於最多分支就只有一次，\n所以總體的複雜度還是跟字串長有關；\nJava的部分因為偷懶使用toCharArray()，\n所以空間複雜度也是O(len(s))，願意節省一點的話，\n也可以用CharAt()來取得某個位置的字元。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-05-03T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-92-string-5/","title":"從LeetCode學演算法 - 92 String (5)"},{"content":"0678. Valid Parenthesis String (Medium)\nQuestion Given a string containing only three types of characters: ‘(‘, ‘)’ and ‘*’, write a function to check whether this string is valid. We define the validity of a string by these rules:\nAny left parenthesis '(' must have a corresponding right parenthesis ')'. Any right parenthesis ')' must have a corresponding left parenthesis '('. Left parenthesis '(' must go before the corresponding right parenthesis ')'. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string. An empty string is also valid. Example 1 1 2 Input: \u0026#34;()\u0026#34; Output: True Example 2 1 2 Input: \u0026#34;(*)\u0026#34; Output: True Example 3 1 2 Input: \u0026#34;(*))\u0026#34; Output: True Note: The string size will be in the range [1, 100].\n分析/解題 給定一個字串，當中僅含三種字元：\u0026rsquo;(\u0026rsquo;, ‘)’, ‘*’ (左括號，右括號及米字號)，試寫一個函式以檢查這個字串是否有效。\n一個字串要符合以下的規則才算是有效的：\n任一個左括號都要有一個對應的右括號 任一個右括號都要有一個對應的左括號 左括號必須出現在其對應的右括號之前 米字號(*)可以被視為單一個右括號、左括號、或空字串 空字串也是有效的 綜合上面的描述，我們可以知道像是：\n‘)(’ -\u0026gt; 右括號還沒對應就出現在左括號前所以是False；\n但像是‘(()()*)’ 就會是True，\n仔細觀察可以發現，如果我們先不考慮米字號的部分，\n從左到右，左括號出現的次數必然 \u0026gt;= 右括號出現的次數。\n(因為要兩兩相對應，且右括號不能還沒對應到就出現在左括號之前)\n所以，如果是沒有米字號的話，這題會相當簡單：\n定義一個cnt(初始值為0)，由左至右，\n每次碰到左括號則+1，右括號則-1 ，中間如果cnt變為負數 ，\n則代表有右括號還沒對應到就出現了 ，則有效性是False ；\n而遍歷整個字串到結尾時，\n如果cnt變為0 的話則有效性是True (剛好所有括號兩兩對應)，\n否則則為False (還有未對應到的括號)。\n那麼，加上米字號的話該怎麼辦呢？\n我們可以先將所有的米字號當成左括號來用 ，\n由左至右檢查是否左括號足夠配對右括號完還有剩。\n假設中途左括號不夠的話 ，肯定是False (因為加上米字號都不夠用)；\n配對完剛好用完 -\u0026gt; ** True**(因為所有的米字號全拿來當左括號剛好OK)\n配對完左括號還有剩 呢？\n這時候我們應該從右至左， 換成將所有的米字號當成右括號來用，\n換成檢查右括號足不足夠配對。\n中途右括號不夠 -\u0026gt; False；\n最後如果右括號數量足夠的話，則為True。\n最後一段我們需要更仔細的考慮原因：\n有沒有可能在由左至右留下來多出來的部分是左括號呢？\n答案是否定的，因為如果是這樣的話，這些多出來的部分，\n在反方向的時候會因為它們不是米字號，使得右括號的數量不夠用 ，\n從而讓中途不足以配對 的狀況發生。\n所以要嘛就是剛好完全配對 ，不然的話，就是剩下的全都是米字號 ，\n這樣反向時才有辦法處理。\n所以，當雙向都能夠順利滿足的時候，\n只要將多出來的米字號視作空字串，就能使整個字串得以滿足有效性了！\n依照上面的邏輯，我們可以進行 two pass 經過整個字串，\n完成整個檢查工作，其空間複雜度為O(1)，時間複雜度為O(n)。\n(n為字串的長度)\n寫成程式碼如下。\nJava Java的部分，使用charAt()來取得特定index的字元，\n並分別設定l跟r變數來計算。(要設成同一個cnt變數也行，自己歸零即可)\nPython Python的部分，這邊使用三元運算子處理。\n此外，如果不想用index一個一個數的話，\n用for c in s以及for c in reversed(s)也可以。\n讀者可能會留意到註解裡有附註了lee215的one pass解法 ，\n有興趣的可以再深入了解。具體的思路是記錄從左至右途中，\n我們現在需要等待多少右括號來將一組括號完整；\ncmax 是將所有碰到的*都當作是左括號 處理，\n(也就是最大可能 會產生尚未配對的左括號數量)\n而cmin 是中間能消去配對的狀況就消去 。\n(也就是最少一定 要被配對完成的左括號數量)\n按這個條件的話，cmax必然要一直\u0026gt;=0，\n且cmin再結尾時要剛好是0才可以。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n)/O(1)，n為字串長度，空間不論是哪種方式都只需常數大小)\n「如果不管空間複雜度，你能使用stack來解這題嗎？」\n(可以做配對然後將成對的括號吐掉，\n具體可以參考以下幾個discussion的解法。\nJava: https://leetcode.com/problems/valid-parenthesis-string/discuss/107572/Java-using-2-stacks.-O(n)-space-and-time-complexity.\nPython: https://leetcode.com/problems/valid-parenthesis-string/discuss/145228/python-using-stack-20ms-beats-100-probably-the-easiest-solution)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-04-19T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-91-string-4/","title":"從LeetCode學演算法 - 91 String (4)"},{"content":"0576. Out of Boundary Paths (Medium)\nQuestion There is an m by ** n** grid with a ball. Given the start coordinate ** (i,j)** of the ball, you can move the ball to an ** adjacent** cell or cross the grid boundary in four directions (up, down, left, right). However, you can ** at most** move ** N** times. Find out the number of paths to move the ball out of the grid boundary. The answer may be very large, return it after mod 10⁹ + 7.\nExample 1 1 2 3 Input: m = 2, n = 2, N = 2, i = 0, j = 0 Output: 6 Explanation: Example 2 1 2 3 Input: m = 1, n = 3, N = 3, i = 0, j = 1 Output: 12 Explanation: Note:\nOnce you move the ball out of the boundary, you cannot move it back. The length and height of the grid are in the range [1,50]. N is in range [0,50]. 分析/解題 題目描述有一組 m * n 的方格，格子上有一個球，其起始座標為 (i, j)，\n你可以將球移到四個方向內沒超過邊界的格子，但最多只能移動N次。\n試算出所有會將球移超過邊界的路徑數目。\n限制：\n一旦移出邊界就不能再回來(也就是直接遊戲結束了) 格子的寬高均在1~50的範圍 總次數N在0~50的範圍\n另由於答案可能非常大，回傳結果要先除以10的9次方+7。 我們先思考關於路徑超過邊界的狀態。\n要被算做是其中一種的話，首先最後一步一定要是從格子內移到格子外 ，\n也就是要在邊界才可以，只差一格index就小於0 或**\u0026gt;m-1** (或n-1 )。\n畢竟不在懸崖邊怎麼可能會有掉下懸崖的可能對吧XD！\n並且，因為掉下去就回不來了 ，所以路徑就會到此為止。\n(當然不管剩下的步數，你總不會飛簷走壁吧@@)\n接著，當 N=0 時，\n由於根本沒辦法動，自然不會有符合的路徑 ，答案為0。\nN = 1 時，則要** 看你四邊有幾個懸崖對吧！\n那N = 2呢？\n是不是就要先看這一步有幾種可能會掉下去，加總起來以後** ，\n接下來先走到不會掉下去的地方，再看那幾個有幾種情況會掉下去。\n由於每走一步路，可用的步數就會少1，\n我們終究會要嘛掉下去 ，要嘛走到沒有步數可用；\n將所有加總起來，就得到答案了。\n這個方式聽起來很DFS對吧？\n所以按照上面的直覺，也許你會寫成像這樣子的內容：\n1 2 3 4 5 6 7 8 9 10 11 12 13 # Will TLE class Solution: def findPaths(self, m: int, n: int, N: int, i: int, j: int) -\u0026gt; int: def dfs(i, j, N): res = 0 if N != 0: res += 1 if i - 1 \u0026lt; 0 else dfs(i-1, j, N-1) res += 1 if i + 1 == m else dfs(i+1, j, N-1) res += 1 if j - 1 \u0026lt; 0 else dfs(i, j-1, N-1) res += 1 if j + 1 == n else dfs(i, j+1, N-1) return res res = dfs(i, j, N) return res % (10 ** 9 + 7) 當方向會掉下去的時候，就代表方法數加1；\n否則的話，就要往那個方向走1步去算可能的方法。\n你會發現測試一般的結果可以算出正確答案，\n但大一點的數字會算到超時，為什麼呢？\n其實理由跟以前我們算Fibonacci數列時一樣，\n這樣子的寫法會導致每一個數都是從單一個1累加起來的，\n中間我們可能走到同樣的格子，剩下相同的步數，\n卻沒有利用到這點，從而導致效率超級差。\n那怎麼辦呢？\n當我們同時考慮動態規劃的觀念時，\n就容易想到，我們可以將先前算過的東西當成已知的內容儲存起來，\n當再碰到時，就可以直接取用計算。\n在本例當中，影響到結果的值有i, j, N，\n所以我們可以選擇使用一個三維的陣列/串列 ，(也可以用兩個二維陣列)\n或者Python內也可以用字典 來做對應儲存。\n扣除掉這點以外，跟前面的寫法並無不同，讀者可以自行參照看看。\n那麼，有沒有別種思考的方式呢？\n有的，像是lee215就提供了另一種思路：\n我們最開始N=0時，整個盤面不論i, j為什麼，\n(i, j, 0)的結果都會是0，而(i, j, N)的結果，\n則取決於**(i, j)上下左右4格在N-1步的時候** 的結果。\n如果該格超出邊界，則至少從(i, j)有1步可以走出邊界，\n反之，(i, j)可以花1步走過去。\n因此，我們可以一次一次更新整個盤面，\n從而算得第N步的結果。(參見Python lee215解 )\n或者，我們也可以從i, j為起點，\n記錄從i, j到某一格的總路徑數量 ，\n每當有機會超出邊界時，則將該部分加總到結果中，\n兩個方法殊途同歸，最後都可以得到解答。(參見Java shawngao解)\n依照上面的這些想法，我們可以寫成解答：\nJava 在Java的部分，除了上面提過的遞進計算整個盤面，\n(使用兩個二維陣列交替)\n也可以用三維陣列去記錄結果，\n留意為了要偵測是否有記錄結果，\n我們要用Arrays.fill()，將初始化的陣列都填入-1，\n這樣我們才知道這個值它是0還是未填入的狀態。\nPython Python的部分，除了lee215的解法外，\n我們也可以如上面提到的採用一個字典來進行儲存先前已計算過的內容。\n此外，由於在這個問題中，\n鏡像對稱位置的點在相同的N值下應該會有相同的答案，\n所以還可以透過對稱的方式來進一步化簡所需的計算數量。\n(可以看註解底下最後一個解，65~69行的部分)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(時間複雜度方面，原則上最壞的狀況就是每個步驟算完整個盤面，\n所以會是O(m*n*N) 。\n空間複雜度的話，使用三維陣列或字典 的話是O(m*n*N) ，\n而使用兩個二維陣列交替記錄 的話則是O(m*n) )\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-03-22T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-90-dynamic-programming-11-dfs-9/","title":"從LeetCode學演算法 - 90 Dynamic Programming (11) / DFS (9)"},{"content":"1346. Check If N and Its Double Exist (Easy)\nQuestion Given an array arr of integers, check if there exist two integers N and M such that N is the double of M ( i.e. N = 2 * M).\nMore formally check if there exist two indices i and j such that :\ni != j 0 \u0026lt;= i, j \u0026lt; arr.length arr[i] == 2 * arr[j] Example 1 1 2 3 Input: arr = [10,2,5,3] Output: true Explanation: N = 10 is the double of M = 5,that is, 10 = 2 * 5. Example 2 1 2 3 Input: arr = [7,1,14,11] Output: true Explanation: N = 14 is the double of M = 7,that is, 14 = 2 * 7. Example 3 1 2 3 Input: arr = [3,1,7,11] Output: false Explanation: In this case does not exist N and M, such that N = 2 * M. Constraints 2 \u0026lt;= arr.length \u0026lt;= 500 -10^3 \u0026lt;= arr[i] \u0026lt;= 10^3 分析/解題 給定一組整數陣列，檢查當中是否存在兩個數N, M使得N = 2 * M。\n(留意不可使用重複的index)\n乍看之下有沒有覺得一陣熟悉？\n沒錯，LeetCode最開始的第一題0001.Two Sum 的套路，\n跟這個非常的相似，只不過從兩數相加等於固定數，\n變成一個是另一個的兩倍。另一方面，我們只要將存在與否輸出，\n所以不用記錄是什麼配對 。\n那麼，按照先前的做法，我們需要做的事情是：\n檢查現在的值有沒有符合之前的配對 ，若有，就直接回傳True即可。\n(先前使用HashMap/Dictionary，這次可以使用HashSet/Set) 將當前的值對應到的配對 擺進Set當中，\n由於當前的值x對應到之後的y有可能是 x = 2 * y 或 y = 2 * x，\n所以我們要一次將兩種可能都放進去。\n這樣子整個Set的總大小會變成2N，但不會影響檢查速度。\n(因為HashSet/Set同樣是使用hash function的機制) 全部檢查完，仍然沒有符合的狀況，則回傳False。 依此，寫成程式碼如下：\nJava Java的部分，由於限制資料型態，\n要留意處理除以2的部分，不能讓它自動做整數除法，\n所以先檢查能否被2整除，可以的狀況才將其加入Set中 。\n(使用HashSet ，檢查是否存在值使用contains() ，add() 來加入元素)\nPython Python的部分，由於/2直接會變成float，沒有特別被限制，\n我們可以直接選擇加入而略過檢查的部分。\n(反正小數點也不會被對到嘛XD)\n(使用set() 開一個Set，in / not in 來檢查，並用update 來加入多個元素)\n(先處理存在或先處理不存在的狀況都可以，看自己的喜好)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，記得乘以2倍空間上是常數，不要講O(2N)歐XD)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-03-01T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-89-hash-table-9/","title":"從LeetCode學演算法 - 89 Hash Table (9)"},{"content":"0575. Distribute Candies (Easy)\nQuestion Given an integer array with ** even** length, where different numbers in this array represent different ** kinds** of candies. Each number means one candy of the corresponding kind. You need to distribute these candies ** equally** in number to brother and sister. Return the maximum number of ** kinds** of candies the sister could gain.\nExample 1 1 2 3 4 5 6 Input: candies = [1,1,2,2,3,3] Output: 3 Explanation: There are three different kinds of candies (1, 2 and 3), and two candies for each kind. Optimal distribution: The sister has candies [1,2,3] and the brother has candies [1,2,3], too. The sister has three different kinds of candies. Example 2 1 2 3 4 Input: candies = [1,1,2,3] Output: 2 Explanation: For example, the sister has candies [2,3] and the brother has candies [1,1]. The sister has two different kinds of candies, the brother has only one kind of candies. Note:\nThe length of the given array is in the range [2, 10,000], and will be even. The number in given array is in range [-100,000, 100,000]. 分析/解題 給定一個偶數長度的整數陣列，當中不同的數字代表不同種類的糖果。\n你要將糖果平分給一對兄妹(姐弟)，試算出當中姐姐/妹妹最多能拿到幾種不同種類的糖果。\n什麼？題目也偏女生嗎(大誤)\n題目內文基本上已經講得相當清楚了，\n接下來問題就來到究竟我們要怎麼知道種類有多少種不同呢？\n首先，如果每顆糖果都不同種類，女生最多能拿的也只有一半 ，\n所以能拿到的種類上限會受限於candies的總數除以2 。\n這個是大前提，我們先將它放在一邊。\n那麼，如果種類總數比candies總數的一半小 呢？\n簡單的想法就是發糖果的時候，每次遇到沒看過的種類，\n就先記起來，藉此將整個種類數計數過一遍。\n(或者你也可以想成每次看到沒看過的種類 要優先給女生，\n給到女生拿滿 或沒有新的種類 為止，兩個思考的模式和條件其實差不多。)\n要記錄某種糖果的出現數量，\n自然會想到HashTable/HashSet/Dictionary這類的東西，\n但由於題目有提到種類是從-100000~100000，\n所以其實我們可以開出一個長度為200001的陣列/串列，\n直接當成Hash Table來使用，只要位移個100000即可。\n(陣列/串列要從0開始)\n因此，我們每次就可以從candies中依序取出一個數字，\n將Hash Table內的對應位置進行遞增，再看看加完後是否剛好是1，\n是1就代表這是新種類的糖果，所以要將種類的變數加1。\n最後再回頭比較種類的數量，跟糖果的總數的一半，\n選擇較小的進行回傳即可。\n依此，寫成程式碼：\nJava Python的部分，我們也可以用set的方式取得不重複的種類，\n再取其len()即可得到不重複的種類數量。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，如果將空間固定成題目給定的限制的話，\n會固定要開出一個200001的空間，這個可以再直接用說的。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-02-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-88-hash-table-8/","title":"從LeetCode學演算法 - 88 Hash Table (8)"},{"content":"1342. Number of Steps to Reduce a Number to Zero (Easy)\nQuestion Given a non-negative integer num, return the number of steps to reduce it to zero. If the current number is even, you have to divide it by 2, otherwise, you have to subtract 1 from it.\nExample 1 1 2 3 4 5 6 7 8 9 Input: num = 14 Output: 6 Explanation: Step 1) 14 is even; divide by 2 and obtain 7. Step 2) 7 is odd; subtract 1 and obtain 6. Step 3) 6 is even; divide by 2 and obtain 3. Step 4) 3 is odd; subtract 1 and obtain 2. Step 5) 2 is even; divide by 2 and obtain 1. Step 6) 1 is odd; subtract 1 and obtain 0. Example 2 1 2 3 4 5 6 7 Input: num = 8 Output: 4 Explanation: Step 1) 8 is even; divide by 2 and obtain 4. Step 2) 4 is even; divide by 2 and obtain 2. Step 3) 2 is even; divide by 2 and obtain 1. Step 4) 1 is odd; subtract 1 and obtain 0. Example 3 1 2 Input: num = 123 Output: 12 Constraints 0 \u0026lt;= num \u0026lt;= 10^6 分析/解題 給定一個數字num，回傳其化簡至0所用的步驟數。\n化簡的方法為：\n若num此刻為偶數，將其除以2；若num此刻為奇數，將其減去1。\n這題如果按照題目的條件一步一步走的話，\n以二進位制來看，\n我們會發現當尾端的bit是1時，就必須減去1並除以2 ，\n也就是向右位移一個bit(這整件事情耗費了2步 )；\n若bit是0時，則只需要除以2即可。\n所以一個很簡單且直觀的寫法，就是利用迴圈，\n當num還大於0時，檢查尾數的bit(可以用num \u0026amp; 1取得尾數是0或1)，\n你可以用三元運算子 ，或者直接**(num \u0026amp; 1) + 1** 亦可，\n請注意由於**\u0026amp;運算子的優先序較低** ，務必將num和1用括號包起來！\n一路做到最後一個1，最後num等於0時就完成了。\n(因為最後一個1不用再位移了，所以我們加總起來的步數最後要減去1)\n這裡提供另一個想法：\n當我們沒有限制計算bitCount的函式及轉換二進位/字串時，\n可以推想到：\n所有1都必須被消成0 (每個bit \u0026lsquo;1\u0026rsquo;會耗費1步) 要除以幾次2，端看最高位的1離個位數有多遠\n(轉成二進位的總長減去1等於總共要除以2的次數) 所以我們得到： 答案 = num的bit ‘1’數量 + num的長度 - 1\n依此，寫成程式碼如下：\nJava Java的部分，我們可以利用bitCount和toBinaryString來達到要求。\n(一步一步算的也有列出參考解，讀者可以自己試看看)\nPython Python的部分，由於bin()轉二進位時，前面會多出**’0b’** ，\n所以計算長度時會多出2，後面的減1就會變成需要改成減3 ，\n請再留意。其他跟Java大同小異。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(logN)/O(1)，但因為num最高就是10^6而已，如果你要宣稱num是constant，因此時間複雜度當成O(1)，個人覺得也是合理的。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\nFrom Cheng Rui Xie :\n位元運算有很多有趣的 function 可以呼叫：\n回傳以二為底的次方項：__lg(num)\n回傳數字二進位後1的個數：__builtin_popcount(num)\n只要取兩個的和即可且運算的時間＝O(1) (這個想法的O(1)也是將num當限定大小看待。)\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-02-11T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-87-bitwise-operation-6/","title":"從LeetCode學演算法 -  87 Bitwise Operation (6)"},{"content":"1331. Rank Transform of an Array (Easy)\nQuestion Given an array of integers arr, replace each element with its rank.\nThe rank represents how large the element is. The rank has the following rules:\nRank is an integer starting from 1. The larger the element, the larger the rank. If two elements are equal, their rank must be the same. Rank should be as small as possible. Example 1 1 2 3 Input: arr = [40,10,20,30] Output: [4,1,2,3] Explanation: 40 is the largest element. 10 is the smallest. 20 is the second smallest. 30 is the third smallest. Example 2 1 2 3 Input: arr = [100,100,100] Output: [1,1,1] Explanation: Same elements share the same rank. Example 3 1 2 Input: arr = [37,12,28,9,100,56,80,5,12] Output: [5,3,4,2,8,6,7,1,3] Constraints 0 \u0026lt;= arr.length \u0026lt;= 10^9 -10^9 \u0026lt;= arr[i] \u0026lt;= 10^9 分析/解題 給定一個陣列，將其依照大小順序排出rank。\n(由1開始，大小相同則相同rank，數字越大，其rank則越大)\n由於我們需要按照大小相同來排定rank，所以顯然我們需要將其排序後，\n才能知道誰應該在第幾個。對於這樣子的題目，\n一般而言我們不需要自己實作排序的過程，除非面試官要求，\n否則說明清楚你使用了排序即可；\n不要忘記對於沒有特別安排的資料結構，\n一般程式語言所使用的排序法基本上都是O(N log N) 的時間複雜度，\n所以最後在問複雜度時記得納入考量。\n既然我們需要取代原先的陣列，所以我們必須另外增加一組記憶體空間，\n用來存放排序的狀態。存放好以後，應該要怎麼去記錄呢？\n由於相同的數字要擁有相同的rank，對於存取和讀出擁有最快的複雜度的，\n就是Hash Table了！我們可以先檢查當下該數字是否已經放入對應 ，\n若還沒有放入對應，則需要寫入(number, rank)的對應。\n這時候rank是多少呢？應該要將已經置入的配對數量+1 來計算。\n(因為代表現在已經給到多少數量的rank了)\n都放完以後，再依序將陣列中的每個值作為key，\n來從Hash Table得到其對應的rank(value)，再覆蓋掉即可。\n依此，寫成程式碼：\nJava Java在增加新的記憶體儲存一份陣列時，可以使用Arrays.copyOf() 。\n(後面加length可以指定複製的總長度)\n使用HashMap來進行存放，並且用putIfAbsent(key, value) ，\n僅在不存在對應時才進行寫入。\n最後再利用HashMap.get()來一一取得對應rank並寫入。\nPython Python的部分，我們可以直接使用sorted(arr)取得一份新的串列。\n也可以使用list.copy() 或者arr[:] 的方式來取得複製的串列。\n請注意 \u0026ldquo;sArr = arr\u0026rdquo; 和 \u0026ldquo;sArr = arr[:]\u0026ldquo;意義上是不同的，\n後者才是完整複製一份arr的串列 ，前者是新增了一個變數名稱，\n但其記憶體位址依舊是指向到arr的！(也就是後者並沒有進行複製)\nJava中使用HashMap，在Python中則用Dictionary達到，\n而對應到putIfAbsent的函式則是setdefault 。\n(也可以用if ** a not in rk: rk[a] = len(rk) + 1**)\n最後，使用map函式來一一得到arr對應到rk.get的內容。\n(即每次從arr依序取出元素再代入到rk.get內)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(NlogN)/O(N))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-02-05T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-86-hash-table-7/","title":"從LeetCode學演算法 -  86 Hash Table (7)"},{"content":"1332. Remove Palindromic Subsequences (Easy)\n寫在前面 Question Given a string s consisting only of letters 'a' and 'b'. In a single step you can remove one palindromic subsequence from s.\nReturn the minimum number of steps to make the given string empty.\nA string is a subsequence of a given string, if it is generated by deleting some characters of a given string without changing its order.\nA string is called palindrome if is one that reads the same backward as well as forward.\nExample 1 1 2 3 Input: s = \u0026#34;ababa\u0026#34; Output: 1 Explanation: String is already palindrome Example 2 1 2 3 4 Input: s = \u0026#34;abb\u0026#34; Output: 2 Explanation: \u0026#34;abb\u0026#34; -\u0026gt; \u0026#34;bb\u0026#34; -\u0026gt; \u0026#34;\u0026#34;. Remove palindromic subsequence \u0026#34;a\u0026#34; then \u0026#34;bb\u0026#34;. Example 3 1 2 3 4 Input: s = \u0026#34;baabb\u0026#34; Output: 2 Explanation: \u0026#34;baabb\u0026#34; -\u0026gt; \u0026#34;b\u0026#34; -\u0026gt; \u0026#34;\u0026#34;. Remove palindromic subsequence \u0026#34;baab\u0026#34; then \u0026#34;b\u0026#34;. Example 4 1 2 Input: s = \u0026#34;\u0026#34; Output: 0 Constraints 0 \u0026lt;= s.length \u0026lt;= 1000 s only consists of letters \u0026lsquo;a\u0026rsquo; and \u0026lsquo;b\u0026rsquo; 分析/解題 給定一個字串，當中僅由\u0026rsquo;a\u0026rsquo;或\u0026rsquo;b\u0026rsquo;的字母所構成，每次你可以從中移除一個palindrome subsequence. 試回傳將該字串刪成空字串所需的最小步數。\n我們先前有講過subsequence的定義，可以參照之前的題目 。\n所以每次要移除掉一個subsequence且必須符合palindrome的條件，\n乍看之下似乎不容易。\n但選這題的目的就是要告訴大家，有時候事情並沒有想像中那麼複雜，\n靜下心來好好推敲，可能可以找到適合的規律，\n不要急著找通解，先試著去用上所有已知的條件 看看才對！\n我們知道subsequence就是按照排列的先後順序取就可以了，\n但palindrome(回文) 則必須取出來從頭到尾和從尾到頭一致才行。\n我們先考慮最簡單的部分，再慢慢往下推。\n1. 當字串是空白的時候：\n不需操作 即可達到條件，所以總step為0。\n2. 當字串本身就是palindrome：\n把整個字串做為subsequence移除，所以總step為1。\n接下來是最重要的部分，\n如果字串本身不是palindrome的話，\n要怎麼樣才會移除一個palindrome sequence後，\n可以用最小步數化簡呢？\n由於s僅僅由’a’和’b’所組成 ，\n所以我們可以考慮直接移去全部的\u0026rsquo;a\u0026rsquo;或全部的\u0026rsquo;b\u0026rsquo;，\n由於全部都是\u0026rsquo;a\u0026rsquo;或全部都是\u0026rsquo;b\u0026rsquo;也是一種palindrome，\n所以符合前面移除的規則；\n而剩下來的就全部都是另外一種字元，\n同樣也構成palindrome。\n因此，最多只要2個step，就能全數移完。\n(想一下，如果今天是有N種不同的字元構成s，\n最多就會需要N個step，但這只是上限而已，而不是minimum steps。)\n有興趣寫更細的話，可以用two pointer來寫這題的檢查palindrome的部分，\n這裡就直接用簡單的操作處理。\nJava Java的部分，操作reverse 要使用StringBuilder 來處理，\n處理完以後，再轉回String。\nPython Python的部分更精簡，使用**[::-1]** 即可表達從尾到頭 的部分。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，若願意一個一個字元比較的話，\n空間複雜度也可以降到O(1)，也就是用簡單的two pointer處理即可)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-01-30T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-85-string-3/","title":"從LeetCode學演算法 - 85 String (3)"},{"content":"0116. Populating Next Right Pointers in Each Node (Medium)\nQuestion You are given a perfect binary tree where all leaves are on the same level, and every parent has two children. The binary tree has the following definition:\n1 2 3 4 5 6 struct Node { int val; Node *left; Node *right; Node *next; } Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.\nInitially, all next pointers are set to NULL.\nFollow up:\nYou may only use constant extra space. Recursive approach is fine, you may assume implicit stack space does not count as extra space for this problem. Example 1 1 2 3 Input: root = [1,2,3,4,5,6,7] Output: [1,#,2,3,#,4,5,6,7,#] Explanation: Given the above perfect binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B. The serialized output is in level order as connected by the next pointers, with \u0026#39;#\u0026#39; signifying the end of each level. 分析/解題 給定一個完美二元樹(perfect binary tree)，\n也就是所有葉子都在相同level且所有父節點均有兩個子節點。\n在Node的定義中增加一個next的定義，\n如圖所示，每個節點的next為其右邊的節點，\n如右邊已無節點，則為NULL。\n(最開始的時候預設所有節點的next均為NULL)\n請把整個next的定義完成。\n由於這個題目已經有提到說只能用常數的額外記憶體空間了，\n但同時將遞迴導致的stack(也就是call stack)當作不算，\n所以使用簡單的遞迴可以簡單達到目的。\n最直觀的方式，就是先檢查root是否是null，\n接下來呼叫一個helper function，代入左節點和右節點來處理，\n只要左節點不是NULL，則將左節點的next設為右節點；\n接下來則要分別處理這三個連接：\n1. 左節點的left -\u0026gt; 左節點的right\n2. 左節點的right -\u0026gt; 右節點的left\n3. 右節點的left -\u0026gt; 右節點的right\n當然，也可以從root為中心出發，\n這時候每次要關注的應該是root.left -\u0026gt; root.right，\n及root.right -\u0026gt; root.next.left。\n如果想要用迭代的方式呢？\n我們留意到每次開始進行連接的都是當個階層的最左邊的節點，\n從Figure B 上來看的話，即為1, 2, 4…等節點。\n所以我們最開始應該要從一個階層的最左邊的節點\n(這邊叫做level_first)開始進行迭代，將當前的節點稱為curr\n分別將curr.left -\u0026gt; curr.right 及curr.right -\u0026gt; curr.next.left。\n接著讓curr遞移到curr.next。\n所以每次連接兩組next的關係，直到curr走到NULL為止。\n這時候這層走完以後，進行到下一層，\nlevel_first應該遞移到level_first.left。\n依此，寫成如下的程式碼。\nJava 在Java中，上述三種方法均有列出，\n順序剛好跟上面提到的相反，\n請務必留意在接續前必須要留意要確定節點是否為null的狀況。\n如果計入call stack的話，只有迭代的方式是O(1)才對。\nPython Python的部分大同小異，不要忘記使用self來呼叫，\n這邊僅列出第二種和第三種。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，如果不考慮Call Stack的話。\n如果考慮的話上面只有直接使用迴圈迭代的是O(1))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-01-24T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-84-tree-11-dfs-8/","title":"從LeetCode學演算法 - 84 Tree (11) / DFS (8)"},{"content":"0091. Decode Ways (Medium)\nQuestion A message containing letters from A-Z is being encoded to numbers using the following mapping:\n1 2 3 4 \u0026#39;A\u0026#39; -\u0026gt; 1 \u0026#39;B\u0026#39; -\u0026gt; 2 ... \u0026#39;Z\u0026#39; -\u0026gt; 26 Given a non-empty string containing only digits, determine the total number of ways to decode it.\nExample 1 1 2 3 Input: \u0026#34;12\u0026#34; Output: 2 Explanation: It could be decoded as \u0026#34;AB\u0026#34; (1 2) or \u0026#34;L\u0026#34; (12). Example 2 1 2 3 Input: \u0026#34;226\u0026#34; Output: 3 Explanation: It could be decoded as \u0026#34;BZ\u0026#34; (2 26), \u0026#34;VF\u0026#34; (22 6), or \u0026#34;BBF\u0026#34; (2 2 6). 分析/解題 給定一個訊息，當中A到Z以1至26的方式依序對應，\n用數字的編碼方式寫成一個字串。\n給定這樣子一個僅含數字1~9組成的字串，\n試決定所有可以解碼的方法數。\n這題在LeetCode上面比較有問題的點在於，\n沒有硬性規定開頭或結尾多出來的0 的部分。\n所以這邊我們會再加上一個條件，\n一旦開頭有0或中間有碰到多餘的0 的部分，\n就當作可以接續下去(不當作錯誤)，\n這樣看起來會比較符合測資測出來的結果。\n首先會考慮到就當下而言，如果是空字串的話，\n應該要直接先回傳0**(雖然沒有字串嚴格來說也是1種方法，\n但給題目來說就要代表沒有辦法解碼)。\n如果是考慮每個字串起始檢查的狀況，\n則應該會將起始條件設定為1種可能。**\n接下來我們考慮往下走的時候，怎麼樣可以構成可能的字組呢？\n我們假定從index 0開始的各種子字串，\n均已知有幾種方法了，那麼，當我們在index i的位置時，\n要如何決定到這邊的方法數呢？其實不難思考。\n由於我們的英文字母可能性是從126，\n所以如果**index i對應的值是19之間** 的話，\n代表它獨立可以成為一種可能性，\n也就是走到前面i-1的狀況，再加上i這邊單獨代表的字母 。\n這麼考慮的話走到i的組合數就和走到i-1的組合數是相同的 。\n(以index i位置的值單獨成立的狀況來說)\n那麼還有另一種可能，\n就是index i-1和index i所組成的二位數也能代表字母，\n這個數字應該是10~26 之間，所以這種狀況成立的條件下，\n走到i的組合數和走到i-2的組合數相同 。\n所以歸納上述兩點，我們必須要分別檢查，\n然後決定是否要將i-1的方法數及i-2的方法數加進來。\n感覺是不是有點像之前的House Robber?\n所以這也是一個典型的Dynamic Programming題目。\n依此，我們可以定一個array或list，取名叫dp ，\n長度為s的長度加1。\n我們將可能的兩位數分別叫做prev跟curr，\n那麼每次要作的事情，就如同上面所述一樣：\n初始化dp[0] = 1 , dp[1] = 1 (如果第一個字不是'0\u0026rsquo;) or 0 (如果第一個字是'0\u0026rsquo;) 迴圈讓i從2l，\n每次將curr的值遞移到prev，prev則取得s[i-1] 的值。\n當curr非0 的時候(即19)，我們可以將dp[i-1]加到dp[i] 中；\n當prev和curr 可以組成10~26之間 的值時，可以將dp[i-2]加到dp[i] 中。 迴圈結束後，回傳dp[l] 即可。 依此，寫成程式碼如下。\nJava Java的部分，也可以順便檢查s是否為null，\n但本題的測資似乎也沒有刁難這個部分(題目有說均為數字)。\n檢查10~26 的部分，\n可以拆成(prev==’1’) 或(prev == ‘2’且curr ≤ ’6’) 檢驗。 對Java而言，\nchar可以直接用數字的方式(ASCII Code)的狀態來比大小，\n所以我們不用再轉成Integer來浪費時間XD\nPython Python的部分，也可以直接比大小 ，其實作是呼叫ord()函數，\n來取得比大小所需的ASCII Code數字，\n但就沒辦法像Java的char那樣很多花樣了。\n提醒大家，在寫的時候請務必留意範圍，\n以本題為例，由於dp[0] 是被佔用做為初始值的，\n所以我們在寫的時候i是對應由1為準起算的。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，N為字串長度)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VE9Q5VE**\n","date":"2020-01-15T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-83-dynamic-programming-10/","title":"從LeetCode學演算法 - 83 Dynamic Programming (10)"},{"content":"0086. Partition List (Medium)\n寫在前面 再過兩天就是投票日了，懇請各位讀者們，\n不論支持誰，都要好好地去了解候選人們及政黨的政見，\n在1/11投下您寶貴的一票。**\n筆者在這裡提醒大家去思考一下：\n程式的世界很單純，很多東西不是True就是False，\n而一個按照正常邏輯運行的程式，最終該呈現怎樣的結果，\n大抵都是可以預期的。\n想像一下，如果一個同事常常遲到早退，罔顧專案進度，\n讓大家必須要幫忙收拾爛攤子；\n話說的很滿，遇到事情卻推拖閃躲，\n顧左右而言他的話，相信這樣的人，\n我們不會希望其成為自己的頂頭上司。\n既然如此，我們會希望這種人成為自己的大老闆嗎？\n運用簡單的邏輯思考，相信聰明的各位都能得到正確答案。\n儘管這種人的餅畫得再大再漂亮，我們知道，\n那都不是真的，因為我們難以相信一個沒有誠信的人能夠說到做到。\nQuestion Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.\nYou should preserve the original relative order of the nodes in each of the two partitions.\nExample:\n1 2 Input: head = 1-\u0026gt;4-\u0026gt;3-\u0026gt;2-\u0026gt;5-\u0026gt;2, x = 3 Output: 1-\u0026gt;2-\u0026gt;2-\u0026gt;4-\u0026gt;3-\u0026gt;5 分析/解題 給定一個Linked List和一個值x，使用x來將所有節點進行分段，\n令較x小的節點排在≥x的分段位置的前面。\n注意在分段時，同時也要保有原先兩段的節點順序。\n這題其實有點像是之前我們在講Merge Two Sorted Lists的感覺，\n為了要能夠讓兩個段落分開且照順序，\n我們應該要有兩個做為頭的dummy節點 ，稱為d1/d2。\n所有小於x的部分都接到d1，反之則接到d2。\n那麼實際上來說，我們只要將整個List遍歷過一遍，\n就可以依照實際和x之間的比較，來決定要將這次看到的節點 ，\n必須要接到d1還是d2上面。\n由於最後我們需要將兩段接起來，\n所以d1/d2保持不動的狀況下，\n我們需要另一個變數來儲存現在遍歷的部份走到的節點，\n先稱其為ite1/ite2，所以ite1/ite2起始分別是d1/d2。\n那麼，按照邏輯來說，我們可以能會想到下面的寫法：\n1 2 3 4 if (head.val \u0026lt; x) { ite1.next = head; ite1 = ite1.next; } 但這麼考慮欠缺了一個條件：\n當我們選定ite1.next = head時，head裡面還藏有它的next的資訊 ，\n造成你以為是只有納入head，殊不知head.next也被隱含進去了 ！\n要解決這個問題，我們可以將ite1.next重新設為null 。\n問題來了，這一設為null，反而變成head的資訊就消失了 ，\n同時head.next的資訊也消失了 。\n所以，我們要一開始用一個nxt的ListNode來記錄head.next，\n接下來兩種狀況下的next相關操作做完以後，\n最後再讓head接上先前儲存的nxt。\n依此，寫成程式碼。\nJava Java的部分，我們先用直觀的方式來處理，\n所以包含前面的處理都完整的話，\n我們應該能得到d1及其後面的一組(直到ite1)、\nd2及其後面的另一組(直到ite2)，\n若其中一個沒有接上任何節點的話，\n可以直接吐出d1.next/d2.next 的狀況。\n若兩者皆有，則先將第一排的結尾接給第二排的開頭 ，\n最後回傳d1.next即可。\n同時，運用陣列可以更輕鬆地化簡邏輯，\n這裡將改善過後的版本放在註解欄中。\nPython 就Python的部分而言，只要使用跟前述相近的處理方式，\n最後再回傳d1.next 即可。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VEQZV7E**\n","date":"2020-01-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-82-linked-list-10/","title":"從LeetCode學演算法 -  82 Linked List (10)"},{"content":"0093. Restore IP Addresses (Medium)\nQuestion Given a string containing only digits, restore it by returning all possible valid IP address combinations.\nExample:\n1 2 Input: \u0026#34;25525511135\u0026#34; Output: [\u0026#34;255.255.11.135\u0026#34;, \u0026#34;255.255.111.35\u0026#34;] 分析/解題 給定一個僅含數字0~9的字串，將其還原成所有合法的IP位址的可能組合。\n對於IP而言，我們所需考慮的有以下幾個條件：\n1. 共分4段(且必須恰好是4段)\n2. 中間以小數點連接，每組的數字在0~255之間\n如果定義再清楚一點的話，\n可以補上前面寫0的部分除了0以外不能納入，會更好一點。\n(比如113.002.22.3不會是合法的IP，但一個IP可以是0.0.0.0)\n所以這題也是很典型的Backtracking+DFS 的題目：\n每次從s上面按順序取一段長度，檢查它是否合法，\n再遞迴取下一段。\n那麼，我們需要考慮一些邊界的條件，\n以便於我們考慮什麼時候該「回頭」：\n最基本的條件，就是已經分到第4段 了，\n我們應該要考慮這段剩下的部分是否合法。\n當剩下的長度\u0026gt;3 =\u0026gt; 根本就超過了，完全不用考慮XD 剩下的長度≤3且轉成數字≤255 ，即可將該段補齊並加到結果。\n例外：連續的0會有問題，所以要優先檢查是否剛好為'0\u0026rsquo; 的狀況，\n除了剛好為\u0026quot;0\u0026quot;的狀況外，首字元為'0\u0026rsquo;就必須被排除掉 。 邊界條件考慮完後，我們來考慮一般的分段法。\n在開始之前，可以先排除掉剩下的長度小於所需的分段數 的狀況，\n用以避免取分段時超出邊界。\n(例如剩下長度為2，但還需要取3段，那麼顯然不夠用)\n假設現在我們接下來要取的位置在 i ，要取 j 個字元：\n那麼 j可以是1~3，但 i+j 不能超過s的長度 。\n我們會發現額外要考慮的就是上面的2的部分 ，\n取完一段以後，呼叫相同的函式進行遞迴，\n不要忘記除了上一次傳進來的前導字串cur 外，\n要加上的是這次取的分段 ，以及分隔用的小數點\u0026quot;.\u0026quot; 。\n依此，寫成程式碼如下：\nJava Java的部分，我們使用LinkedList來記錄結果res，\n傳入的參數有該字串s，res，當前要取的索引值i，\n當前的分段cnt(從0起算)，以及到目前為止的IP的字串cur。\n由於每次呼叫checkIP時帶進去的字串都是新生成 的，\n所以回到上一層時就自然還原了cur的狀態，\n不用像之前的棋盤搜尋字串問題中需要額外考慮要還原的問題。\n每次開始前不要忘記檢查s.length()-i \u0026lt; 4 - cnt的邊界 ，\n若已經不符則可直接return。\n(註：理論上也可以額外檢查s.length()-i \u0026gt; (4-cnt)*4的邊界，\n但實測上並不會因此變快，推估可能理由和檢查255的問題一樣)\n另外請務必留意在比較字串是否相等時請使用equals()的函式 ，\n不要使用\u0026quot;==\u0026quot;(會出錯) 。\nPython Python的部分也是一樣的概念，\n只是substring的操作可以簡單用s[i:j] 的形式來處理，\n且比較相等可以直接使用\u0026quot;==\u0026quot;。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(len(s)) / O(len(s))，更廣義來說，其實長度必須在12 以內，\n所以最大的佔用空間和時間是可以固定的 ，\n要說O(1)也不太算有錯就是了。)\n「為什麼不是當3位數才檢查小於等於255？」\n(這樣必須要先分開3位數及其他，變成要先經過另一組判斷式，\n整體而言不會比較節省時間。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VEQZV7E**\n","date":"2020-01-07T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-81-backtracking-5-dfs-7/","title":"從LeetCode學演算法 - 81 Backtracking (5) / DFS (7)"},{"content":"0082. Remove Duplicates from Sorted List II (Medium)\nQuestion Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.\nExample 1 1 2 Input: 1-\u0026gt;2-\u0026gt;3-\u0026gt;3-\u0026gt;4-\u0026gt;4-\u0026gt;5 Output: 1-\u0026gt;2-\u0026gt;5 Example 2 1 2 Input: 1-\u0026gt;1-\u0026gt;1-\u0026gt;2-\u0026gt;3 Output: 2-\u0026gt;3 分析/解題 給定一個排序好的鏈結串列，將擁有重複的數字的節點全數刪去，\n只保留原先在串列上相異的數字。\n我們之前就嘗試過從鏈結串列刪去節點 的題目了，\n只是今天這組更激進一點XD\n原本是刪到剩一個即可，現在變成要將重複的全都刪掉，\n那麼，該怎麼辦呢？\n由於有可能刪到第一個，一般來說這種狀況，\n習慣上會開出一個dummy node做為不會變動的節點參照，\n我們先將其叫做dum，簡單將dum的next連接至head即可。\n接下來要處理的是：我們要記得數值一致的節點群前面的那一個節點 ，\n這樣刪去的時候才能將前後重新連接上。\n因此，我們需要一個節點記錄，這裡將它叫做pre ；\n另一個節點則做為迭代用，記錄現在所在的位置，將其稱做cur ，且就位置關係來說，pre的next應該會是cur 。\n開始時pre的起始點 應該是dum ，這樣cur 會從head 開始，\n當cur還沒走到底的時候要進行迴圈遍歷 。\n另外在內部每次要迴圈檢查 ：\n1. cur是否有下一個節點\n且\n2. cur的下一個節點和自己的值是否相等\n(和先前一樣，這個迴圈用來略過所有重複值的節點 )\n當走完以後有可能是\ncur還沒到底(有值) =\u0026gt; pre的next就是cur ，所以再往下找的話要將pre設為pre.next cur已經碰到底了 (cur.next == null) =\u0026gt;\n將pre.next指向null (pre.next = cur.next) 最後，別忘了將cur往下走(cur = cur.next) 。\n最終做完的時候，由於先前我們將dum.next設定成head ，\n中間連接有變動的話，會被pre的操作給連接過去，\n所以新的head的位置不管有無更動，\n應該還是位於dum.next上。\n(因為pre一開始等於dum，pre.next一開始會連動到dum.next )\n依此，寫成程式碼。\nJava Java的部分不要忘記該new的dum，\n剩下就只有判斷null的時候不像Python可以直接用if not，\n其他大多大同小異；Python的邏輯是一致的，就不再贅述說明了。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1))\n相似及延伸 這題理論上也可以用遞迴的方法解，有興趣的讀者可以嘗試看看。\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(最後一波早鳥優惠了，不確定調回原價是什麼時候)： ** https://hiskio.com/courses/319?promo_code=VEQZV7E**\n","date":"2020-01-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-80-linked-list-9/","title":"從LeetCode學演算法 - 80 Linked List (9)"},{"content":"0383. Ransom Note (Easy)\nQuestion Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function that will return true if the ransom note can be constructed from the magazines; otherwise, it will return false.\nEach letter in the magazine string can only be used once in your ransom note.\nNote:\nYou may assume that both strings contain only lowercase letters.\n1 2 3 canConstruct(\u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;) -\u0026gt; false canConstruct(\u0026#34;aa\u0026#34;, \u0026#34;ab\u0026#34;) -\u0026gt; false canConstruct(\u0026#34;aa\u0026#34;, \u0026#34;aab\u0026#34;) -\u0026gt; true 分析/解題 繼時空旅人買賣股票( 0121 ) 及闖空門教學( 0198 , ** 0213**** )後，\n我們這次要來寫勒索信** 啦！\n有沒有覺得這一系列很實用？(大誤)\n勒索信的構成很簡單，就是每個從雜誌上的字，\n剪下來以後只能用一次 ，要用這些字去組出勒索信的內容。\n所以這個就很簡單就可以處理啦！\n我們可以先將所有雜誌上的字分門別類，\n這邊還很貼心告訴我們全部只有小寫字母 ，\n所以分成a-z即可，計算總共有的素材數量。\n接下來用勒索信上的每個字來去檢驗，\n每次都扣除掉對應的字母的計數，中間一旦有素材不夠，\n表示已經沒辦法完成信件，即可回傳false，\n否則整個迴圈完成的話表示可構成勒索信，則回傳true。\n依此可以寫成程式碼。\nJava Java的部分，其實如要扣掉一些條件，\n可以先檢查兩者的長度，magazine長度比較小時肯定無法完成勒索信。\n由於題目的給定，我們可以不用HashMap，\n僅用一個長度26的陣列來處理，index則用c - ‘a’ 來計算，\n留意使用\u0026ndash;table[c-\u0026lsquo;a\u0026rsquo;]時由於先進行遞減 ，所以檢查條件是小於0。\nPython Python的部分，可以用dictionary作到類似的事情。\n(list也可以，不過要自行用ord來轉換，和Java不同)\n當然，我們也可以使用Counter或count來做更迅速的計算。\n(註解提供了另外兩種leetcode上別人的解法)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(len(ransomNote) + len(magazine))/O(1))\n(空間複雜度因為依題目提示，key值固定最多26，\n所以不因字串長而改變。)\n「如果要求含大小寫/大小寫可混用/含標點符號等狀況呢？」\n(依照所需使用HashMap或Dictionary，\n並將共用的部分利用他們相減的距離歸到同類)\n(在ASCII Code上，‘a’-’A’ == 32 )\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(接下來快要漲成下個價格啦XD)： ** https://hiskio.com/courses/319?promo_code=VEQZV7E**\n","date":"2019-12-31T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-79-hash-table-6/","title":"從LeetCode學演算法 - 79 Hash Table (6)"},{"content":"0392. Is Subsequence (Easy)\nQuestion Given a string s and a string ** t**, check if ** s** is a subsequence of ** t**.\nYou may assume that there are only lower case English letters in both s and ** t**. ** t** is potentially a very long (length ~= 500,000) string, and ** s** is a short string (\u0026lt;=100).\nA subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, \u0026quot;ace\u0026quot; is a subsequence of \u0026quot;abcde\u0026quot; while \u0026quot;aec\u0026quot; is not).\nExample 1 s = \u0026quot;abc\u0026quot;, ** t** = \u0026quot;ahbgdc\u0026quot;\nReturn true.\nExample 2 s = \u0026quot;axc\u0026quot;, ** t** = \u0026quot;ahbgdc\u0026quot;\nReturn false.\nFollow up:\nIf there are lots of incoming S, say S1, S2, … , Sk where k \u0026gt;= 1B, and you want to check one by one to see if T has its subsequence. In this scenario, how would you change your code?\n分析/解題 給定一個字串s跟一個字串t，\n檢查s是否是t的subsequence(子序列)。可以假設s是一個短字串(長度≤100)且t是一個長字串(長度約500000)。\n從原字串t刪除字母(也可以完全不刪)，\n並保有原字串的相對位置，所構成的新字串，即為t的子序列。\n後面有一個Follow up問的是，\n假設這個函式會拿來檢查很多次(k次)不同的S的話(例如會處理1billion次)，\n要怎麼實作這個函式比較好？\n首先我們先來看看比較直觀的解法。\n我們先舉個例子，如果有一個s是”abcde”的話，\ns要是t的子序列的條件，就是我們要能在t當中，\n依序得到 a~e這五個字母。\n那麼第一個我們一定要先找a，假設從t中找到一個a以後，\n按照順序的話，這個a以前的bcde就都不能用了 ！\n(因為順序就不對啦XD)\n同樣的，找到b以後b以前的cde也不能用，以此類推。\n因此，我們要保持能確定找到可能性的方式，\n就是每一次在t中都取這個順序最前面出現的字母 。\n在s當中使用一個記錄index用的i ，\n從頭開始找t中的s[i] 在哪，記錄為pre 。\n每次找到以後，將i遞增 ，\n接下來從t的pre+1處 開始尋找下一個s[i]的位置。\n如果找不到的話呢？就表示沒辦法成立，應該回傳false，\n否則當全部的s的字母都能找到對應的位置的話，\n則代表s可以作為t的子序列。\n上面描述這樣的方法，我們使用了兩個索引值，\n來記錄s和t當前查找到的位置，\n所以這個解法可以視為two pointer手段的一種操作。\n同時，我們前面在解的時候，\n每次都盡可能 去找最前面出現 的第一個s[i]，\n這種概念的想法，僅在特定的題目適用。\n當符合在每一個當前狀況都取當前最佳的狀況 ，\n全局就會是最佳 的時候，我們就在局部的區段盡可能貪婪。\n這樣子的策略被稱為貪婪演算法 (Greedy Algorithm)\n請留意到，這種方式往往在很多情況下會失效，\n所以在使用前請詳閱公開說明書(X)。\n(開玩笑的XD，應該是使用前請確認局部最佳能推導至全局最佳 。)\n這麼做基本上要掃過s跟t的字串，所以時間會是O(len(s)+len(t))，\n或者說當t遠大於s的時候可以視為O(len(t))。\n那麼如果搭配Follow up的條件呢？\n如果有k次不同的s的檢查，\n就上面的解法而言，每次仍然要各掃過一遍s跟t，\n時間複雜度是O(k*(len(s)+len(t))) ，顯然當t很大的時候，\n掃過k次是很不理想的，我們會希望能夠化簡一點這個部分。\n那要怎麼作呢？這邊引用shuoshankou 在leetcode上的解，\n我們可以先針對t建立一個HashMap ，當中的key是t上的字母 ，\n而value是這個字母出現在t上面的indices (使用ArrayList來儲存)。\n這個儲存過程會是O(len(t)) 。\n接著要查找的過程就會變成針對s[i]來搜尋HashMap上的index，\n且限定這個index要剛好是在i之後的第一個出現的位置。有沒有覺得很眼熟？沒錯， 這不就是Binary Search嗎？\n我們在處理的，就跟對於某個陣列，\n搜尋一個值在哪裡(或應插入在哪裡)的問題一樣！\n所以就一般來說，搜尋需求是log(N)，\n如果前後拆成常數的單位可以忽略不記，\n所以對於k個s搜尋所需會是O(k*len(s) * log(len(t))) ，\n當k大到一定程度的時候，顯然只作一次O(len(t))先建立對應表，\n讓後面的搜尋相關的t的複雜度都變成對數量級 是相當划算的。\n注意，以這題的測試資料而言，Binary Search速度並不會跑起來比較漂亮，\n原因是測試資料的總數可能相對有限，並不像Follow up假想那樣，\n所以前面吃下一整個建立HashMap的時間就會顯得拖累。\nJava Java的部分可以先檢查s和t的長度來避免一些根本不需要跑的狀況，\n同時使用indexOf 來搜尋每次的si第一個出現的位置。\n(搜尋不到的話indexOf會回傳-1 )\nBinary Search的寫法則如註解處，\n先建立起HashMap並掃過整個t並依序塞入，\n後面再使用getNextIndex來寫Binary Search。\n其實如果要能像Follow up那樣反覆利用的話，\n應該要能將t的輸入抽離開來，題目的要求和預設寫法並沒有考慮這點，\n會導致每次都需要對t建立一個HashMap。\n如果要重複利用的話，應該要給定成class Solution的變數，\n且建立時能先給入t才對。\nPython Python的部分則使用index 來進行查找，\n請留意查找不到的話會產生exception，\n所以這邊是使用try/except 來處理的。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(請見上面詳述。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(接下來快要漲成下個價格啦XD)： https://hiskio.com/courses/319?promo_code=VEQZV7E ","date":"2019-12-28T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-78-two-pointer-4-binary-search-5/","title":"從LeetCode學演算法 - 78 Two Pointer (4) / Binary Search (5)"},{"content":"1071. Greatest Common Divisor of Strings (Easy)\nQuestion For strings S and T, we say \u0026ldquo;T divides S\u0026rdquo; if and only if S = T + ... + T (T concatenated with itself 1 or more times)\nReturn the largest string X such that X divides str1 and X divides str2.\nExample 1 1 2 Input: str1 = \u0026#34;ABCABC\u0026#34;, str2 = \u0026#34;ABC\u0026#34; Output: \u0026#34;ABC\u0026#34; Example 2 1 2 Input: str1 = \u0026#34;ABABAB\u0026#34;, str2 = \u0026#34;ABAB\u0026#34; Output: \u0026#34;AB\u0026#34; Example 3 1 2 Input: str1 = \u0026#34;LEET\u0026#34;, str2 = \u0026#34;CODE\u0026#34; Output: \u0026#34;\u0026#34; Note:\n1 \u0026lt;= str1.length \u0026lt;= 1000 1 \u0026lt;= str2.length \u0026lt;= 1000 str1[i] and str2[i] are English uppercase letters. 分析/解題 給定兩字串，找出能「除盡」這兩個字串的最長字串X。\n題目已經給定的非常明顯了就是在求gcd(最大公因數)，\n因此，拿出小學就教過的輾轉相除法即可。\n(要看起來厲害一點的話，也可以叫歐幾里得算法Euclidean algorithm)\n輾轉相除法告訴我們說，兩個數的最大公因數，\n就是不斷將大的除以小的，取出餘數替代之，直到能夠整除為止。\n於是這邊變成字串時，我們的除就會比較麻煩一點。\n為求簡單起見，我們可以固定將第一個字串選擇放比較長的 ，\n如果發現相反 的話，則將兩者進行對調 。\n所以就可以分成以下的步驟：\n取兩字串長l1, l2，若l1 \u0026lt; l2 則呼叫遞迴將str1, str2交換 若str1和str2完全一樣，則回傳str1 若str1的前面的部分 和str2 一樣，則將str1扣除掉該部份 以後，\n呼叫遞迴傳入繼續計算。\n(因為我們操作字串的除只能一組一組扣掉 ) 否則就回傳空字串 (因為不一樣的話代表完全沒有共同的字串，\n跟數字的最大公因數是1概念一樣) Java Java的部分，字串相等請使用equals來比較，\n而前面的部分一樣可以用startsWith函式，\n並留意空字串要用雙引號，不能用單引號(因為單引號是char)。\nPython Python的部分，使用==和串列取值的方式，\n可以簡單達成我們所需要的操作。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(l1+l2)/O(l1+l2)，由於每階段會固定消去最小單位的長度，\n所以最差的狀況就是全部都消去，也就做了兩字串長度的消去的動作，\n但中間未考慮比較是否相等的狀況。\n空間複雜度的部分，\nJava的substring和Python的切list的方式都會產生新的單位，\n理論上仍然最少會佔用到完整的l1+l2單位空間)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(額滿即截止)： https://hiskio.com/courses/319?promo_code=VEQZV7E ","date":"2019-12-24T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-77-string-2/","title":"從LeetCode學演算法 - 77 String (2)"},{"content":"0290. Word Pattern (Easy)\nQuestion Given a pattern and a string str, find if str follows the same pattern.\nHere follow means a full match, such that there is a bijection between a letter in pattern and a ** non-empty** word in str.\nExample 1 1 2 Input: pattern = \u0026#34;abba\u0026#34;, str = \u0026#34;dog cat cat dog\u0026#34; Output: true Example 2 1 2 Input:pattern = \u0026#34;abba\u0026#34;, str = \u0026#34;dog cat cat fish\u0026#34; Output: false Example 3 1 2 Input: pattern = \u0026#34;aaaa\u0026#34;, str = \u0026#34;dog cat cat dog\u0026#34; Output: false Example 4 1 2 Input: pattern = \u0026#34;abba\u0026#34;, str = \u0026#34;dog dog dog dog\u0026#34; Output: false Notes:\nYou may assume pattern contains only lowercase letters, and str contains lowercase letters that may be separated by a single space.\n分析/解題 給定一個pattern和一個字串str，檢查str是否遵循pattern的模式。\n簡單來說，就是str的每一段字的重複或不重複模式，\n都要能被pattern裡的\u0026quot;abba\u0026quot;這樣的每個字母去對應 的方式來表達出來。\n看到這邊，有沒有覺得很像LeetCode最開始的那個Two Sum?\n我們每次想要將一個pattern內的字母去對應到str的一段字串，\n而重複的狀況應該要有相同的對應。\n那不就是key-value的對應方式嗎?\n所以想法就很簡單了：\n建立一個Hash Table名為map(Java的HashMap或Python的Dictionary) 先檢查pattern的段數和str的段數是否相同 ，若否則直接回傳false 依序按段取出 pattern和對應的str的分段，檢查以下性質：\n(下面pattern均作為key，str的分段均作為value)\n若key不存在且value不存在-\u0026gt;將**(key, value)** 放入map\n若key不存在且value存在-\u0026gt;回傳false (** 表示別人先對應到它了**)\n若key存在且value不對-\u0026gt;回傳false (** 表示該key已經被占用掉**) 請留意後面的兩個false的狀況，\n我們可以對照Example 2 跟Example 3 ，\n因為有些可能是前面某個key或某個value已經達成對應關係了，\n後續如果出現對不上的狀況，就表示整個對應關係無法成立囉！\n依此，寫成程式碼如下：\nJava Java的部分，\n可以使用HashMap的containsKey/containsValue/get，\n以及字串的split/equals函式，來協助判斷的工作。\nPython Python方面，同樣有split可以使用，\n其他使用dict的in/not in及values()等簡單的存取方式即可。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，準確來說應該是看len(str)來決定N)\n「如果限制使用split呢？」\n(進行依字元掃瞄過整個陣列，碰到空白再輸出成字串(list或arraylist)即可)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium優惠(額滿即截止)： ** https://hiskio.com/courses/319?promo_code=VEQZV7E**\n","date":"2019-12-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-76-hash-table-5/","title":"從LeetCode學演算法 - 76 Hash Table (5)"},{"content":"0289. Game of Life (Medium)\nQuestion According to the Wikipedia’s article: “The Game of Life , also known simply as Life , is a cellular automaton devised by the British mathematician John Horton Conway in 1970.”\nGiven a board with m by n cells, each cell has an initial state live (1) or dead (0). Each cell interacts with its eight neighbors (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):\nAny live cell with fewer than two live neighbors dies, as if caused by under-population. Any live cell with two or three live neighbors lives on to the next generation. Any live cell with more than three live neighbors dies, as if by over-population.. Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction. Write a function to compute the next state (after one update) of the board given its current state. The next state is created by applying the above rules simultaneously to every cell in the current state, where births and deaths occur simultaneously.\nExample:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 Input: [ [0,1,0], [0,0,1], [1,1,1], [0,0,0] ] Output: [ [0,0,0], [1,0,1], [0,1,1], [0,1,0] ] Follow up :\nCould you solve it in-place? Remember that the board needs to be updated at the same time: You cannot update some cells first and then use their updated values to update other cells. In this question, we represent the board using a 2D array. In principle, the board is infinite, which would cause problems when the active area encroaches the border of the array. How would you address these problems? 分析/解題 這題是典型的生命遊戲 題目。生命遊戲一般是透過2D的棋盤式的格子，\n上面以1代表活著的細胞，0代表死去的細胞，\n透過設定好的規則來觀察其演化的狀況。\n設定這些東西的目的最初應該是為了要產生模擬圖靈機，\n後來發現一些有趣的現象，比如能穩定周期性的圖案像是滑翔機、\n機關槍等等，也有的看似是有周期的但最後會消滅的狀況，\n總之某種層面上有點像是可以拿來模擬族群聚落的演進等狀態就是了，\n有興趣的讀者可以再看看相關的資料。\n回到題目，基本上生命遊戲裡面的每個單位，\n在下一個時間點要嘛是1(活著)，不然就是0(死去)。\n典型的規則是看其九宮格的周圍：\n如果原本自己是1(活著) 的話，只有周圍有2~3個 鄰居(活著的細胞)，\n下一刻自己才會繼續存活，否則就會死去。\n(只有1個鄰居以下會因人口過少而死，\n而超過3個鄰居會因人口過多而死)\n如果原本自己是0(死去) 的話，只有周圍恰好有3個鄰居 ，\n下一刻自己會變成1(活著) (視作被繁衍出來的後代)\nFollow up有兩點，1是詢問是否能in-place解題，\n2是棋盤是無窮大的話該怎麼描述問題。\n這個題目其實看懂定義的話並不困難，只是繁瑣而已。\n首先有一個重點是：更新的時候必須要一口氣一起更新，\n因為每個細胞的變化都需要看周圍的細胞，不同時改變的話，\n結果就有可能會出錯。這邊有兩種考慮方式：\n開一個跟board一樣大的二維陣列(串列)，\n記錄下一刻的狀態，最後再進行替換。 想辦法用原有的board 來進行記錄。\n我們這邊因為希望達成in-place，所以自然選擇2。\n還記得之前我們提過的word search嗎？\n我們利用了沒有被用到的位元做為遮罩進行XOR，\n使得visited的資訊用原先的棋盤就可以做記錄了；\n這邊比之前還要簡單，我們只要拿2的1次方位 來記錄即可，\n因為board一開始只用到1和0而已 ，所以判斷完以後，\n如果它會變成存活的狀態，則將該值加上2，\n死去的話則不用額外動作。\n這樣一來，最後我們只要將整個board除以2取整數 ，\n就可以得到新的棋盤狀態了！\n中間在進行周圍八格的判斷時，不要忘記要除以2取餘數 。 所以總體會像這樣：\n遍歷整個棋盤做check check 函式中:\na. 依次檢查是否存活(alive)，並加總 周圍八格的存活細胞數量\nb. 若本身當前存活 -\u0026gt; 檢查** 周圍存活數是 2或3時， 將自己加上2**\nc. 否則(本身死亡 )，若周圍存活數 是3 ，將自己加上2 alive 函式中:\na. 若超出邊界則回傳0\nb. 否則回傳該格數值除以2的餘數 全數檢查完後呼叫next 函式更新狀態 next 函式: 遍歷整個棋盤，將值除以2取整數 。 一般典型的話理論上邊界應該要互相連接，\n(走到最底會通往最上面，走到最右邊會連通最左邊)\n但我們這邊就不考慮這個問題了。\nJava Java的部分，計算八方向我們使用了一個d(direction)的二維陣列來記錄，\n除了邊界條件以外沒有特別需要注意的地方。\nPython Python的部分，d的方面我們可以用list comprehension ，\n扣掉自身(0, 0)來建構。除了留意子函式的定義，\n要在拿來做為global的部分後面(才能拿來用) ，\n在呼叫之前(因為是腳本執行) 以外，\n其他沒有什麼特別的地方XD\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(m * n), O(1))\n「如果棋盤無限大？」\n(那應該要找出一個pattern來表示它才對，\n不可能真的開出一個無限大的棋盤)\n「首尾相接的話？」\n(Python直接按照負數index會發生的事情處理，\nJava要自己計算過界的狀況)\n「還能簡化嗎？」\n(理論上相鄰的兩個點會共用到4個鄰居點 ，\n應該可以再節省一點計算時間，但時間複雜度是一樣的 )\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\n第二階段Medium優惠(額滿即截止)： https://hiskio.com/courses/319?promo_code=VEQZV7E\n","date":"2019-12-19T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-75-array-14/","title":"從LeetCode學演算法 - 75 Array (14)"},{"content":"0234. Palindrome Linked List (Easy)\nQuestion Given a singly linked list, determine if it is a palindrome.\nExample 1 1 2 Input: 1-\u0026gt;2 Output: false Example 2 1 2 Input: 1-\u0026gt;2-\u0026gt;2-\u0026gt;1 Output: true Follow up:\nCould you do it in O(n) time and O(1) space?\n分析/解題 給定一個單向鏈結串列，試判斷它是否是palindrome(回文)。\n所謂palindrome就是從尾到頭和從頭到尾看起來會相同 。\n在這題當中，由於我們的結構是Linked List，無法很輕鬆的到達尾端，\n也無法輕易的回頭，那麼該怎麼辦呢？\n要判斷回文有一個重點，就是從中間切開來兩邊是對稱的 。\n因此，我們可以設定fast/slow的兩個pointer，\n以之前常用的技巧，每次fast走兩步，slow走一步 ；\n讓fast走到底時，slow剛好走到一半 。\n節點總數是偶數時，切開來的第二段應該是從slow的下一個節點 開始，\n所以當fast不是NIL 時，我們應該讓slow多走一步 。\n(例如總共有10個節點，按上面的方法走完，\nfast會在10，slow會在5，但第二段應該從6開始，所以slow要往下走一步)\n所以比較「從slow到串列尾端的反轉串列 」及\n「從head往下的對應節點 」，即可檢驗串列是否為回文。\n那麼要怎麼反轉串列呢？上上篇文章 不就是嗎XD\n我們可以用之前的reverse函數進行反轉，\n反轉後再對兩個串列一一進行比較，\n一旦值不相等即回傳false。\n依此，寫成程式碼如下：\nJava 我們也可以使用另一種思路，\n先多設定一個rev節點，\n在slow/fast行進時，將slow經過節點進行反轉連接，\n這樣在走完的時候，讓rev 變成前半段反轉後的串列的開頭 ，\n而slow 則是後半段的串列的開頭 。最後同樣一個一個檢查，\n即可判斷整個串列是否是回文。\nPython 務必請留意這麼做的缺點是整個串列就被我們拆成兩半了 ，\n如果不是要求空間複雜度是O(1)的話，\n用別的資料結構輔助去存入一半的節點，能夠保有原先的結構。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1))\n「如果不計較空間複雜度，有沒有辦法保留原先的linked list呢？」\n(Python的話可以使用list來做兩邊儲存比較的動作，\n或者要使用stack來置入前半段的節點，後面pop出來做比較也可以)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium限額5名優惠(額滿即截止)： https://hiskio.com/courses/319?promo_code=VE9NJQE 問卷抽書＆取得上架通知： https://pse.is/MS2J2 如果你對線上課程不放心，\n也可以先來12/17(二) 我在天瓏分享的講座看看！\n講座連結： https://pse.is/JS3LJ ","date":"2019-12-16T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-74-linked-list-8/","title":"從LeetCode學演算法 - 74 Linked List (8)"},{"content":"0208. Implement Trie (Prefix Tree) (Medium)\nQuestion Implement a trie with insert, search, and startsWith methods.\nExample:\n1 Trie trie = new Trie(); 1 2 3 4 5 6 trie.insert(\u0026#34;apple\u0026#34;); trie.search(\u0026#34;apple\u0026#34;); // returns true trie.search(\u0026#34;app\u0026#34;); // returns false trie.startsWith(\u0026#34;app\u0026#34;); // returns true trie.insert(\u0026#34;app\u0026#34;); trie.search(\u0026#34;app\u0026#34;); // returns true Note:\nYou may assume that all inputs are consist of lowercase letters a-z. All inputs are guaranteed to be non-empty strings. 分析/解題 試實作一個trie，當中包含插入，搜尋，是否含前綴判斷的函式。\n我們很早以前講過一題使用Trie來進行解題的問題，這次再來複習一下XD\nTrie跟樹非常相像，通常用來作字典搜尋，所以又叫做字典樹 。\n在實作Trie的時候，我們通常會實作TrieNode作為每個節點的單位，\n這當中每個節點主要會記錄兩件事：\n1. 這個節點是否到這邊構成一個字\n因為可能是經過的節點，比如word -\u0026gt; w, o, r, d，\n假設我們插入了一個這樣的字，那麼總共會生成4個節點，\n但只有d 這邊應該被判定到此構成一個字 。\n所以就這題而言，\n我們可以使用一個boolean值(True/False)來儲存這個狀態，\n也就是下面程式碼中看到的isWord 。\n2. 這個節點往下連接的節點群\n以這題來說，由於僅限定a到z，所以我們其實可以用長度為26的節點陣列，\n來表達下一個連結。當節點不存在時，表該路徑不存在/尚未生成，\n在Java中我們用一個TrieNode[] next來儲存。\n但對Python而言，因為語言特性，\n我們無法在TrieNode內直接宣告TrieNode(會報錯)，\n所以會選擇使用一個字典進行記錄。\n最後，留意到由於我們每次進行路徑移動時，\n所使用的index要嘛是該字元減去’a’ (Java)，\n要嘛乾脆是當前的字元 (Python)，\n所以我們不需要額外耗費空間記錄字元值 。\n此外，若題目有要求記錄被存入的相同字的次數，\n就需要額外的count變數來儲存。(另外可以將isWord改成count用作判斷)\n所以整個的思路就會很明顯了：\n定義一個TrieNode class，當中有isWord跟next。 在Trie中，初始化時宣告一個根節點root的TrieNode。 insert: 節點從root處開始查找，沿著每個字元連接到下一個TrieNode，\n並且如果節點尚未建立就將其建立，走到底後，將isWord設為true。 search: 一樣從root開始，沿著每個字元往下走，\n若碰到沒有建立則可直接回傳false。\n當走到該節點以後，依據isWord的狀態來判斷要回傳true or false。 startWith: 由於只要路過即可，所以前面和search一樣，\n但最後只要能走到，即可回傳true。 Java Java的部分留意到使用了c - \u0026lsquo;a\u0026rsquo;的方式來取得index，\n因為char是可以當作正整數來相減的。\nTrieNode的建構式理論上可省略，\n但直接先寫可以降低編譯器還要幫你生成的麻煩，\nSubmit實測上似乎平均會快一點點XD\n(沒有大量測試，有興趣的讀者可再比較看看)\n在最開頭的TrieNode代表著根，但它本身並不代表任何字元 ，\n請留意這點。\nPython Python的部分額外提供了一個LeetCode上找到解答較快的版本，\n是使用#的符號來取代isWord的功能，並用一個多層的字典名為tree，\n來記錄整個字典樹的結構。\n這個方法的好處是無需另外產生一個TrieNode的物件，\n但缺點是必須使用一個不會出現在字串中的符號 。\n(如果今天這個字串內會含#的話，這個解就會無法使用了XD)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(插入：O(N)/空間全新的話O(N)\n搜尋：O(N)/O(1)\n前綴：O(N)/O(1)\n當中N代表字串長。)\n「如果要支援刪除呢？」\n(要實作刪除函式時，不是使用TrieNode的話，\n就要留意去處理自己製造的結束標記。\n一般使用TrieNode很簡單，使用search找到該字，\n並將isWord設成false/False即可。\n記得詢問找不到該字要怎麼回傳。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium限額5名優惠(額滿即截止)： https://hiskio.com/courses/319?promo_code=VE9NJQE 問卷抽書＆取得上架通知： https://pse.is/MS2J2 如果你對線上課程不放心，\n也可以先來12/17(二) 我在天瓏分享的講座看看！\n講座連結： https://pse.is/JS3LJ ","date":"2019-12-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-73-trie-2/","title":"從LeetCode學演算法 - 73 Trie (2)"},{"content":"0206. Reverse Linked List (Easy)\nQuestion Reverse a singly linked list.\nExample:\n1 2 Input: 1-\u0026gt;2-\u0026gt;3-\u0026gt;4-\u0026gt;5-\u0026gt;NULL Output: 5-\u0026gt;4-\u0026gt;3-\u0026gt;2-\u0026gt;1-\u0026gt;NULL 分析/解題 試反轉一個單向鏈結串列。\n很久以前我們嘗試解過這題的較困難的版本\n(0092. Reverse Linked List II (Medium))，\n不過是透過stack的輔助，這題較為簡單，\n我們來嘗試不使用其他資料結構來試試看吧XD！\n先舉一個簡單的例子：\nhead -\u0026gt; a -\u0026gt; b -\u0026gt; c -\u0026gt; d -\u0026gt; NIL\n這個單向鏈結串列在反轉的時候應該會變成 ：\nNIL \u0026lt;- head \u0026lt;- a \u0026lt;- b \u0026lt;- c \u0026lt;- d\n我們可以先看head, a, b這段，\n在反轉時，我們要將head的next從a改成別的指向；\n但如果先改掉的話，那就喪失掉a的位置了，\n所以我們需要一個tmp來記錄a的位置，\n再將head的next指向到前一個node (這邊一開始是NIL)，\n最後讓tmp這個node做為下一個要處理的對象。\n反覆處理，最終當head是null的時候，\n回傳前一個node即為新的linked list的開頭(反轉前的尾端)。\n所以以迭代法的步驟上會像這樣：\n先宣告一個NIL的ListNode，我們命名為prev 當head非null時，進行迴圈：\n2-1. 宣告一個節點n，位置指定到head的位置\n2-2. head往下走到其next\n2-3. n的next位置指定成prev\n2-4. 再將prev的位置指定到n 迴圈完成後回傳prev即可 1 1. (prev=NIL) head -\u0026gt; a -\u0026gt; b ... 1 2 2. (n) (prev=NIL) head -\u0026gt; a -\u0026gt; b ... 1 2 2-3 (head) prev=NIL \u0026lt;- n a -\u0026gt; b ... 1 2-4 NIL \u0026lt;- prev head=a -\u0026gt; b ... 以第一輪的迴圈推導會如上面，讀者也可以自行嘗試推演看看。\n若用遞迴的話也可以達到相同效果：\n呼叫一個遞迴函式rev，將(null, head)做為參數傳入\n(在rev中，參數為前一個節點prev，跟當前的節點n) 如果n為NIL的話則直接回傳prev 宣告一個tmp節點，其位置指定為n.next 再將n.next的位置指定給prev 回傳rev(n, tmp) 所以不論哪一種方式，\n我們基本上都是使用宣告的節點去記錄next的部分，\n再將當前的節點的next指向到prev，從而完成將鏈結反向的工作。\n依此，寫成如下的程式碼：\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\nMedium限額5名優惠(額滿即截止)： https://hiskio.com/courses/319?promo_code=VE9NJQE 問卷抽書＆取得上架通知： https://pse.is/MS2J2 如果你對線上課程不放心，\n也可以先來12/17(二) 我在天瓏分享的講座看看！\n講座連結： https://pse.is/JS3LJ ","date":"2019-12-02T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-72-linked-list-7/","title":"從LeetCode學演算法 - 72 Linked List (7)"},{"content":"0205. Isomorphic Strings (Easy)\nQuestion Given two strings *s * and *t *, determine if they are isomorphic.\nTwo strings are isomorphic if the characters in *s * can be replaced to get *t *.\nAll occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.\nExample 1 1 2 Input: s = \u0026#34;egg\u0026#34;, t = \u0026#34;add\u0026#34; Output: true Example 2 1 2 Input: s = \u0026#34;foo\u0026#34;, t = \u0026#34;bar\u0026#34; Output: false Example 3 1 2 Input: s = \u0026#34;paper\u0026#34;, t = \u0026#34;title\u0026#34; Output: true 分析/解題 給定兩個字串s和t，試判斷它們是否同構(isomorphic)\n若s和t同構，表示可以透過將s中的相同的字元轉換成另一個字元，\n保有其順序，使得在轉換過後的s和t完全一樣。\n兩個不同的字元不可映射到相同的字元 ，\n但一個字元可以映射到原來的字元(也就是不變)。\n這個題目簡而言之，就是在找尋用特定方式轉換對應字的方法，\n比如範例中的paper -\u0026gt; title有以下的轉換對應：\np \u0026lt;-\u0026gt; t, a \u0026lt;-\u0026gt; i, e \u0026lt;-\u0026gt; l, r \u0026lt;-\u0026gt; e\n由於同構並沒有限制轉換方向，所以既要轉得過去，也要轉得回來，\n這代表了他們對應必須要1對1才行。\n因此，我們可以想到以下的方式：\n先檢查兩邊長度，不相等則直接回傳False (怎麼轉都沒用XD) 可以選擇建立一個HashMap/Dict 並額外處理雙向 的對應檢查，\n或者選擇開出2個陣列/Dict(也可用串列，不過要自己轉換) 來做檢查。 每次從s, t中各取出一個字元 (假設現在在index i )：\n3-1. 兩字元都未進入 陣列對應 -\u0026gt; 將s[i] 與t[i] 放入兩個陣列的對應\n3-2. 兩字元都進入 陣列對應 -\u0026gt; 檢查s[i] 是否對到t[i] ，t[i] 是否對到s[i]\n(只要其中一個對錯或沒對到，即可判定為False ) 當所有字元均檢查完，表示順利全數對應到，回傳True 。 簡單吧！\n在Java的部份，\n我們可以直接利用char可以自動轉換成int當作陣列的index。\n沒有對應則會拿到預設值(0)，依此寫成以下程式碼：\nJava Python的部份，方便起見我們使用了dict來紀錄，\n預設值使用get放入0。\n另外提供一個特別的用法，可以使用maketrans 及translate ，\n來進行兩個表的轉換。但由於中間可能有重複，\n所以要先經過set(刪去重複)和list, join 以後，\n重新依照原先的字母排列排序(用key＝s.index) ，\n最終看看s經過轉換以後是否和t相同。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N), 但空間複雜度最高取決於實際用到的字數，\n亦可視為O(1)，因限縮在ASCII Code的話也才128種類)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n筆者開設的系列同名線上課程：\n「從Leetcode學演算法｜基礎篇」已經上線啦！ 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\n限額早鳥連結： https://hiskio.com/courses/319?promo_code=13L5QJE 問卷抽書＆取得上架通知： https://pse.is/MS2J2 如果你對線上課程不放心，\n也可以先來12/17(二) 我在天瓏分享的講座看看！\n講座連結： https://pse.is/JS3LJ ","date":"2019-11-26T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-71-hash-table-4/","title":"從LeetCode學演算法 - 71 Hash Table (4)"},{"content":"0203. Remove Linked List Elements (Easy)\nQuestion Remove all elements from a linked list of integers that have value *val *.\nExample:\n1 2 Input: 1-\u0026gt;2-\u0026gt;6-\u0026gt;3-\u0026gt;4-\u0026gt;5-\u0026gt;6, val = 6 Output: 1-\u0026gt;2-\u0026gt;3-\u0026gt;4-\u0026gt;5 分析/解題 題目要求將一個給定的linked list上值是val的所有元素均去除掉。\n前面已經講過一些linked list的題目了，\n在處理的重點上，不外乎就是在於如何進行遍歷 ，\n以及移動 和取代 的不同，是很多人容易弄混的。\n我們先假定有一組node的連結長這樣：\nprev -\u0026gt; curr -\u0026gt; next\n今天如果想要遍歷的話，我們應該做的事情是先宣告一個node，\n並將prev的位置指定給node：\n1 2 3 4 5 6 Java: ListNode node = prev; while (node != null) { System.out.println(node.val); node = node.next; } 1 2 3 4 5 Python: node = prev while node: print(node.val) node = node.next 這當中，node = node.next的方式變動了node所指向的記憶體位址，\n使其切換到下一個(也就是curr所在的位址)，但prev仍然在原地 。\n回歸到題目本身，\n題目要求的是跳過特定的val值，例如1-\u0026gt;2-\u0026gt;6-\u0026gt;3，目標val是6。\n遇到val值時，應該要將2的連接從6改到3 ，換言之，\n當結點node走到2時，發現node.next.val跟目標val一樣，\n連接上就會變成：\nnode.next = node.next.next\n此外，為了要進行遍歷，所以每次node都需要往下一個前進，\n在前一個狀況下已經確定了會將node.next接到node.next.next去了，\n若val不同的話，則需要將node的位置移到下一個 去：\nnode = node.next\n還有一個問題，就是如果一開頭的値就符合val的話，\n刪去頭會導致原先的head消失，\n為了避免麻煩，常見的做法是宣告一個dummy node，將其連接到head處。\n中間不論如何都不去動dummy，結尾時再將dummy.next 回傳即可。\nJava的部分，我們初始化一個dummy node並另開一個curr來進行移動。\n**每次curr.next的値符合時，就將curr.next接到curr.next.next，\n否則就讓curr往下走。**這麼一來，只要不斷檢查curr.next是否為NIL並遞進即可。\nJava Python的部分大同小異。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/ O(1))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n我將於11/26 開設系列同名線上課程**「從Leetcode學演算法｜基礎篇」。** 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\n問卷抽書＆取得上架通知： https://pse.is/MS2J2 Leetcode解題挑戰拿優惠： https://pse.is/NAUVP 如果你對線上課程不放心，\n也可以先來12/17(二) 我在天瓏分享的講座看看！\n講座連結： https://pse.is/JS3LJ ","date":"2019-11-20T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-70-linked-list-6/","title":"從LeetCode學演算法 - 70 Linked List (6)"},{"content":"0202. Happy Number (Easy)\nQuestion Write an algorithm to determine if a number is “happy”.\nA happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.\nExample:\n1 2 3 4 5 6 7 Input: 19 Output: true Explanation: 1^2 + 9^2 = 82 8^2 + 2^2 = 68 6^2 + 8^2 = 100 1^2 + 0^2 + 0^2 = 1 分析/解題 給定一個數，試檢查其是否為快樂數(happy number) 。\n所謂的快樂數就是從一個正整數n開始，將其每一個位數的平方和加總，\n作為新的n值，反覆操作，若n最終等於1的話則為快樂數，\n否則若n最終會進入一個不包含1的循環的話，則不是快樂數。\n之前我們介紹過HashTable(HashMap/Dictionary)，\nJava的HashSet和Python的set 其實是類似的概念，不過僅限於單值，\n也就是說它們每筆資料只存放一個值 ，而非key/value相對。\n一個Hash Set裡面，相同的值不能夠重覆出現，\n同時利用了hash的性質，其插入/查找 的速度也是O(1) 。\n這題當中我們唯一需要考慮的問題就是當陷入循環的時候怎麼作判定，\n所以我們可以使用Hash Set來進行記錄，當中若碰到n等於1的時候，\n可以直接回傳true；其他狀況則檢查n是否在Hash Set內 ，\n若是，則表示已經碰到循環了，則可脫離迴圈回傳false 。\n在循環內計算下一個n基本上就是將除以10的餘數平方並移位後加總，\n這邊就不再贅述。\n對Java而言，檢查是否在HashSet內請使用contains() 。\nJava 如果對快樂數有更進一步的認識的話，\n當非快樂數陷入循環時會是固定的模式：\n4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4\n同時，除了1和7以外，低於10的其他數均是非快樂數 。\n所以也可以像上面寫到的另一種解法來處理這個問題，\n在執行時間上對測試資料目前看起來是比較快的。\n對Python而言，使用in來檢查即可。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(時間複雜度不確定，空間複雜度O(1))\n相似及延伸 這題也可以不使用HashSet/set來解，\n請思考看看如果用two pointers的方式的話可以怎麼寫XD\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n感謝大家對這系列文章的支持！這邊跟大家自我工商一下：\n我將於11/26 開設系列同名線上課程**「從Leetcode學演算法｜基礎篇」。** 在這堂課中，你將學會利用十種演算法/資料結構來優化解題過程，\n並實際完整練習20題 精選考古題，\n進而逐漸提升到不需提示也可以突破白板題，取得工作門票！\n問卷抽書＆取得上架通知： https://pse.is/MS2J2 Leetcode解題挑戰拿優惠： https://pse.is/NAUVP 如果你對線上課程不放心，\n也可以先來12/17(二) 我在天瓏分享的講座看看！\n講座連結： https://pse.is/JS3LJ ","date":"2019-11-19T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-69-hash-set-1/","title":"從LeetCode學演算法 - 69 Hash Set (1)"},{"content":"0201. Bitwise AND of Numbers Range (Medium)\nQuestion Given a range [m, n] where 0 \u0026lt;= m \u0026lt;= n \u0026lt;= 2147483647, return the bitwise AND of all numbers in this range, inclusive.\nExample 1 1 2 Input: [5,7] Output: 4 Example 2 1 2 Input: [0,1] Output: 0 分析/解題 給定一個範圍m, n，且0≤m≤n≤2147483647(也就是2³¹-1)，\n回傳這個範圍內(inclusive，即含n)的所有數字的bitwise AND的結果。\n首先這題要先理解inclusive表示頭跟尾都要 ，\n例如[5, 7]，其範圍內的所有數字就是5, 6, 7。\n再者如前面提到過的bitwise operation的部份，\n這邊做的是對每個bit一一對應做AND的操作。\n我們先來看一下範例1，將其化成二進位：\n1 2 3 4 5 : 101 6 : 110 7 : 111 AND : 100 =\u0026gt; Output: 4 注意到由於AND操作要求兩個bit都是1結果才是1 ，\n所以中間一旦出現任意一個0的話，當個bit的AND結果最終必然是0 。\n由於\n已經知道m≤n了，假設m跟n前面存在一組位元長得一模一樣，\n例如：\n1 2 m: 100100101000 (2344) n: 100100111111 (2367) 可以明顯看出從m到n的部份，1001001 的位元是完全不變的，\nAND出來這部分顯然也會保留 ，因為每個數字的這部份都一樣。\n那麼後面呢？\n由於m ≤ n，\n所以在後面不相同的狀況下，開始不相同的m的第一個bit顯然會是0 ，\nn的第一個bit顯然會是1 ，那麼從m一路到n的bit變化，\n就必然有從011…1到100…0 的情況，\n所以後面的所有bit皆至少有出現過一次0 ，\n這會使得後面的區塊經過AND完以後肯定是0 。\n所以整個問題就可以化簡成：\n找到m和n的最前面相同的bit，再將後面補上0即為答案 。\n要找這個很簡單，每次檢查m, n是否相等，若否，\n則各自向右移動一個bit，最終到** m, n相等時，\n只要乘上對應的位移倍數，即為解答。\n讀者可以自行選用將factor視為位移位數** 或必須相乘的倍數 ，\n兩者速度基本相似。\n除此之外還有另一個思路，既然我們只是想要n的前面那區bits，\n那就一次從n剝離一個bit\n( n \u0026amp;= n-1 , 先前的題目有提到可以用來一次去除最低位的bit)，\n直到n≤m為止。這時候留下來的n即為答案，因為低位的全被剝離了。\n依此，寫成程式碼。\n(三者速度差異不大，但最後一種看起來最簡單，讀者可以自行斟酌選擇)\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n的長度)/O(1)，\n因為要做到哪一步端看什麼時候找到m和n前面相同的位置)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-11-11T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-68-bitwise-operation-5/","title":"從LeetCode學演算法 - 68 Bitwise Operation (5)"},{"content":"0191. Number of 1 Bits (Easy)\nQuestion Write a function that takes an unsigned integer and return the number of ‘1’ bits it has (also known as the Hamming weight).\nExample 1 1 2 3 Input: 00000000000000000000000000001011 Output: 3 Explanation: The input binary string 00000000000000000000000000001011 has a total of three \u0026#39;1\u0026#39; bits. Example 2 1 2 3 Input: 00000000000000000000000010000000 Output: 1 Explanation: The input binary string 00000000000000000000000010000000 has a total of one \u0026#39;1\u0026#39; bit. Example 3 1 2 3 Input: 11111111111111111111111111111101 Output: 31 Explanation: The input binary string 11111111111111111111111111111101 has a total of thirty one \u0026#39;1\u0026#39; bits. Note:\nNote that in some languages such as Java, there is no unsigned integer type. In this case, the input will be given as signed integer type and should not affect your implementation, as the internal binary representation of the integer is the same whether it is signed or unsigned. In Java, the compiler represents the signed integers using 2’s complement notation. Therefore, in Example 3 above the input represents the signed integer -3. 分析/解題 給定一個unsigned integer(正整數或0)，試回傳其位元為1的個數。\n這題其實比上一題還要再簡單一點XD\n假設我們將數字稱為n，要計算其位元為1的個數的方式一般有兩個：\n看當前的位數是否為1 來決定是否遞增記錄累積的cnt(count)，\n再將n向右位移1位，直到做完全部32個位元。\n將n每次和n-1相AND，可以去掉最低次的位元。\n舉例來說：\nn=11100 =\u0026gt; 11100 \u0026amp; 11011 = 11000\n(減1時最低位的1會被借位，導致該位變成0，\n其後的位數變成1，從而在相AND時全都會變成0)\nn=10011 =\u0026gt; 10011 \u0026amp; 10010 = 10010\n(最低位的1一開始就在最右邊，顯然減完最右邊變成0，\n同樣會符合去掉最低次的位元的特性)\nJava Python的部份，也可以轉成二進位以後再用count去數'1\u0026rsquo;。\n(不需要考慮前面的0b因為沒差XD)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(1)/O(1)，因最多32次迴圈就結束了XD)\n相似及延伸 Special Thanks suggestions/corrections from viewers: 這題其實一樣可以有更精妙的解法，但同樣不建議在面試時使用。\n(除非你要面試的就是非常在乎效能加速的公司)請參見JDK所使用的Integer.bitCount() 函式原始碼講解：\nhttps://juejin.im/post/5c3969b76fb9a049a5712060\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-11-05T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-67-bitwise-operation-4/","title":"從LeetCode學演算法 - 67 Bitwise Operation (4)"},{"content":"0190. Reverse Bits (Easy)\nQuestion Reverse bits of a given 32 bits unsigned integer.\nExample 1 1 2 3 Input: 00000010100101000001111010011100 Output: 00111001011110000010100101000000 Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 which its binary representation is 00111001011110000010100101000000. Example 2 1 2 3 Input: 11111111111111111111111111111101 Output: 10111111111111111111111111111111 Explanation: The input binary string 11111111111111111111111111111101 represents the unsigned integer 4294967293, so return 3221225471 which its binary representation is 10111111111111111111111111111111. Note:\nNote that in some languages such as Java, there is no unsigned integer type. In this case, both input and output will be given as signed integer type and should not affect your implementation, as the internal binary representation of the integer is the same whether it is signed or unsigned. In Java, the compiler represents the signed integers using 2’s complement notation. Therefore, in Example 2 above the input represents the signed integer -3 and the output represents the signed integer -1073741825. 分析/解題 題目要求將一個32bit長度的integer進行反轉。\n(也就是將二進位制的各個bit 0變成1，1變成0)\n先前我們談過二進位的問題，以及一些位元運算 。\n如果這題有要求處理正負號的問題的話，就會稍微複雜一點，\n因為如題目提示的說明，Java中的有號的integer會使用**二補數\n(2’s complement)**來表示，這件事情隱含了如果將bit位移時，\n需要考慮是\u0026raquo;或\u0026raquo;\u0026gt;的問題。\n負數使用\u0026raquo;時最高位會補1，而\u0026raquo;\u0026gt;時最高位會補0 ，\n由於最高位用來記錄正負號，這會影響到實際得到的結果。\n但我們這邊單純只是要將整個32 bit順序反過來的話就沒有太大問題XD\n我們先從簡單一點的開始，\n比如有一個數字n是1001100(也就是十進制的76)，\n假設我們要將這7個bit反轉，應該要得到0011001，這個過程怎麼來的呢？\n先將我們的答案叫做r(result)，一開始為0，我們先這樣表示：\n1 2 r: n: 1001100 接下來我們要找下一個對應的bit的話，\nn必須要取最右邊的bit才行，記錄完以後，\n為了讓下一次的n的最右邊依然是我們要的bit，\n可以將n進行一次向右位移，即可對到最右邊。\n另外，r為了要記錄下一個位元，每次要向左位移一格，空出最右邊來。\n1 2 r: 0 n: 100110 重複相同的操作，直到n等於0或全部位元操作完畢即可。\n1 2 r: -\u0026gt; 0 -\u0026gt; 00 -\u0026gt; 001 -\u0026gt; 0011 -\u0026gt; 00110 -\u0026gt; 0011001 n:1001100 -\u0026gt; 100110 -\u0026gt; 10011 -\u0026gt; 1001 -\u0026gt; 100 -\u0026gt; 10 -\u0026gt; 1 -\u0026gt; 0 觀察上面的規律，我們可以歸納出對32位元的操作：\n1. 令res為0\n2. 執行32次以下的迴圈：\n2–1. res向左位移1位\n2–2. 將n的最右邊的bit加到res上\n2–3. 將n向右位移1位\n3. 最終res即為答案\n依此，可以寫成如下的程式碼：\nJava的部分，我們使用\u0026laquo;=和\u0026raquo;=進行各自位移後再回存。\n而對應到2-2的部分，除了如第8行的寫法，\n將n和1進行AND運算 來確認最右邊的位元 以外，\n也可以用AND完以後跟res進行OR 的方法。\n此外，由於最開始res是0，\n所以先將其往左位移一次是不會對答案造成影響的。\nJava Python的部分提供一個看到比較特別的寫法：\n使用format將n進行轉換，\n當中0:032b的第一個0可以不用寫 (因為format中也只有一個數字)，\n第二個0代表多出來的部份必須進行補0 (補完反轉才不會有問題)，\n轉成32位的bit後，將其從尾往頭擺順序，\n再用int轉換回integer(指定前面那段是二進制)即可。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，因為必然經過每個位元)\n「如果檢查n是否為0做為結束條件，執行速度是否會較快？」\n(不一定，要看n反轉後的最接近高位的0有多接近，\n否則每次多檢查一次未必比較快)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\nFrom ** 程式人雜誌 — 公益出版** ** - Novus Chou**:\n「 現實中比較講究的位元操作，會盡可能一次處理多位元，\n而且最好不動用迴圈。\n以 8 bit 為例\n12345678\n=\u0026gt; 21 436587 (奇偶交換)\n=\u0026gt; 4321 8765 (兩兩一組交換)\n=\u0026gt; 87654321 (前後半交換)\n類似 C 風格的寫法大概長這樣，\n最後一輪利用整數自然截位所以不用 mask（當然這點要看語言特性）。\nx = (((x \u0026amp; 0xAA) \u0026raquo; 1) | ((x \u0026amp; 0x55) \u0026laquo; 1));\nx = (((x \u0026amp; 0xCC) \u0026raquo; 2) | ((x \u0026amp; 0x33) \u0026laquo; 2));\nx = (x \u0026raquo; 4) | (x \u0026laquo; 4);\n更快的作法就是半查表，也就是把問題分解到某階段改用查的。 」\n(註：利用連續的bit mask進行處理，可達到交換的目的，\n這個方法對於在意效能 來說，\n由於if/while/for 等需要判斷 或有分歧狀況 的程式碼，\n皆須花費相對於位元運算而言較多 的時間，\n能夠單純利用位元運算達成互換會是在實際狀況較棒的解法。)\n(但，其實沒特別用過的話，面試時其實頗難回想出這種解法就是了XD)\n有興趣的話可以參考這兩篇：\nhttps://leetcode.com/problems/reverse-bits/discuss/54741/O(1)-bit-operation-C%2B%2B-solution-(8ms)\nhttps://leetcode.com/problems/reverse-bits/discuss/54746/Java-Solution-and-Optimization 底下的 ** dugu9sword** ** 的回應**\n另外，Java中內建的bitCount 函式(計算某個數的二進位制含有1的數量)，\n也運用了類似的手法達到目的。\n參見： https://www.jishuwen.com/d/2HPI/zh-tw\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n1 如果你／妳覺得這篇文章不錯，請給我5個Like。(點開SHOW EMBED!) ","date":"2019-11-02T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-66-bitwise-operation-3/","title":"從LeetCode學演算法 - 66 Bitwise Operation (3)"},{"content":"0926. Flip String to Monotone Increasing (Medium)\nFlip String to Monotone Increasing (Easy) Question A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possibly 0), followed by some number of '1's (also possibly 0.)\nWe are given a string S of '0's and '1's, and we may flip any '0' to a '1' or a '1' to a '0'.\nReturn the minimum number of flips to make S monotone increasing.\nExample 1 1 2 3 Input: \u0026#34;00110\u0026#34; Output: 1 Explanation: We flip the last digit to get 00111. Example 2 1 2 3 Input: \u0026#34;010110\u0026#34; Output: 2 Explanation: We flip to get 011111, or alternatively 000111. Example 3 1 2 3 Input: \u0026#34;00011000\u0026#34; Output: 2 Explanation: We flip to get 00000000. 分析/解題 一個只含'0\u0026rsquo;和'1\u0026rsquo;的字串在以下的狀況成立時會被視為單調遞增 ：\n數個'0\u0026rsquo;作為開頭(也可能是0個)，其後接著數個'1\u0026rsquo;作為開頭(也可能是0個)。\n(簡單說就是0後面接1就對了，也可以全0或全1)\n給定一個字串s ，且可以將當中任意的'0\u0026rsquo;翻轉成'1\u0026rsquo;，\n也可以將任意的'1\u0026rsquo;翻轉成'0\u0026rsquo;，\n試求要將s經過翻轉操作成為單調遞增 的狀態所需的最小翻轉次數 。\n這題其實某種程度隱含了一點動態規劃的概念在內，\n但相對而言算是較簡單的。\n我們先思考根據單調遞增特性，由於這個特性，\n注定了一旦在某個點變為1，其後的每個單位也必須要是1 才可以。\n若將最後的結果分成兩個狀況的話，事情會變比較簡單：\n全部都是0 前面0後面1(含全部都是1) 考慮做到第i位時，要保持單調遞增所需翻轉的次數:\na. 如果第i位是0，對狀況1來說，不需額外作任何事情即可保持\nb. 如果第i位是1，對狀況1來說，要將第i位翻轉為0(翻轉次數+1)\nc. 如果第i位是0，對狀況2來說，要將第i位翻轉為1(翻轉次數+1)\nd.如果第i位是1，對狀況2來說，相當於從第i-1位時選擇狀況1/狀況2均可\n若我們將上面的狀況1所需的翻轉次數叫做f0，\n狀況2的所需次數叫做f1的話，\n上面的a/c就是第i位碰到'0\u0026rsquo;的狀況 ，此時從第i-1位的f0/f1 更新到第i位 時，\n新的f0不需改變 ，但f1必須遞增 ；\nb/d就是碰到'1\u0026rsquo;的狀況 ，更新時新的f1要取原先的f0, f1中較小的値 ，\n且f0必須要遞增 。\n一開始什麼都還沒做，所以我們可以定f0, f1均為0 ，\n接下來從頭到尾依照碰到的字元進行操作。\n最終，答案只要取f0/f1中較小值 即可。\n依此寫成程式碼：\nJava的部分可以利用for each的語法蜜糖來取出單個char，\n(記得S要先轉成char array)\n且需要留意f0的遞增要在取完f1之後 (不然值會錯)。\nJava Python的部分亦同，記得只有+=沒有++這種東西XD\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，需遍歷整個String的長度，但記錄用輔助變數只需常數單位)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-28T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-65-array-13/","title":"從LeetCode學演算法 - 65 Array (13)"},{"content":"0080. Remove Duplicates from Sorted Array II (Medium)\nQuestion Given a sorted array nums, remove the duplicates in-place such that duplicates appeared at most twice and return the new length.\nDo not allocate extra space for another array, you must do this by modifying the input array ** in-place** with O(1) extra memory.\nExample 1 1 Given nums = [1,1,1,2,2,3], 1 Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively. 1 It doesn\u0026#39;t matter what you leave beyond the returned length. Example 2 1 Given nums = [0,0,1,1,1,1,2,3,3], 1 Your function should return length = 7, with the first seven elements of nums being modified to 0, 0, 1, 1, 2, 3 and 3 respectively. 1 It doesn\u0026#39;t matter what values are set beyond the returned length. Clarification:\nConfused why the returned value is an integer but your answer is an array?\nNote that the input array is passed in by reference , which means modification to the input array will be known to the caller as well.\nInternally you can think of this:\n1 2 // nums is passed in by reference. (i.e., without making a copy) int len = removeDuplicates(nums); 1 2 3 4 5 // any modification to nums in your function would be known by the caller. // using the length returned by your function, it prints the first len elements. for (int i = 0; i \u0026lt; len; i++) { print(nums[i]); } 分析/解題 給定一個已排序的陣列nums，將其重復超過2次的部分捨棄掉，\n且使用in-place的方式來操作(在原陣列操作)，回傳最終結果的長度。\n這題算是之前的0083. Remove Duplicates from Sorted List (Easy)的延伸，說真的我認為這題不該當作Medium難度XD\n再次提醒，當題目要求使用in-place的時候，\n對一些語言的確是可以真的用刪掉單點 的方式來處理(例如Python)，\n但刪除這件事情也是較耗時的操作，所以沒特別要求的話，\n請依照題目希望你的方向來撰寫(面試則依照面試官的限制條件 )。\n我們先來講筆者直觀想到的解法，再來提leetcode上另一位高手的解。\n直觀而言，要怎麼能夠知道有沒有碰到3個 以上的重復呢？\n最直接的方式就是使用一個cnt變數來記錄。\n同時，為了要確認是否是重複的數，\n我們需要記錄上一次開始重復的數last。\n那麼步驟就會像這樣：\n如果nums長度 ≤ 2 的話，表示完全不用更動，\n直接回傳nums的長度 即可。 將last設為nums[0], cnt設為1, 預計要覆蓋的** index j設為1。** 令i從1開始一個迴圈來遍歷整個nums:\n3-a. 如果nums[i]不等於last 的話，表示數字不同 ，\n必須將其覆蓋到j的位置 。\n同時，我們必須更新last為nums[i]，j要遞增，\ncnt要重設為1 (用來做下一次比較)。\n3-b. 否則，如果兩者相等且cnt小於2 ，\n代表重複未超過2次，同樣要進行複寫和遞增j，但cnt要遞增 。 當整個迴圈完畢以後，j 應該是位在處理過後的陣列的尾端+1 的位置。\n所以回傳j即可代表新的陣列的總長 。 聽起來有點多，但其實寫起來並不困難，\n但還有更厲害的解法XD\n這邊提供了LeetCode上StefanPochmann 的解，\n簡單來說呢，我們可以換個思路：\n由於整個陣列是排序過的 ，當我們遍歷陣列時，\n某個數字應不應該要覆蓋到index上 ，\n(筆者之前的解法將這個index叫做j，相當於這個解裡的i)\n取決於前面兩個數字是否跟它一樣 ；\n都一樣的話，就產生了三個相同的數 的狀況，\n自然不需要再被取用，且由於排序的關係，\n我們只需要比較前面兩個數字中較前面的那個 即可。\n當i小於2時，直接無條件覆蓋( 因為不可能重複超過2次)；\n當遍歷到的値n大於num[i-2] 時，代表數字不一樣 或重複未超過2次 ，\n則應將其值覆蓋過去並遞增i 。\n各自寫成程式碼如下：\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，我們需要遍歷整個陣列，且儲存用的輔助變數只有常數個)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-22T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-64-array-12-two-pointer-3/","title":"從LeetCode學演算法 - 64 Array (12) / Two Pointer (3)"},{"content":"0077. Combinations (Medium)\nQuestion Given two integers n and k, return all possible combinations of k numbers out of 1 … n.\nExample:\n1 2 3 4 5 6 7 8 9 10 Input: n = 4, k = 2 Output: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ] 分析/解題 給定兩個整數n跟k，回傳所有1~n之間取k個數字的組合。\n這題其實跟先前的0078. Subsets非常的接近，\n差別在於我們必須改成取得固定k個 ，\n所以現在考慮上必須要將**「目前將取到第幾個數字」** 這件事情納入考量。\n那麼，我們可以同樣用backtracking(回溯法) 的方式來考慮。\n我們考慮初始化一個組合combo ，從1 開始決定要不要加入組合中，\n並記錄現在走到的index(以i表示) 。\n那麼，我們需要傳入的參數值有：\ncombo (當前未完成的組合), res (記錄結果的所有已完成的組合),\nn (1~n的數字), k(連同當前這輪，還有幾個數字要被納入組合 ),\ni (當前走到的數字)\n那麼，我們可以使用遞迴(命名為findCombos)來處理這題，\n當k等於0 時，表示已經完成這個組合，將其加入res中 ；\n否則當i ≤ n 時，表示還有** 可以選擇的數字**(** 且組合還沒完成**)，\n此時可以分成 a. ** 將i加入combo 或 b. 不加入combo** 中。\na. 將i加入combo中的話 -\u0026gt; ** 代入findCombos的遞迴中k要減1，i要加1。\n且這輪下去遞迴完以後，記得將狀態復原(把combo的最後一個數字拿掉)\nb. 不將i加入combo的話** -\u0026gt; 代入findCombos的遞迴僅需i要加1即可。\n(因為只有當前選擇的數字增加)\n除此以外，我們可以額外考慮一件事情：\n由於剩下的可選數字應該大於我們還需要選擇的數字 ，\n所以 i≤n 的條件應該可以進一步縮限成 ** i+k-1 ≤ n**。\n依此，寫成如下的程式碼。\nJava的部分，可以使用ArrayList/LinkedList皆可，\n並且保險起見，可以先行檢查n和k。\n(畢竟測資也有可能弄個不合法的負數或零)\nJava 如之前的文章，Python請不要忘記append到combo上的必須是複製的list。\n此外也可以使用itertools的combination來直接得到答案，\n但請不要 在面試的時候這樣用XD\n(因為這只證明了你知道工具，而不是你懂回溯法)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(C(n, k))/O(k*C(n,k))。\n由於k的値會影響階乘連接的個數，所以不好化簡。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-18T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-63-backtracking-4-dfs-6/","title":"從LeetCode學演算法 - 63 Backtracking (4) / DFS (6)"},{"content":"0102. Binary Tree Level Order Traversal (Medium)\nQuestion Given a binary tree, return the level order traversal of its nodes’ values. (ie, from left to right, level by level).\nFor example:\nGiven binary tree [3,9,20,null,null,15,7],\n1 2 3 4 5 3 / \\ 9 20 / \\ 15 7 return its level order traversal as:\n1 2 3 4 5 [ [3], [9,20], [15,7] ] 分析/解題 給定一個二元樹，回傳其節點値的層序遍歷結果。\n我們在先前的文章中，\n已經提到過層序走訪(level-order traversal)的概念了，\n按照題目範例，這邊要將level分層開來。\n對於遞迴 解來說，如果使用一般的DFS的話，\n我們將不知道哪一個節點位在哪一個level上，\n故我們將必須加入變數level ，\n讓level的值來幫助我們辨別要加到List的哪個level區塊中。\n所以對於遞迴解而言，在主函式 中：\n檢查根節點 將root的值加入第0層的list 中，再將該list加到答案res 中 呼叫幫助用的函式，將level遞増代入 (表下一層) 在幫助用函式 中：\n先檢查代入進來的節點，\n若遇到NIL則表示到此為止 ，進行回傳即可。 檢查目前res的size 和level 的關係，\n若相等則表示要開一個新的list(因為level從0起算 )；\n否則，找到對應level的list，將該節點的值加入。 分別檢查左節點和右節點進行遞迴 。 觀察這樣子的遍歷方式，讀者應該可以發現一點：\n幫助用的函式本質上就是在做pre-order traversal。 之所以會達成我們想要的效果，是因為我們額外記錄了level這個資訊。\n如果使用迭代法 來解呢？\n我們可以建立一個Queue ，在每一層先行取得Queue的大小(長度) ，\n每次迴圈只要剛好執行這個次數，\n就可以不斷利用相同的Queue來堆出不同的層數 ，\n再分頭將對應的左節點和右節點推入Queue中 。\n(記得要先檢查，非NIL才需要推入)\n最終所有節點都遍歷過一遍時，\n剛好Queue裡面也不會留存任何節點。\n依照上述說明，請參考對應的程式碼。\nJava的部分，記得用來檢查的isEmpty() ，以及可以用LinkedList 來實作Queue 的部分。\nJava Python用deque (記得我們提到過的，list在移除左端的部分效率較差 )\n另外，若幫助函式沒有要再被其他函式使用，\n是可以考慮如底下34行以後這樣子寫成子函式的方式再呼叫的，\n可以省去要加一堆self的狀況。\n(但要記得：Python函式要先宣告才能呼叫 )\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，因為要遍歷全部節點並記錄)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-16T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-62-tree-10/","title":"從LeetCode學演算法 - 62 Tree (10)"},{"content":"1140. Stone Game II (Medium)\n寫在前面 大家連假過的好嗎XD？筆者到新加坡玩了一趟，不好意思好幾天沒更新啦~\nQuestion Alex and Lee continue their games with piles of stones. There are a number of piles arranged in a row , and each pile has a positive integer number of stones piles[i]. The objective of the game is to end with the most stones.\nAlex and Lee take turns, with Alex starting first. Initially, M = 1.\nOn each player’s turn, that player can take all the stones in the ** first** X remaining piles, where 1 \u0026lt;= X \u0026lt;= 2M. Then, we set M = max(M, X).\nThe game continues until all the stones have been taken.\nAssuming Alex and Lee play optimally, return the maximum number of stones Alex can get.\nExample 1 1 2 3 Input: piles = [2,7,9,4,4] Output: 10 Explanation: If Alex takes one pile at the beginning, Lee takes two piles, then Alex takes 2 piles again. Alex can get 2 + 4 + 4 = 10 piles in total. If Alex takes two piles at the beginning, then Lee can take all three piles left. In this case, Alex get 2 + 7 = 9 piles in total. So we return 10 since it\u0026#39;s larger. Constraints 1 \u0026lt;= piles.length \u0026lt;= 100 1 \u0026lt;= piles[i] \u0026lt;= 10 ^ 4 分析/解題 聽說之前有人一直嗆說怎麼都沒人能夠將1140這題講清楚？\n這題其實題目不難理解：\nAlex和Lee兩個人玩搶石頭的遊戲，石頭被分成數堆，\n使用piles[i]來記錄，遊戲目的是在結尾時拿到最多的石頭。\nAlex和Lee輪流拿石頭(Alex先 )，最開始的時候M設定為1 。\n每次玩家要決定拿剩下的前X堆的所有石頭 (必須按順序不可以跳過 )，\nX的範圍是1 ≤ X ≤ 2M；接下來就要依照X來更新M：M = max(M, X)\n直到所有石頭都被拿光，遊戲就結束了。\n假定Alex和Lee都以最佳化的狀況來玩這個遊戲(play optimally)，\n回傳Alex在遊戲結束時最多能拿到的石頭。\n在所謂\u0026quot;play optimally\u0026quot;的遊戲中，\n我們會假設參與的玩家都清楚知道所有人的策略 ，\n並且選擇對自己利益最大的選擇 。\n依照這樣子的概念，我們其實可以感覺到前後會有所關聯，\n因為對於雙方來說都是想要最大化自己拿到的石頭 ；\n又，自己拿到最多，就意味著對方拿到最少 ，\n所以這點同時還隱含了中間的可能會有一些判斷，\n比如像是X這類型的變數對於同樣從第i堆開始來說，\n要走哪個方向又會都有各自的分支，需要好好考慮才行。\n我們先假定有一個函數dp，\n這個函數可以計算當現在要從pile[i]開始拿的時候，\n(也就是0~i-1堆都被拿光了)\n輪到的玩家在這次及這輪以後所能拿到的石頭數的最大值。\n顯然這還會有另一個變數M，\n因為M能夠決定這輪最大可以拿到的堆數(2M)。\n因此我們將這個函數表示成dp(i, M)。\n先討論一個最簡單的狀況：\n當i+2M ≥ n-1 的時候，(假設總石頭的堆數是n)\n表示這個玩家可以直接選擇將剩下的石堆全取走 ，\n就會是他所能拿到的石頭量的最大值。\n(因為遊戲就結束了，另一個玩家什麼都拿不到)\n所以這個就會是這個dp的確定值 的部分了。\n接下來我們討論另一個狀況：(假設是A跟B玩家輪流拿石頭)\n假設A玩家取了x堆 ，接下來會發生什麼事情呢？\n輪到下一個玩家B了，對吧？\n那麼玩家要從i+x堆 的位置開始拿取，\n而此時的M按照遊戲規則是max(M,x) 。\n由於B同樣也是play optimally ，\n所以B也想最大限度的在這整場遊戲中獲得較多的石頭 ，\n故對B而言在i+x堆開始拿取的數字按照定義就是dp(i+x, max(M,x)) 。\n那麼關鍵來了：\n對於dp(i,M) 而言，固定不變的會是從pile[i]到最後的石堆的石頭總量 ，\n我們暫時先命名為Si, Si = pile[i]~ pile[N-1]的和 。\n所以會變動的就只有B拿的部分而已。\n所以我們可以得到dp(i, M) = Si - dp(i+x, max(M, x)) 。\n又實際上我們一開始也不知道x應該取多少會最好，\n所以x的範圍一樣是1~2M ，也就是我們要在x是這個範圍的所有狀況下，\n找出dp(i+x, max(M, x))的最小值，從而得到dp(i, M) 。\n(因為想要A拿的最多，就是要B拿的最少 ，故要取後者的最小值)\n在實務上，我們可以拿前面的piles來計算Si，只要一路從尾到頭 ，\n將piles的値往回加即可(因為Si = piles[i]piles[N-1]的和)。\n我們需要一個二維陣列dp[][]，\n第一個維度表示i (範圍是**0n-1** )\n第二個維度表示M (範圍是1~(n-1)/2 + 1 ，但為了方便起見，\n我們陣列只使用1開始的部分以避免位移，\n所以再加一以後，我們第二維的長度會是**(n+1)/2 + 1** )\n我們整理一下實際的演算流程。\n主函式中:\n從尾到頭 將piles[i+1] 加到piles[i] 上，\n讓piles[i]現在代表從第i堆開始的所有石頭數 。 新增一個二維陣列dp[][] 以表示在**(i, M)** 條件下所能取得石頭的最大値。 呼叫helper函式來遞迴 處理。\n在helper函式中: 如果i已經走超過了則回傳0 (表遊戲結束) 如果2*M \u0026gt;= len(piles) - i則回傳piles[i] (一口氣取完剩下的石頭 ) 當dp[i][M]尚未被計算出値的時候，\n遞迴搜尋dp[i+x][max(M,x)]的最小值 ，(x範圍是1~2*M)\n(已知値的話則直接代入) dp[i][M]等於piles[i]減去前述的最小值 回傳dp[i][M] 依此，寫成程式碼：\nJava Python的部分，可將遞迴的部分搭配\nfor x in range(1, 2 * M + 1) 看起來會更簡潔。\nPython Python的部份根據大神lee215的解答，還可以做一些簡化：\n1 2 3 4 5 6 7 8 9 10 def stoneGameII(self, A: List[int]) -\u0026gt; int: N = len(A) for i in range(N - 2, -1, -1): A[i] += A[i + 1] from functools import lru_cache @lru_cache(None) def dp(i, m): if i + 2 * m \u0026gt;= N: return A[i] return A[i] - min(dp(i + x, max(m, x)) for x in range(1, 2 * m + 1)) return dp(0, 1) lru_cache 可以將函式已經計算過的結果直接快取放置在記憶體中，\n當再次需要計算値的時候，不經過計算，直接將値回傳 。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N³)/O(N²)，因為記錄所有解要對應到二維陣列，\n而對於每一個陣列解都需要往下搜尋O(N)的長度來比較得出最小值。)\n「為什麼要記錄一個dp的陣列？不能直接靠遞迴記錄嗎 ？」\n(遞迴記錄同樣要使用記憶體空間 ，且因為中間拆解時，\n可能會有重複的(i, M)出現，不先記錄的話會造成有重複計算的狀況。 )\n「這題是否可以用迭代法解？」\n(可以，請參閱yzstone的解法。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-13T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-61-dynamic-programming-9/","title":"從LeetCode學演算法 - 61 Dynamic Programming (9)"},{"content":"0078. Subsets (Medium)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given a set of distinct integers, nums, return all possible subsets (the power set).\nNote: The solution set must not contain duplicate subsets.\nExample:\n1 2 3 4 5 6 7 8 9 10 11 12 Input: nums = [1,2,3] Output: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ] 分析/解題 給定一組內含相異的整數的集合nums，試回傳其power set。\n(所有可能的子集合，包含空集合)\n我們先考慮一下所謂的子集合。\n所謂的子集合就是在指說，在nums所有的元素(element)中，\n有哪些要被用，哪些不要被用的所有組合。\n所以對於每個數都有加進去/不加進去的兩種可能，\n如果nums有N個元素，所有的組合的可能是就會是2^N。\n我們可以透過上述的思路來建構遞迴的函式。\n首先，我們先產生一個subset，\n用來存放走到當前的狀況 ，\n而一個確定可以放進結果res的subset，\n必須是將整個nums走完且決定誰要進，誰不要進才行。\n要放進subset和不放都是可行的選擇，\n那麼我們就必須要分岔成兩條路 ：\n將當前遇到的數字置之不理，直接朝向下一個index走 先將當前遇到的數字加進subset中 ，再朝下一個index走\n留意當回到上一層 的時候，這個index遇到的數字同樣應該要被取消掉 ，\n所以我們應該要從subset中拔掉最後一個數字 。 那麼遞迴的尾端 ，自然就是當index走超過範圍 的時候，\n此時我們應該將這個subset作為其中一個結果放入到res中，\n並回到上一層。\n依此，我們可以寫成如下的程式碼。\n在Java的部分，List使用LinkedList或ArrayList皆可，\nArrayList適用於需要取得某個點的値，\n而LinkedList在儲存時會稍微快一點，\n請留意我們在新增組合時是使用new ArrayList\u0026lt;\u0026gt;(subset) ，\n用以加入subset的複本來放入res中。\n如果單純放subset的話，由於大家都指向相同的位置，\n後面修改subset的時候會導致res內的內容也同部被改到，\n請務必留意XD\nJava 這邊也提供了參考的其它解，包含了迭代解和另一種遞迴解，\n概念都是**拿現在的所有組合和新的數字，決定要加或不要加，\n用以衍生出兩倍的組合。**這種方法其實概念上類似我們之前提到的Gray Code的解法，\n用原先的部分來組新的東西，有興趣可再參考。\nPython的部分一樣需注意subset要使用copy來複製一份使用。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(2^N)/O(2^N)，因每種組合皆須經過一次，且都要存入結果。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-07T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-60-backtracking-3-dfs-5/","title":"從LeetCode學演算法 - 60 Backtracking (3) / DFS (5)"},{"content":"0079. Word Search (Medium)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given a 2D board and a word, find if the word exists in the grid.\nThe word can be constructed from letters of a sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.\nExample:\n1 2 3 4 5 6 board = [ [\u0026#39;A\u0026#39;,\u0026#39;B\u0026#39;,\u0026#39;C\u0026#39;,\u0026#39;E\u0026#39;], [\u0026#39;S\u0026#39;,\u0026#39;F\u0026#39;,\u0026#39;C\u0026#39;,\u0026#39;S\u0026#39;], [\u0026#39;A\u0026#39;,\u0026#39;D\u0026#39;,\u0026#39;E\u0026#39;,\u0026#39;E\u0026#39;] ] 1 2 3 Given word = \u0026#34;ABCCED\u0026#34;, return true. Given word = \u0026#34;SEE\u0026#34;, return true. Given word = \u0026#34;ABCB\u0026#34;, return false. 分析/解題 給定一個2維棋盤和一個字(word)，檢查這個字是否存在這個棋盤裡。\n構成字的方式是從棋盤的某一格開始，連續選取相鄰的格子。\n同時，相同的格子不能使用兩次。\n前面提到過Backtracking(回溯法)，\n這題同樣也是典型的DFS+Backtracking方法可以處理的對象。\n首先，要構成一個字，就要從棋盤上選擇一個位置開始往下 。\n每次選一個相鄰的格子，拿來跟word比對，\n都必須要和word對應的位置上的字元(char)相同才行，\n所以這表示我們還要記錄現在比對到哪個index 了。\n同時，由於用過的格子不能重複使用，每次在進入dfs的時候，\n我們必須要記錄是否有造訪(visit)過這個格子 ，\n才往更深處呼叫；同時，在該層的四個方向都判斷完以後 ，\n回到上一層之前，必須將造訪的紀錄還原回去 。\n(因為我們只有在這次走這條路的時候有造訪，\n回到上一層的時候這個格子應該處於沒有造訪過的狀態)\n所以最開始我們要做的事情是，\n使用迴圈分別將每個cell作為起始點，開始進行搜尋。\n(搜尋的遞迴函式如果其中一次是True的話就可以直接回傳True)\n每次搜尋的時候，傳入的有：\nboard(棋盤), r, c(當前的cell位置), index(比對到word的哪一個char), word\n每一次我們要做的步驟：\n檢查board[r][c]和word的index處的值是否不同 ，\n不同則回傳False 表示這條路行不通。 檢查index 是否已經走到最後了(length of word - 1 )，\n是的話代表這條路到這邊剛好就是答案，回傳True 。 將index遞增 (接下來要給下面遞迴使用)，並將board[r][c]標明已造訪 。 分別以往上下左右 方向的新的(r, c)值來代入函式進行遞迴搜尋 ，\n如果結果是True的話，直接回傳True 。(也就是下面的部份都不用做了XD)\n(這邊記得要檢查上下左右移動一格以後是否超出board範圍 ) 前面四個都是False的狀況，代表這條路行不通了，\n我們要回到上一步，這時候要先將board[r][c]標明未造訪 ，\n才回傳False 。 如果跑完整個棋盤，都沒有能夠成立的路徑的話，\n就應該回傳False 作為答案。(因為我們沒有找到可行的路徑)\n在實作時為了方便起見，我們可以宣告class的變數來放一些常用的東西，\n這邊用了wlen(word的長度), row, col(board的列/行數)。\n需要注意的是，在實作造訪與否的紀錄時，\n我們可以選擇使用像是visited[][]的二維陣列來寫，\n但也可以採用別的方法，比如將裡面的值暫時設為\u0026quot;0\u0026quot;，\n後面再還原，或者像Java這邊寫的將其和128進行XOR 。\n為什麼和128進行XOR呢？\n因為ASCII中的所有字元值均不超過128，\n也就是說，它們在二進位上的第8位數(由右數到左)均為0 。\nXOR後，第8位數會變成1，所以再度遞迴下去比對時，\n就不可能等於任何字元，從而達到標示造訪過的目的。\n還原回來的時候，因為：\na XOR 128 XOR 128 ＝ a XOR 0 = a\n(先前的文章 有提到過的Bitwise Operation)\n所以再重複用128進行一次XOR即可還原原先的值 了！\n寫成程式碼如下：\n(留意Java可以直接對char當作是數字來操作 )\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(如果row = m, col = n，word長度=l的話，從每個點出發一次，\n並且每次都有4個方向的選擇(但只有三個方向能繼續延伸)，\n時間複雜度會是O(m * n * 3^L)。\n空間複雜度的部分，如果考慮call stack的話，最大會是O(L)，\n不考慮的話，由於沒有使用visited[][]來處理，則會是O(1)。\n如果用visited來存放的話則是O(m*n))\n「在Python中是否可以使用類似Java對char的解法來處理呢？」\n(可以，請使用ord()將單個字元進行轉換成數字再進行xor，\n不能直接用str型態的値來處理。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\nRaiy Kuo: 細算的話選擇方向這部份的時間複雜度是3^L，\n詳情請見response中的討論。\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-59-backtracking-2-dfs-4/","title":"從LeetCode學演算法 - 59 Backtracking (2) / DFS (4)"},{"content":"0075. Sort Colors (Medium)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.\nHere, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.\nNote: You are not supposed to use the library’s sort function for this problem.\nExample:\n1 2 Input: [2,0,2,1,1,0] Output: [0,0,1,1,2,2] Follow up:\nA rather straight forward solution is a two-pass algorithm using counting sort.\nFirst, iterate the array counting number of 0’s, 1’s, and 2’s, then overwrite the array with the total number of 0’s, then 1’s and followed by 2\u0026rsquo;s. Could you come up with a one-pass algorithm using only constant space? 分析/解題 給定一個陣列當中有n個物件，被著色成紅、白、藍，\n請將其以in-place的方式將同顏色排序至相鄰，並順序亦為紅白藍。\n這裡給定的陣列顏色紅/白/藍分別以0/1/2代表。\n如果有印象的話，大家可能還記得之前有一題Move Zeroes，\n差別在於這題是0, 1, 2，我們依舊可以用類似的概念來解題。\n使用3個變數來分別記錄0/1/2的個數，\n等到計完了，再依序覆寫到nums裡面，就可以得到答案，\n這麼做會需要掃過陣列兩次，第一次用來計數，第二次用來填入新的値。\n那麼，題目也問了：\n有沒有辦法給出一個one-pass 的演算法來解此題呢？\n(one-pass algorithm意思是指說只掃過整個資料一次，詳見wiki)\n我們可以仿照先前的Two Pointer 的概念來思考。\n首先，1在這個陣列當中是我們較不在意的部分，\n因為它一定是排在整個陣列的中間，\n然後左邊區塊最後會是0，右邊區塊最後會是2。\n假設我們要排序，所要做的就是將0的部分都往左邊擺，\n將2的部分都往右邊擺；最開始的時候，因為還沒排過，\n我們可以將下一個要擺放的位置命名為i0和i2，\n並假定應該要擺在0和n-1的位置。(陣列的最左邊和最右邊)\n接下來，依序掃描整個陣列(假設迭代的index為i)，會有以下三個情況。\n碰到1:\n因為將0和2都擺完以後1自然在中間，所以完全不用管它XD\n碰到0:\n我們應該將其擺放在i0的位置 ，\n但原先i0所在的値不能平白消失，所以將其和i位置的値相交換。\n換完之後，i0 因為已經填入0了，\n故下個要填入0的位置必須更新 ，所以將i0遞增 。\n碰到2:\n同理，將其擺在i2的位置，和i位置的値相交換，再遞減i2 ；\n需要注意的是由於i的位置換到我們不知道值的部分 ，\n(前面碰到0的時候換的應該都是1，所以沒有影響)\n所以將i遞減，抵銷掉i在整個迴圈中每次加1的部分 ，\n以便迴圈的下一輪能檢查相同的位置。(檢查換過來的値 )\n這整個迴圈的結束時間點應該在i和i2交錯的時候 ，\n因為這代表後面都是2，既然後面已經相當於排完，\n就可以結束整個迴圈了！\n寫成程式碼如下，\n幾個需要簡單注意的地方是，\n當使用第一種方法 的時候，\n其實可以直接開一個長度為3的陣列 來儲存數字出現次數；\n其次，使用第二種方法 時，Python當需要判定條件會改變的狀 況時，\n請使用while迴圈 ，因為for in range的寫法沒辦法動態地去改變條件。\n(另外別忘記Python沒有++或 — ，請用+=和-=)\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，不論哪個解法，最多就是掃描過2次的nums的長度，\n且我們基本上只會用到三個記錄各自數量的變數或三個索引值)\n相似及延伸 1.0148. Sort List (Medium) 2.0324. Wiggle Sort II (Medium) Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-10-01T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-58-two-pointer-2/","title":"從LeetCode學演算法 - 58 Two Pointer (2)"},{"content":"0074. Search a 2D Matrix (Medium)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:\nIntegers in each row are sorted from left to right. The first integer of each row is greater than the last integer of the previous row. Example 1 1 2 3 4 5 6 7 8 Input: matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] target = 3 Output: true Example 2 1 2 3 4 5 6 7 8 Input: matrix = [ [1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 50] ] target = 13 Output: false 分析/解題 給定一個m x n的矩陣，此矩陣每列(row)都是從左到右升冪排序；\n同時此矩陣每列的第一個值都比前一個列的最後一個值還要大。\n試找出一個有效率的演算法，\n來處理在這個矩陣搜尋一個值是否在這裡面。\n有沒有覺得很熟悉？\n其實這題的延伸題目就是上一題，作為同樣Medium難度的題目，\n這題就要來得簡單許多。\n為什麼呢？\n因為按照題目的定義的話，\n我們假設從每一列的尾巴接到下一列的頭，\n最終就會得到一個完整的已排序陣列。\n那麼，已排序陣列的搜尋方式，\n我們以前已提到過了，就使用基本的二元搜尋法(Binary Search) 即可。\n(還沒弄清楚或還不知道二元搜尋法的讀者，可以參見前面這篇 。)\n那麼我們所要做的，就只剩下將matrix上的index，\n轉為如果攤平以後對應到的陣列index即可。\n對於matrix[i][j]來說，\n由於有m列n行，i代表從0到i(總共i+1個列) ，\n所以前面會經過i列，共 (i * n) 個數字；\n接著要往右邊移動，\nj代表從0到j有j+1個數字 ，再相加起來，\n所以matrix[i][j]是整個攤平以後的第(i * n + j + 1)個數字，\n從0開始起算的話就是(i * n + j)。\n因此，如果我們找到某一個中間index mid ，\n要轉換成i, j 的型式的話，\n就只需要分別取除以n得到的商和餘數 即可。\n依此進行二元搜尋的時候，其方式就和一般的二元搜尋一模一樣，\n若跳出迴圈則代表該目標值不存在於matrix中，則回傳false 。\nJava Python的部分請不要忘記取整數除法要用雙斜線\u0026quot;//\u0026quot;。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(log(mn))/O(1))\n相似及延伸 0240. Search a 2D Matrix II (Medium) Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-29T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-57-binary-search-4/","title":"從LeetCode學演算法 - 57 Binary Search (4)"},{"content":"0240. Search a 2D Matrix II (Medium)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:\nIntegers in each row are sorted in ascending from left to right. Integers in each column are sorted in ascending from top to bottom. Example:\nConsider the following matrix:\n1 2 3 4 5 6 7 [ [1, 4, 7, 11, 15], [2, 5, 8, 12, 19], [3, 6, 9, 16, 22], [10, 13, 14, 17, 24], [18, 21, 23, 26, 30] ] Given target = 5, return true.\nGiven target = 20, return false.\n分析/解題 給定一個m x n的矩陣，此矩陣每列(row)都是從左到右升冪排序；\n同時此矩陣每行(column)都是由上到下升冪排序。\n試找出一個有效率的演算法，\n來處理在這個矩陣搜尋一個值是否在這裡面。\n這題乍看之下沒有這麼直觀，如果我們從matrix[0][0]出發的話，\n顯然馬上就會碰到問題：\n「好現在target比1大，我該往哪邊走？」 看來怎麼走都不對是吧？如果透過暴力的方式來一排一排找，\n結果時間複雜度會是O(mn) 。\n就算有想到Binary Search 可以處理已排序的陣列，\n每次取一行或一列來搜尋值，\n時間複雜度也只會降到O(m log n)或O(n log m) ，\n似乎還是不那麼理想。\n那麼，該怎麼考慮這個題目呢？\n翻了翻提示，居然也是寫Binary Search；\n而Binary Search的精髓，\n其實就在於可以在每次的抉擇中保留需要的那部分的選項 。\n那麼，回頭看看上面的矩陣，想要能夠靠選擇每次去掉選項，\n我們考慮看看15這個點如何？\n當target等於15 的時候，就直接是答案了，回傳true 。\n當target不是15 的時候，可以分成比15大，或比15小 。\n比15大 的狀況：\n代表原先15的一整列(1, 4, 7, 11, 15)已經都不用考慮了 ，\n因為15已經是這整列的最大值 ，故我們可以挑到19，\n因為19這行還沒看過，\n同時(15, 19, 22, 24, 30)這當中也是越來越大，\n所以挑選19可以繼續進行比較，\n這個操作就相當於扣掉一整列的備選 。\n比15小 的狀況：\n代表原先15的一整行(15, 19, 22, 24, 30)不用考慮了，\n理由跟1.講得相似，只是這次我們就變成往右走挑到11 ，\n整個操作相當於扣掉一整行的備選 。\n我們每次刪去一行或一列，那麼總共有m列n行的話，\n最多就要操作m+n次 才能確認target是否在matrix中。\n(因為每次扣掉一行或一列的備選嘛)\n所以其實再仔細一看，\n如果我們將這個矩陣往逆時針轉45度，\n(或將你的頭順時針轉45度)，\n你會發現這整個矩陣其實可以當作一個以15為根結點的二元樹 。\n(不過由於它的特性，可以想像它還有其它不只二元樹的連結)\n(或者更準確的說，它就是有向圖(Oriented Graph) )\n所以我們的整個演算法如下：\n檢查matrix是否正常，不正常則直接回傳false 將初始點定在**(i, j)=(0, n-1)** 的位置 當i和j都沒有超過邊界 的時候，進行下面的迴圈：\n3-a. 若target和當前點的値相等 ，回傳true\n3-b. 否則若target較大，將i遞增\n3-c. 否則將j遞減 若迴圈結束尚未回傳，代表這個值不在矩陣內，\n回傳false結束。 寫成程式碼如下所附。\n(也有人判斷第一步的時候用\u0026lt; 1而非==0，但測試目前沒有明顯差異，\n讀者依自己喜好選擇寫法即可。)\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(m+n)/O(1)，因為每次都會刪去一行或一列，最差狀況就是全部刪完。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\nPython Taiwan 王彥珽：** 直行橫列**才對(註：中國才是橫行直列XD)\n(但我工作就會講row跟column啦)\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n1 2 如果你／妳覺得這篇文章不錯，請給我5個拍手，並且給我5個Like。 (點開最上面的SHOW EMBED!) ","date":"2019-09-26T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-56-binary-search-3/","title":"從LeetCode學演算法 - 56 Binary Search (3)"},{"content":"0236. Lowest Common Ancestor of a Binary Tree (Medium)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.\nAccording to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself ).”\nGiven the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4]\nExample 1 1 2 3 Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 Output: 3 Explanation: The LCA of nodes 5 and 1 is 3. Example 2 1 2 3 Input: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 Output: 5 Explanation: The LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition. Note:\nAll of the nodes’ values will be unique. p and q are different and both values will exist in the binary tree. 分析/解題 給定一棵二元樹，試找出樹中兩個給定的節點的最低共同祖先(LCA)。\n整棵樹的節點值均不同，且兩個節點p, q是不同的節點，\n且會存在於此樹上。\n由於不同於之前的0235題，這題是二元樹而非二元搜尋樹，\n所以我們於此喪失了可以透過比大小來決定要往哪個方向走的可能。\n那麼怎麼辦呢？\n對於兩個節點的最低共同祖先來說，有一個特性是絕對肯定的，\n就是以下3點必然會恰好成立2點 ：\n1. 節點自己是p或q\n2. 節點的左子樹有p或q\n3. 節點的右子樹有p或q\n1, 2和1, 3應該很直觀，就不多作解釋了，\n這邊有一點很重要的是，當共同祖先不是p或q 的時候，\n如果p和q都分布在同一邊的子樹，那它就不會是最低共同祖先 ，\n因為我們還可以再往下找更低的共同祖先。\n所以1不成立的時候，2, 3都必須要成立才行 ，\n這樣才能符合最低 的特性。\n我們可以運用DFS 的方式來確認一個節點的左子樹/右子樹是否符合特性，\n並且同時判斷該節點是否是p或q之一 ，\n這樣一來，只要三者成立兩點 的時候，就表示我們找到目標了，\n可以將答案記錄下來。\n所以只要將整棵樹遍歷過一次，最後回傳記錄下來的答案即可。\n實作上，我們將1當作成立，0當作不成立，\n那麼整個DFS的過程就是在找三個結果相加等於2。\nJava Python部分基本一致，只是三元運算是由if else來寫的。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(N)，因為要考慮到最糟的情況，同時遞迴會產生call stack )\n「能否給出迭代解？」\n(原題的Solution處有給出來，請參照看看XD，簡單來說，\n就是分別使用stack記錄p跟q的祖先節點，最後回頭找最底層的那個祖先。)\n(但因為使用stack的關係，空間複雜度依舊會是O(N) )\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-23T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-55-dfs-3/","title":"從LeetCode學演算法 - 55 DFS (3)"},{"content":"0114. Flatten Binary Tree to Linked List (Medium)\nQuestion Given a binary tree, flatten it to a linked list in-place.\nFor example, given the following tree:\n1 2 3 4 5 1 / \\ 2 5 / \\ \\ 3 4 6 The flattened tree should look like:\n1 2 3 4 5 6 7 8 9 10 11 1 \\ 2 \\ 3 \\ 4 \\ 5 \\ 6 分析/解題 給定一個二元樹，請將其攤平成linkedlist形式且以in-place的條件進行。\n依照題目要求攤平後，整棵樹應該會變成每一個節點只會有右邊的節點。\n仔細觀察題目我們會發現其走訪的順序其實是pre-order。(中左右)\n那麼，該怎麼做到攤平呢？\n我們可以先考慮某個子樹的情況，\n根節點自己在攤平後應該還是不會動，\n而所有左子樹的節點在攤平後應該都排在右子樹節點的前面 。\n所以當我們假定先完成了一個樹的左右子樹的攤平的話，\n樹應該長得像這樣：\n1 2 3 4 5 6 7 a / \\ b e \\ \\ c f \\ \\ d g 那麼，我們要做的應該是將d跟e接起來(a-e斷開) ，\n並且將b的位置從a的左邊挪到右邊 。\n所以整個流程會像這樣：\n檢查根節點 ，是NIL則回傳(代表這條路走到底了)。 先記錄左右節點備用(l, r)，\n並分別呼叫自己的左右節點進入flatten遞迴 。 經過2以後左右子樹應該分別攤平了，\n現在將左節點設為null，右節點設為l 。 使用迴圈找到root.right的最右邊的節點 (也就是原先左子樹的最後一個節點)，\n將其和r接起來。(也就是在做上圖的d跟e 的銜接) Java Python 讀者可能會注意到上面也提供了迭代解，\n這個版本的解法源自於Morris Traversal ，\n有興趣的讀者可以了解一下。\n簡單來說呢，它做的事情跟遞迴是一致的，\n不過它不需要使用到call stack，\n只需要用到輔助的TreeNode 來記錄先前的root.right。\n每次我們會檢查左節點是否為NIL ，\n是的話我們可以直接往右邊走 (因為左邊不用處理了)；\n接著做的事情相同，先用tmp暫時存下右子樹 ，\n對左子樹進行接到右邊的動作。 (也就是每一次會處理掉每個左子樹的右邊的分枝 )\n這整個流程並不是很好理解，\n讀者只需留意到其時間複雜度一樣是O(N) 即可，\n在實際面對類似題目時，如果沒有把握，可以以前面的遞迴解為主。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，但遞迴解的空間複雜度要另行考慮call stack，\n若平衡的話是O(logN))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-22T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-54-dfs-2/","title":"從LeetCode學演算法 - 54 DFS (2)"},{"content":"0278. First Bad Version (Easy)\nQuestion You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.\nSuppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.\nYou are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.\nExample:\n1 Given n = 5, and version = 4 is the first bad version. 1 2 3 call isBadVersion(3) -\u0026gt; false call isBadVersion(5) -\u0026gt; true call isBadVersion(4) -\u0026gt; true 1 Then 4 is the first bad version. 分析/解題 一個正在由你主導的團隊所開發的產品在最新的版本沒過品質檢驗。\n由於每個版本都是由前面的版本進版，所以當某個版本壞掉了，\n其後的版本也都會是壞的。\n假定有n個版本，你要找出第一個開始壞掉的版本。\n這題其實蠻真實的，\n除了一般來說不會有什麼API，\n可以看這個版本是不是壞掉這種東西(都嘛要自己測XD)\n而實際碰到這種狀況的時候，\n通常做的也是先想辦法倒回到某個版本時間點。\n這時候Project Owner就會叫大家先不要commit了，\n開始從上一個好的版本到這個版本中列出所有commits，\n再來切一半 的位置來檢查中間的版本 有沒有問題，\n沒有問題 的話就代表這個中間點到尾端 這區間才有問題；\n有問題 的話就代表是開頭到中間點 這個區間有問題。\n所以每次我們都可以排查掉一半的可能性並縮小範圍，\n最終就找到那個元凶的commit，視情況決定要做revert或其他動作。\n所以我們可以發現，這種連續性的東西，\n也可以用Binary Search的方式來解，只是要處理的條件就不同了。\n我們將較小的版本叫lo，較大的版本叫hi，\n一開始lo=1, hi=n，取中間的版本mid，\n當mid剛好是bad version時，並不代表可以回傳mid ，\n應該將hi設定為mid (也就是可能的範圍是1~mid )。\n否則的話，代表1~mid都是清白的 ，\n我們可以將lo設定為mid+1 ，縮小範圍繼續搜尋。\n最終，當lo和hi交會的時候，\n代表我們找到出問題的那個版本，所以最後要回傳lo 。\nJava的部分考慮到int要盡量避免溢位，\n一樣使用lo + (hi - lo) / 2的形式來計算。\nJava Python的部分一樣請記得要整數除法。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(logN)/O(1))\n相似及延伸 1.0035. Search Insert Position 2.0034. Find First and Last Position of Element in Sorted Array Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-53-binary-search-2/","title":"從LeetCode學演算法 - 53 Binary Search (2)"},{"content":"0268. Missing Number (Easy)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.\nExample 1 1 2 Input: [3,0,1] Output: 2 Example 2 1 2 Input: [9,6,4,2,3,5,7,0,1] Output: 8 Note :\nYour algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?\n分析/解題 給定一個陣列內含n個不同的數字，\n(從0~n之間選n個，也就是說會少一個)\n試找出漏掉的那個數。\n首先最笨最暴力的方法當然是排序過後再從0開始看nums[i]是否為i。\n這個做法顯然經過排序就需要O(NlogN)的時間，\n但其實還是可以通過測資XD\n我們考慮比較簡單一點的作法：\n我們都知道梯形公式(以及那個聰明的高斯XD)，\n從0加到n的總和會是n * (n+1) / 2。\n所以想要知道中間漏掉哪個，就將0~n的總和，\n減去nums的所有元素全部加起來即可。\nJava 在Python中不要忘記了除法取整數要用「//」，\n並且陣列的和可以用sum來取得。\nPython 這種解法要留意一點，如果在有限制int的狀態下，\nn*(n+1)是有機會溢位的！所以如果有時間的話，\n還是可以嘗試一下下面提到的解法。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1)，乘法只做一次，加法會做n次，儲存的部分只有幾個輔助的變數)\n「這題有別的解法嗎？」\n(其實用Bitwise Operation來解也很簡單，\n這邊留給讀者可以自行嘗試看看(用XOR)。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-20T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-52-array-11/","title":"從LeetCode學演算法 - 52 Array (11)"},{"content":"0235. Lowest Common Ancestor of a Binary Search Tree (Easy)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.\nAccording to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself ).”\nGiven binary search tree: root = [6,2,8,0,4,7,9,null,null,3,5]\nExample 1 1 2 3 Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 Output: 6 Explanation: The LCA of nodes 2 and 8 is 6. Example 2 1 2 3 Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 Output: 2 Explanation: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition. Note:\nAll of the nodes’ values will be unique. p and q are different and both values will exist in the BST. 分析/解題 給定一個二元搜尋樹及其中兩個不同的節點，\n試找出它們的最近共同祖先(LCA)。\n題目有標註說一個節點可以視作自己的後裔(descendant)，\n這點會有影響，還請留意。\n那麼，我們如何尋找這個最近共同祖先呢？\n首先要知道，這是一棵二元搜尋樹，假設這個LCA的節點叫作L好了，\n兩個節點分別叫p跟q，那麼我們可以考慮以下幾個狀況：\n如果L是p或q其中之一 的話，先遇到誰，就代表誰是那個LCA 。\n(因為先遇到的節點會是後面的那個節點的祖先) 如果L不是p或q其中之一 的話，L的値的範圍必在p.val和q.val之間 ，\n也就是說兩者會位在L的不同側的子樹。\n(即p.val \u0026lt; L.val \u0026lt; q.val或p.val \u0026gt; L.val \u0026gt; q.val) 如果從root開始判斷的話，就可以分成幾種情況：\nroot的値和p或q的值相等 =\u0026gt; ** 直接回傳root** (p或q就是L) root的値在p和q的值的範圍之內 =\u0026gt; ** 直接回傳root**\n(即p.val \u0026lt; L.val \u0026lt; q.val 或p.val \u0026gt; L.val \u0026gt; q.val ) p和q的値都小於 root的值 =\u0026gt; 往下找root.left 的狀況遞迴 p和q的値都大於 root的值 =\u0026gt; 往下找root.right 的狀況遞迴 也就是說，最終總會找到L是p或q之一 ，或者L能將兩個節點拆成兩邊 。\n於是我們可以輕鬆解出這個題目，在Python的部分，\n除了要留意a \u0026lt; b \u0026lt; c這種形式是Python才能用的，Java不接受以外，\n這邊在Java的解答中要提供一個較簡潔的解法。\n仔細思考的話，我們可以發現1, 2其實可以看作一件事情：\nroot.val - p.val和root.val - q.val的關係。\n當符合1. 的時候，上面的兩個式子會有一個等於0 ；\n當符合2. 的時候，上面的兩個式子會一正一負 。\n所以兩者相乘 時，符合1.跟2.的條件的狀況下，\n結果會\u0026lt;=0 (或\u0026lt;1，因為值是int)。\n同時，當不符1.且不符2.時，由於p, q已經確定是同邊 了，\n只需要拿p來比較即可，不用再去比較q。\n根據上面的推導我們可以寫成Java的答案版本。\n同時，由於每次遞迴都只有動到root所指向的節點，\n所以我們也可以很簡單地將其改動成迭代的解法，\n由於不需call stack，總體速度有可能會有些許的加快。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(Worst case: O(N)/O(N) (如果節點都在同一邊)\n平衡樹的話最大會走到整個深度的節點，是O(logN))\n(用迭代解的話，因為不用call stack，空間複雜度為O(1))\n「用相乘的方法會有什麼副作用？」\n(在有限定變數是int的狀況下，相乘有機會導致溢位 ，所以如果這題的測試資料刁鑽一點的話，請不要用相乘的，一組一組判斷就好。)\n相似及延伸 1.0236. Lowest Common Ancestor of a Binary Tree (如果這棵樹只是二元樹 而非二元搜尋樹呢？)\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-17T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-51-bst-4/","title":"從LeetCode學演算法 - 51 BST (4)"},{"content":"0226. Invert Binary Tree (Easy)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Invert a binary tree.\nExample:\nInput:\n1 2 3 4 5 4 / \\ 2 7 / \\ / \\ 1 3 6 9 Output:\n1 2 3 4 5 4 / \\ 7 2 / \\ / \\ 9 6 3 1 Trivia:\nThis problem was inspired by this original tweet by Max Howell:\nGoogle: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so f*** off.\n分析/解題 題目要求反轉一個二元樹。\n我們今天來看一題經典的題目，\n這題經典的原因也許不是在於它有多困難，\n而是在於這問題背後的故事XD\n或許另一方面也可以看看他本人在Quora上的回應。\n所以演算法很重要有沒有XDD\n(據稱有一種說法是說當時的題目是要求min-max的反轉，這邊暫不討論，\n我們以左右反轉為準)\n相信大家經過前面的一堆二元樹相關題目以後，\n應該已經對二元樹駕輕就熟了，應該可以輕鬆地寫出遞迴方式的版本。\n跟之前的Symmetric Tree相似，\n只是這次我們直接將一棵樹的左右節點交換，\n除了交換以外，它們的左右子樹的部分也要再度進行交換。\n所以我們會拆成：\n檢查root是不是null (是的話代表這條路到底了，直接回傳null) 將root.left和root.right進行交換 將root.left和root.right分別做為參數，呼叫函式進行遞迴 Java Python寫得再簡單一點，不過意思是一樣的XD\nPython 你以為這樣就結束了嗎？\n我們將繼續來探討一下如果是迭代解的話該怎麼處理。\n如果思考一下前面的遞迴解，\n會發現一件事情：\n對於一個我們造訪的節點而言，\n我們所影響到的只有其左節點和右節點，\n當下這個節點的値並不會受任何影響。\n所以我們只需要保證當走到這個節點的時候，\n關於這個節點以上的操作已經做完 即可，\n那麼要保證這點的話，只要使用level order 的方式，\n我們按順序操作即可做完所有反轉的動作。\n由於是先將同一層的做完才會進到下一層，\n也可以視作是BFS的方式。\n按順序作的話，\n可以使用Queue來處理這樣子的問題，步驟大致上是：\n0. 檢查root是否為NIL，是的話直接回傳NIL\n建立一個queue(python請用deque ) 將root放入queue中 每次從queue中取出一個節點，將其左右位置互換 ，\n並分別將左右節點中非NIL的節點放入queue中 重複3直到queue中沒有節點 回傳root Java:\nPython:\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(因每個節點均要和另一個位置進行對調，所以時間複雜度為O(N)。\n空間複雜度會受到樹的平衡程度影響。\n平衡狀態 的話空間複雜度對遞迴解來說是O(logN)(call stack) ，\n而對迭代解來說是O(N) (因為最大是最底部那層)\n(這時候反而越不平衡每層的節點會越不容易太多))\n「這兩種解哪種是DFS？哪種是BFS？」\n(遞迴解是DFS(一路走到最深才回頭)，迭代解是BFS(當層走完才往下層走))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-15T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-50-tree-9/","title":"從LeetCode學演算法 - 50 Tree (9)"},{"content":"0217. Contains Duplicate (Easy)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given an array of integers, find if the array contains any duplicates.\nYour function should return true if any value appears at least twice in the array, and it should return false if every element is distinct.\nExample 1 1 2 Input: [1,2,3,1] Output: true Example 2 1 2 Input: [1,2,3,4] Output: false Example 3 1 2 Input: [1,1,1,3,3,4,3,2,4,2] Output: true 分析/解題 給定一個整數陣列，若陣列有任何重複的數，則回傳true，否則回傳false。\n今天來點簡單的，畢竟中秋節嘛XD\n和之前找出單一元素的題目不同，因為這題沒有限定重複出現的次數 ，\n所以並不適用於bitwise operation 的方法。\n以暴力法來說要O(N²)，排序後再比要O(NlogN) ，\n均不理想，所以一般常見的想法是，\n一樣引入hashmap或dictionary 來解題。\n而由於我們只在意數字有沒有出現 ，對於Java來說，\n還有另外一個名為HashSet 的方式可以使用。\nHashSet在新增 方面複雜度同於HashMap均為O(1) ，\n但HashSet同時具備Set的特性，同個資料只能出現在Set當中一次 ，\n若有相同資料要被新增時，則新增會失敗(回傳false) ；\n我們可以利用這點，每次對HashSet新增當前的數字，\n失敗則代表已經出現重複了(直接回傳true)，\n若全數新增完畢則代表不存在重複(回傳false)。\nJava Python的set新增時碰到重複的資料時不會進行任何動作 ，\n所以這邊還是使用dictionary。\n另一種作法是可以使用set來進行化簡後，直接檢查總長度是否改變 ，\n即可知道是不是含有重複的元素。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(N)，因為每次插入均為O(1))\n「如果限制不用HashSet/Dictionary，但給你nums值的範圍呢？」\n(建立一個array/list，總長為整個範圍，\n將其拿來做為輔助陣列使用即可。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-13T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-49-hash-table-3/","title":"從LeetCode學演算法 - 49 Hash Table (3)"},{"content":"0819. Most Common Word (Easy)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Given a paragraph and a list of banned words, return the most frequent word that is not in the list of banned words. It is guaranteed there is at least one word that isn’t banned, and that the answer is unique.\nWords in the list of banned words are given in lowercase, and free of punctuation. Words in the paragraph are not case sensitive. The answer is in lowercase.\nExample:\n1 2 3 4 5 6 7 8 9 10 Input: paragraph = \u0026#34;Bob hit a ball, the hit BALL flew far after it was hit.\u0026#34; banned = [\u0026#34;hit\u0026#34;] Output: \u0026#34;ball\u0026#34; Explanation: \u0026#34;hit\u0026#34; occurs 3 times, but it is a banned word. \u0026#34;ball\u0026#34; occurs twice (and no other word does), so it is the most frequent non-banned word in the paragraph. Note that words in the paragraph are not case sensitive, that punctuation is ignored (even if adjacent to words, such as \u0026#34;ball,\u0026#34;), and that \u0026#34;hit\u0026#34; isn\u0026#39;t the answer even though it occurs more because it is banned. Note:\n1 \u0026lt;= paragraph.length \u0026lt;= 1000. 0 \u0026lt;= banned.length \u0026lt;= 100. 1 \u0026lt;= banned[i].length \u0026lt;= 10. The answer is unique and written in lowercase (even if its occurrences in paragraph may have uppercase symbols, and even if it is a proper noun.) paragraph only consists of letters, spaces, or the punctuation symbols !?',;. There are no hyphens or hyphenated words. Words only consist of letters, never apostrophes or other punctuation symbols. 分析/解題 給定一個段落和一個被禁止的字的列表，回傳這個段落裡面出現次數最高且沒有在禁止字列表內的字。\n(題目保證至少有一個字不會被禁止且答案只會有一個)\n禁止字表會以小寫字給定且不需考慮標點符號，\n在段落中的字並不限定大小寫(也就是視作相同的字)，\n答案要用小寫表示。\n這題一般而言會使用HashMap或dict來解題，\n但隨著總字數的增加，一些重複的字母不斷出現感覺其實相對浪費，\n所以今天就要專門來介紹一個資料結構來解決這個問題，\n這個資料結構就是字典樹(Trie)。\nTrie (From Wikipedia)\n字典樹長得基本上就是樹的一種，通常儲存的是字串。\n其根節點代表著空字串 ，而每個連結出去的節點，\n都代表在前面的基礎上加上一個字元(char) 。\n換句話說，我們只要知道從根到葉走了哪些鏈結，\n就知道最終葉所代表的字串是什麼，如上圖所示。\n在這題當中，我們可以自行定義一個class TrieNode，\n當中包含了links (從這個節點連出去26個字母)，\ncnt (這個字在整個段落出現的次數)，以及word (實際上這個字是什麼)。\n其實word可以如上面所說一步一步加起來，\n不過寫起來稍微麻煩一點點，這邊就讓我偷懶一下吧XD\n在Java的部分，設定條件是：\n當被要求大多數的字串處理函式都禁止使用時，\n該怎麼一步一步寫出我們所要的東西。\n首先要建TrieNode，除了上面所述外，我們需要三個函式：\n1. insert\n透過每個字母沿links的路徑走，\n如果curr.links[index] == null 則表示前面還沒走過，\n要自行new出來，並設定其word變數。\n在走到底的時候我們要將cnt數加1 。\n(代表這個word出現在段落裡次數加1次)\n行走的路徑如之前提過的，直接使用字元來減去’a’ 即可，\n這邊將links[0]視為是’a’，而links[25]視為是’z’ 。\n當走到某一條links[index]還沒初始化時，\n就將其初始化並給定其word值。\n每次往下走時不要忘記將用來迭代到下一個字元的curr指到下一個位置 。\n2. ban\n只要將該string對應的TrieNode中的cnt設成零 即可。\n如果在走的路徑途中遇到null，表示段落裡不存在這個string，\n直接return即可。\n3. findMax\n遍歷所有TrieNode並找到最大的cnt及對應的word。\n(這邊使用到res作為結果 的字串及maxcnt作為儲存當前最大值的變數 )\n只需要從root的位置開始，往下搜尋有cnt的值，\n一一比較即可，當這層搜尋完時，\n我們還要往下一層去，所以用迴圈往下再進行遞迴。\n(這部分是DFS )\n回到mostCommonWord 函式中，\n我們先產生一個StringBuilder(命名為st) 及一個root(TrieNode) ，\n並用isString 來表示現在st是否構成一個word。\n每次將paragraph中的字元取出來，檢查其是否是大小寫字母，\n並將字母統一成小寫後接到st上；\n一旦發現遇到非大小寫字母的字元，且設定的isString為真 ，\n則表示現在st構成一個word，將其丟進root中插入到字典樹內。\n(不要忘記最後面還要再檢查一次 ，\n因為有可能還沒插入就離開迴圈了)\n接著再ban 及findMax 後，就可以回傳res 作為答案了!\nJava Python的部分思路跟Java相近，\n不過因直譯器的特性，這邊選擇將對應的函式拉到class Solution來做。\n讀者可以兩邊互相對照看看差異。\n此外，由於banned測資似乎存在會重複的狀況，\n所以可以使用set來縮小總長。\n另這邊也提供leetcode上lee215的解：\n使用re.findall ，用正規表示式直接將words找出，\n再利用Counter直接計算頻率，最終取出最高頻率的字。\n(應該是目前最快的解法)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n可以從不同面向來考慮。由於有點長，且不好解釋，\n這邊直接貼筆者在leetcode上回答的內容。\n「這個解法有沒有再更優化的方法？」\n(至少有兩個，如果讀者有興趣的話可以嘗試看看：\n將word的部分去除(也就是只使用中間的鏈結來取得整個字) 其實可以先做ban再作insert (ban可將cnt設為**-1** ，而insert時先檢查cnt是否為-1，是的話可以直接跳過)\n(這個方法可以同步在insert時更新res和maxcnt，所以會變成先ban再insert完以後，就可以直接回傳答案了，速度應該會再快一點點。)) 「Java如果允許使用split呢？」\n(可以這樣用：\nString[] words = paragraph.toLowerCase().split(“[ !?’,;.]+”); 當然，前提是你不要中間的標點符號漏打XD)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-11T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-48-trie-1/","title":"從LeetCode學演算法 - 48 Trie (1)"},{"content":"0204. Count Primes (Easy)\n(當然，Medium的拍手也可以多拍幾下啦XD)\nQuestion Count the number of prime numbers less than a non-negative number, *n *.\nExample:\n1 2 3 Input: 10 Output: 4 Explanation: There are 4 prime numbers less than 10, they are 2, 3, 5, 7. 分析/解題 給定一個非負整數n，試求所有小於這個n的質數。\n讓我們來複習一下國中(還是國小？)數學：\n質數的定義就是除了1和自己 以外，沒有其他數可以整除它的正整數。\n透過這個特點我們可以再延伸：\n因為合成數必然可以拆成質數相乘 ，\n所以我們要判定某個數是否是質數的話，\n只要將其他比它小的質數 測試它是否是目標的因數 即可。\n另外，由於一個數若能拆成2數相乘，\n那麼其中一個因數會小於等於這個數的開根號 ；\n另一個因數則是大於等於這個數的開根號 。\n如此一來，我們只要檢驗2**~目標數的開根號** 的數是否能整除目標數 即可。\n所以老師會教你一個消去法：\n首先將2的倍數排除掉，再將3的倍數排除掉，\n再將5的倍數排除掉……(2倍以上，不含自己)\n一個個操作，走到沒有被排除掉的數即為質數 。\n我們可以再進一步處理一點：\n假設現在處理到i，\n那麼其實我們應該知道i*2, i*3, …, i*(i-1 )的部分，\n應該都被前面的操作排除 了，\n故每次我們只要從i*i開始，排除到n，\n也就是i走到最大n的開根號即可。\n故整個程式會從2到根號n，每次將對應i的i倍以上的部分設為非質數，\n最後計算總質數有多少個。\nJava的部分，由於boolean預設為false，\n這邊使用nPrime代表not prime，所以nPrime為false代表這個數是質數，\n要設定成不是質數時請用nPrime[j] = true。\n在處理完後請記得bound後面的質數個數要記得加起來。\nJava Python的部分，sqrt可以直接用n ** 0.5，\n並且我們可以用1代表質數，0代表非質數，\n讀者可以仔細看一下第8行，其實和Java迴圈的目的是一樣的，\n不過這邊直接最後才算prime陣列的總和來取得質數個數。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n), O(n log log n))\n(外層迴圈的boundary上限是sqrt(n)，\n內層j的次數上限會從n/2 -\u0026gt; sqrt(n)，具體計算我也不會XD\n以Wikipedia提供的時間複雜度為O(n log log n)。\nhttps://zh.wikipedia.org/wiki/%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89%B9%E5%B0%BC%E7%AD%9B%E6%B3%95)\nSpecial Thanks suggestions/corrections from viewers:\nPython Taiwan, 林宣丞：此篩選方式又稱 埃拉托斯特尼篩法(sieve of Eratosthenes)。\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n1 2 如果你／妳非常喜歡這篇文章，可以按著拍手直到50下。 也請記得「Follow」我，隨時收看最新的文章。 ","date":"2019-09-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-47-array-10/","title":"從LeetCode學演算法 - 47 Array (10)"},{"content":"0199. Binary Tree Right Side View (Medium)\n另外筆者昨天生日，快補祝我生日快樂XDDDDD\nQuestion Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.\nExample:\n1 2 3 Input: [1,2,3,null,5,null,4] Output: [1, 3, 4] Explanation: 1 2 3 4 5 1 \u0026lt;--- / \\ 2 3 \u0026lt;--- \\ \\ 5 4 \u0026lt;--- 分析/解題 給定一棵二元樹，想像你站在樹的右邊往左看，\n試回傳從上到下依序所看到的值。\n這題一看就知道某種程度上屬於level-order traversal，\n(還不清楚或不知道什麼是level-order的讀者請參閱這篇)\n只是要求的部分有點不一樣而已，這邊只要求最右邊的數字。\n那麼要注意囉！可能會有人想，我能不能只走最右邊 取值就好呢？\n答案是當然不行！！！因為你可能會遇到類似這樣的狀況：\n你看到的最右邊不是人家的最右邊XD\n如果只取最右邊的話，顯然我們會走1-3-0然後就結束了，\n但還有一個4落在中間，所以這題無論如何還是要乖乖遍歷所有節點才行。\n我們可以用BFS的方式來解這題(DFS也行，但要用到遞迴，這裡暫不討論)，步驟如下：\n先新增一個queue用來存放當層(level)的所有節點，\n另外開一個串列res(result)用來存放結果。 記錄當下queue的總數cnt(count)。 執行一個cnt次數的迴圈，依序將當層的節點取出 每取出一個節點，就分別檢查其左右節點是否存在，\n存在則以先左後右 的順序放入queue中。 迴圈執行完後，queue中應該全是下一層的節點；\n同時最後一個取出的節點 ，就是每層最右邊的節點，\n將其值取出放入res中。 重複2~5的動作，直到queue中沒有節點為止。 讀者會發現這樣的做法唯一的差別就是要記錄最後一個取出的節點 ，\n其他和level-order traversal一樣，利用queue先進先出的原則，\n每次恰好處理一層的節點。\n依此我們可以寫成程式碼，\nJava的部分List和Queue都可以使用LinkedList，\n且TreeNode的部分由於Java必須給定值，故一開始last先行給定為null。\nJava Python的部分不要忘記當需要從左邊取值時deque 的速度會較List快，\n另外last其實可以不用先給值也可以順利通過。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(N)，每個節點都會遍歷過，\n同時因為使用Queue的時候中間會儲存整個level，\n空間複雜度還是跟總數相關。)\n「可以使用DFS嗎？」\n(可以，但需要對每項記錄其level，解法相對較難處理，讀者可嘗試看看)\n「如果題目改成從左邊看呢？」\n(一樣要遍歷所有節點，但改成在每一層的第一項就將值置入到答案中)\n相似及延伸 1.0102. Binary Tree Level Order Traversal Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-07T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-46-bfs-2-queue-3/","title":"從LeetCode學演算法 -  46 BFS (2) / Queue (3)"},{"content":"0200 Number of Islands (Medium)\nQuestion Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.\nExample 1 1 2 3 4 5 Input: 11110 11010 11000 00000 1 Output: 1 Example 2 1 2 3 4 5 Input: 11000 11000 00100 00011 1 Output: 3 分析/解題 給定一個二維的地圖當中陸地用'1\u0026rsquo;表示，水則用'0\u0026rsquo;表示 ，\n試計數這整張圖有多少島嶼(island)。可假定地圖的外圍均為水域。\n(島嶼的定義就是其周圍都圍繞著水，\n且可以通過連接相鄰的垂直/水平陸地所構成。)\n如對於題目描述依舊沒搞懂的話，就把它當成小畫家填色的色塊吧！\n視為相同區域的用油漆桶可以全部填滿XD\n而題目所問的，就相當於要填幾次才能將所有陸地區域填滿 。\n對於要確認島嶼這點，只有一種方法：\n每次從一個點開始向外延伸相鄰的格子，\n直到周圍沒有可以延伸的區域為止。\n這時候這整塊區域就是我們所謂的島嶼，於是計數可以加1 。\n那麼問題來了，在延伸的過程中一共有四個方向 可以選擇，\n如果不加限制的話，無疑會有重複的部分；\n所以除了檢查是否遇到水(‘0’，也就是可以不用繼續往下搜尋)外 ，\n我們還需要知道這個格子是否已經走過了。\n所以我們會再新增一個visited陣列用來標明已經走過的區域 。\n(這樣子只要已經走過的就直接跳過即可。)\n由於每次會需要走到底才會回頭，\n所以這種方式是很典型的DFS(Depth-First Search，深度優先搜尋) 方法。\n所以流程會變成：\n初始化一個visited 二維陣列，預設當中每個值均為false 對grid中的每個點(i, j)檢查其是否為陸地(‘1’) ，且未曾走訪過的話:\n2-a. 遞增島嶼計數值，並從每個點(i, j)呼叫函式dfs 來開始走訪 在dfs中，先檢查(i, j)點是否符合規範(因會+1或-1，須不超出範圍 )，\n且尚未走訪過(visited[i][j] == false) 的狀況，進行3-a的流程\n3-a. 將visited[i][j]設定為true\n3-b. 往(i, j)的上下左右 走，並傳入下一階段的dfs。 這麼一來，當整張圖掃過去以後，\n我們就能知道到底有幾個島嶼了！\nJava和Python的寫法基本一致，這邊不再贅述，\n讀者只要注意到應該被檢查的邊界條件 即可。\nJava Python 在這個範例中我們使用了一個額外的陣列來儲存，\n有沒有辦法能夠不用額外的陣列呢？\n其實是有的，辦法就是將每次走過的陸地(‘1’)，\n都直接設定成水(‘0’)，自然就相當於都走過了，\n從而可以替代掉用visited來處理。\n優點是速度會較為快速，\n但很嚴重的缺點是這麼做完以後，\ngrid本身就會變成全部都是’0\u0026rsquo;的陣列了 。\n除非已經確定這個grid可以被任意操作，\n否則筆者認為要這麼做的話記得要先問清楚要求才下手才行XD~\n此外，這題在返回時仍舊要保留走過哪些格子的資訊 ，\n所以和之前的Backtracking的題目作法是不一樣的。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(若m, n為長寬，O(m*n) for best case，理論上全部走訪一遍即可, O(m*n))\n(如果可以清空grid則記錄用的空間複雜度是O(1))\n(若考慮call stack的部份的話，總空間複雜度worst case是O(N) )\n相似及延伸 1.0130. Surrounded Regions 2.0695. Max Area of Island Special Thanks suggestions/corrections from viewers:\nRaiy Kuo: DFS時recusive占用的stack應一併考慮進去。\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-45-dfs-1/","title":"從LeetCode學演算法 - 45 DFS (1)"},{"content":"0160. Intersection of Two Linked Lists (Easy)\nQuestion Write a program to find the node at which the intersection of two singly linked lists begins.\nFor example, the following two linked lists:\nbegin to intersect at node c1.\nExample 1 1 2 3 Input: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 Output: Reference of the node with value = 8 Input Explanation: The intersected node\u0026#39;s value is 8 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [4,1,8,4,5]. From the head of B, it reads as [5,0,1,8,4,5]. There are 2 nodes before the intersected node in A; There are 3 nodes before the intersected node in B. Example 2 1 2 3 Input: intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 Output: Reference of the node with value = 2 Input Explanation: The intersected node\u0026#39;s value is 2 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [0,9,1,2,4]. From the head of B, it reads as [3,2,4]. There are 3 nodes before the intersected node in A; There are 1 node before the intersected node in B. Example 3 1 2 3 4 Input: intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 Output: null Input Explanation: From the head of A, it reads as [2,6,4]. From the head of B, it reads as [1,5]. Since the two lists do not intersect, intersectVal must be 0, while skipA and skipB can be arbitrary values. Explanation: The two lists do not intersect, so return null. Notes:\nIf the two linked lists have no intersection at all, return null. The linked lists must retain their original structure after the function returns. You may assume there are no cycles anywhere in the entire linked structure. Your code should preferably run in O(n) time and use only O(1) memory. 分析/解題 有兩個單向連結串列，試找出其交會開始的節點。\n如果它們彼此之間沒有相交，則回傳null。\n(注意中提到最好時間使用O(n)且空間僅使用O(1)。)\n這題其實相當簡單，但要特別留意一點：\n就算兩個節點的值相等，也並不代表它們是同一個節點。\n從Example 1中就可以看到這個例子，\n節點值都是1，但並非同節點，這部分要特別留意。\n不過我們並未特別針對ListNode去實作相等的function的狀況下，\n直接用**==** 判斷即可。\n那麼，怎麼來找共同的交會節點呢？\n我們可以先假設它們有一個交會點，\n那麼list A跟list B在這個交會點(含)以後的節點數會相等。\n(因為重合了XD)\n所以比如說A總長度是9，B總長度是6，\n我們可以先讓A從開頭走3步 ，(這樣才能對齊 )\n接著兩邊開始依序走訪比對走到的節點是否交會，\n若交會則回傳；若走到底還沒有看到相同的節點，\n則回傳null(或None)。\n所以大體上的操作如下：\n設定iteA/iteB作為走訪list A/list B用的節點 先各自走訪過一輪來取得A和B分別的長度 長度相減，讓比較長的list的起始節點先多走相差的節點數 同時開始第二次的走訪，一邊比對節點是否交會，\n是則回傳該節點，不是則走到至少一邊走完為止 若4走完尚未回傳則回傳null(表示沒有交會) 寫成程式碼如下。\nJava Python的部分可以寫得稍微簡潔一點，\n留意用來遞進用的迴圈這裡的for會使用單底線，\n因為我們只想要使用重複diff或-diff次的功能，\n並不在意迴圈執行到第幾次。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1)，我們共遍歷了最多兩次的list，\n且只有額外使用到幾個輔助用的節點和變數。)\n相似及延伸 1.0599. Minimum Index Sum of Two Lists Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-09-03T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-44-linked-list-5/","title":"從LeetCode學演算法 - 44 Linked List (5)"},{"content":"1161. Maximum Level Sum of a Binary Tree (Medium)\nQuestion Given the root of a binary tree, the level of its root is 1, the level of its children is 2, and so on.\nReturn the smallest level X such that the sum of all the values of nodes at level X is ** maximal**.\nExample 1 1 2 3 4 5 6 7 Input: [1,7,0,7,-8,null,null] Output: 2 Explanation: Level 1 sum = 1. Level 2 sum = 7 + 0 = 7. Level 3 sum = 7 + -8 = -1. So we return the level with the maximum sum which is level 2. Note:\nThe number of nodes in the given tree is between 1 and 10^4. -10^5 \u0026lt;= node.val \u0026lt;= 10^5 分析/解題 給定一個二元樹的根節點，若將該層(level)稱為1，\n其子節點所在層稱為2，……以此類推，\n嘗試找出最小的x層，這層的所有節點和是在所有層裡面最大的 。\n這題其實存在不同的解法，若讀者有興趣的話也可以使用DFS的解法，\n本篇只介紹BFS的作法。\n如果有看過先前對於Tree的介紹的話，\n我們應該有提到過不同方式的走訪，而這題問的，\n如果限定在迭代法解的話，就適合使用層序走訪(level-order traversal) 。\n層序走訪的概念很簡單：\n每次先走完這一層的所有節點，再走下一層的所有節點 。\n用遞迴來看的話顯然是沒辦法的，\n因為每次往下都是走往下一層 (左子樹或右子樹)，\n所以我們需要用非遞迴的方式，並使用Queue來作輔助。\n大概步驟會像這樣子：(下面將Queue命名為q)\n將根節點放入q中\n當q中有節點時，先求q現在的節點數量cnt\n(註：這個節點數量就是目前這整層的所有節點數 )\n開始一個迴圈，這個迴圈執行cnt次 :\n3-a. 每次從q中取出一個節點n ，並將其值加到當前總和total 中\n3-b. 檢查左右節點，如果不是NIL則放進q中\n(註：第3步做完以後，\nq中前一層的cnt個節點應該已經全數移除，並加入下一層的所有節點)\n檢查total是否大於當前的最大總和 ，\n若是，則替換掉最大總和 及所求答案的層數\n遞增當前的層數(level)\n重複2~5的動作，直到q中沒有任何節點為止\n由上面的步驟可知，每一次我們均藉由Queue來走遍所有同一層 的節點。\n在非樹的題目中，類似的作法是先走所有離自己一步距離的可能，\n再往下一層去處理，由於是先求廣度 ，\n這樣子的作法我們稱之為廣度優先搜尋(BFS, Breadth-First Search) 。\nJava的部分，我們可以使用不同的Queue的實作方式，\n讀者可以選用ArrayList, LinkedList或ArrayDeque。\n(一般來說ArrayList效率會較差，\n有人說ArrayDeque號稱比LinkedList好，\n但筆者實測看起來沒有明顯差異XD)\nJava的Queue放入和取出的寫法是offer/poll ，總數使用size ，\n檢查是否為空則用isEmpty 。\nJava Python的部分則使用前面提過的deque 來處理，\n放入和取出分別是append 跟popleft ，總數使用len ，\n是否為空則直接拿其本體來判斷 (裡面是空的則會是False )\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(N)，因為會遍歷整棵樹，而空間占用最大的時候會占用最下面的一整層，所以最糟的狀況也會是O(N)。)\n「題目有告訴我們node總數最大是10^4，如果這棵二元樹是處在平衡的狀態的話，有沒有比較方便的解法？」\n(平衡二元樹代表中間該填滿的都填滿了，\n所以可以利用這點去算最大的層數，\n新增一個陣列/串列來記錄某一層的總和；\n直接利用層數來進行DFS，將走到的點的值加到對應的位置，\n最後加總完以後再來看哪一個level總和最大。)\n「可以用DFS來解這題看看嗎？」\n(可以，只是traversal的時候記得要傳遞層數的值，\n並且開一個ArrayList/List來存放每層的總和。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-31T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-43-bfs-1-queue-2/","title":"從LeetCode學演算法 - 43 BFS (1) / Queue (2)"},{"content":"0257. Binary Tree Paths (Easy)\nQuestion Given a binary tree, return all root-to-leaf paths.\nNote: A leaf is a node with no children.\nExample:\n1 Input: 1 2 3 4 5 1 / \\ 2 3 \\ 5 1 Output: [\u0026#34;1-\u0026gt;2-\u0026gt;5\u0026#34;, \u0026#34;1-\u0026gt;3\u0026#34;] 1 Explanation: All root-to-leaf paths are: 1-\u0026gt;2-\u0026gt;5, 1-\u0026gt;3 分析/解題 給定一個二元樹，回傳其所有根到葉的路徑。\n這題是Easy難度的題目，剛好藉由它來講一下回溯法(Backtracking) 。\n這個題目看起來挺簡單的，如果沒有特別要求的話，寫起來也不難，\n依照遞回的模式就可以順利解決，\n思路大致上是每走一步就將root的值串上path字串 ，\n直到左右均無節點，表示已走到葉節點了，即可將其放到結果res中。\n所以一般可能會寫成這樣：\n可以通過但不盡理想的遞回解\n這麼做其實不盡理想，\n因為我們會發現裡面的每一個tmp其實都是使用一個新的變數 ，\n顯然這件事情會讓我們花費更多的空間(因為產生新的變數)。\n怎麼辦呢？這時候就到了回溯法上場的時候了。\n我們之前有介紹過DFS/BFS ，\n分別代表著深度優先搜尋 和廣度優先搜尋 ，\n如這題前面的解法其實也可以當作DFS來看待，\n而回溯法的概念又更廣泛一些 ：\n在每個階段將所有可能性列出 ，\n經過檢查排除 掉不可能的解後，往下一個階段 進行搜尋；\n如果這個階段的所有分支均不成立 ，\n則回復到上一個階段 的搜尋，並取消 掉這個階段所造成的影響。\n(過程中視要求，可在找到所有答案後才回傳，或者找到第一個答案就回傳)\n簡單來說，就是一個一個試，\n走錯了就回頭，而且記得先前** 試的痕跡要處理掉**就對了XD\n聽起來可能還是有點抽象，我們講這題的實作方式好了。\n要進行回溯法，首先要確立要處理的對象 。\n例如這題裡面最重要的是節點經過的路徑 ，\n那麼我們應該可以將當前的路徑當作主要處理的對象：\n每次在遞迴函式中應該要做的事情有：\n將當前的根節點 加到路徑 的ArrayList中 如果左節點 存在，遞迴進行左子樹 的部分 如果右節點 存在，遞迴進行右子樹 的部分 如果左右節點均不存在 ，表示該路徑是答案要求的其中一條 ，\n將整個路徑內的節點值按照要求的格式輸出到結果res中 走完前4步，這個階段的可能性均搜索完畢 ，\n所以要回到上一個階段，這時在1.的時候加入的根節點應該要被移除 ，\n因為上一個階段並沒有它。 可以看到在回溯法中，路徑的部分是所有函式共用 的，\n所以只要妥善處理用完後復原，即可使用一個List來處理整個樹的狀況，\n這個List最大的占用空間就是這棵樹的深度 。\n依此，我們可以寫出其程式碼。\nJava的部分，這邊用DFS來命名遞迴的函式名，\n也可以叫getPath，可依讀者喜號命名。\n使用StringBuilder來進行字串的整理(加上”-\u0026gt;”)，\n以及使用ArrayList/LinkedList來處理path相關的部分。\n(應該是用哪個都可以啦XD 題目只限定List)\n最後不要忘記每次該階段做完要將最後一個進行移除(remove)。\nJava Python的部份我們可以直接使用List來處理，\n並且利用join 的特性可以很方便地串接所有的path。\n最後一樣不要忘記移除當階段的痕跡(pop )。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(時間複雜度為O(N)(因為要掃過整棵樹)；\n空間複雜度的部分，使用的path在平衡的狀態下複雜度是O(logN)\n而最後的res部分如果用個數來看的話，完美的二元樹深度是O(logN)，\n路徑數是O(N)，所以總占用空間是O(N * logN) )\n相似及延伸 1.0113. Path Sum II Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-29T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-42-backtracking-1-tree-8/","title":"從LeetCode學演算法 - 42 Backtracking (1) / Tree (8)"},{"content":"0242. Valid Anagram (Easy)\nExample 1 1 2 Input: s = \u0026#34;anagram\u0026#34;, t = \u0026#34;nagaram\u0026#34; Output: true Example 2 1 2 Input: s = \u0026#34;rat\u0026#34;, t = \u0026#34;car\u0026#34; Output: false Note:\nYou may assume the string contains only lowercase alphabets.\nFollow up:\nWhat if the inputs contain unicode characters? How would you adapt your solution to such case?\n分析/解題 給定兩個字串s跟t，\n寫出一個函式來判斷t是否是a的一個anagram(易位構詞)。\n所謂的anagram就是指將這個字串的字母搬動順序以後，\n可以組成另一個字串的遊戲，這在很多推理小說裡都有出現過，\n比如達文西密碼或者哈利波特XD\n那麼，怎麼確切知道s跟t是否是彼此的anagram呢？\n我們比較幸運只需要檢查正確與否就好，所以一般常見的解法有幾個：\n排序(暴力?)法\n既然完全是由相同的字母及相同使用字母的個數組成，\n那就代表只要將兩個字串進行排序，最後它們會長得一模一樣 。\n但這樣作的時間複雜度為O(n log n)(n為字串長) 。\n雖然能夠通過測試，但似乎不是很理想。\nHash Table 法\n上次我們已經介紹過了Hash Table的概念，那麼這次我們應該也可以使用相同的方式來處理。由於題目已經告知字串僅含小寫字母，也就是a-z，\n只要依序掃瞄過兩個字串，將字串所含每個字母的個數計算是否相等，\n即可判定結果。\n這麼作只需要O(n) 的時間複雜度，空間部分只需要O(1) 。\n(因為是26個字母 ，所以陣列長是固定的)\n我們可以利用上一次提到的ASCII的方式，\n來對a-z 的部分位移到一個計數陣列的0到25 ，\n同時，掃過s 的時候將對應的字母計數遞增 ，\n掃過t 時將對應的字母計數遞減 ；\n一旦有字母是遞減到小於零 的話就可以直接判定s和t彼此並非anagram。\nJava的版本完整演示了上述的流程。\nJava Python的部分這邊也可以另外使用別的方法，\n這邊提供幾個比較簡便且複雜度一樣的方法：\n使用count 跟all 來計算(所以對每個字母都會分別檢查一次)\n(all是用來判定所有會迭代的狀況是否全數為TRUE)\n使用Counter 計算後再比較(所以會先算完全部再來檢查)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n)/O(1))\n「如果大小寫視為相同？」\n(使用類似Java的方式，但每個字元要先確認是否是大寫，\n若是，先將其轉為小寫才往陣列中存放，之後的做法應該是一致的。)\n(ASCII中A-Z是6590而a-z是97122，可以先平移對應的相差量)\n「如果還有其他英文字母以外的字元？」\n(將陣列改成用HashMap，\nkey存放字元，value存放出現次數。Python則用Dict即可)\n「如果大小寫視為相同，空格及標點符號要省略呢？\n(沒錯，就跟達文西密碼的留法一樣，沒人在管標點的XD)」\n(可以嘗試刪去不需要的，或只取英文字母的部分。)\n相似及延伸 1.0049. Group Anagrams 2.0438. Find All Anagrams in a String Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-28T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-41-hash-table-2/","title":"從LeetCode學演算法 - 41 Hash Table (2)"},{"content":"0238. Product of Array Except Self (Medium)\nQuestion Given an array nums of n integers where n \u0026gt; 1, return an array outputsuch that output[i] is equal to the product of all the elements of numsexcept nums[i].\nExample:\n1 2 Input: [1,2,3,4] Output: [24,12,8,6] Note: Please solve it ** without division** and in O(n).\nFollow up:\nCould you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.)\n分析/解題 題目給定一個陣列nums，目標是產生一個output陣列，\n這個output上的output[i]都相當於除了nums[i]以外其他的乘積。\n要求不能用除法且必須在O(n)的時間完成。\n延伸要求：用來做為輸出的output不算在額外的空間內的話，\n是否可使用常數空間複雜度來解決此題？(即僅使用O(1)空間)\n這題如果用暴力法來解的話，\n就是使用兩層for-loop，將每個output[i]先初始化為1，\n再進行對其他值的相乘(也就是要乘N-1次)，\n所需的總乘法會是N*(N-1)，故時間複雜度為O(N²)。\n這樣顯然速度不太好，我們再來考慮一下實際的情形。\n1 2 3 4 nums 2 3 4 5 res 3*4*5 2*4*5 2*3*5 2*3*4 l 2 2*3 2*3*4 r 3*4*5 4*5 5 假設有一個陣列是[2, 3, 4, 5]，而我們要求的結果是res，\n按照定義我們可以先將res的結果寫出。\n仔細觀察我們可以發現，如果將res的每項拆成兩組相乘 ，\n我們可以拆分成l, r兩個陣列，\n當中l從index 1 開始往後推 有數值，依序是2, 2*3, 2*3*4 。\nr則從index 2 開始往回推 有數值，依序是5, 4*5, 3*4*5 。\n(這邊的拆分就是取明顯有斷層 的部分，空出來的部分為1 )\n所以我們可以先將res初始化，用它承載l 的部分，\n再依次將r從1開始，把5,4,3依序乘上去一個值以後依序乘到res中，\n這樣一來計算res的時候就只有分別經歷過兩次O(N)，\n時間複雜度會維持在O(N)。\n同時，因為前面第一次利用了res來儲存l的部分，\n第二次只用單個變數r來依序記錄要乘的順序，\n故扣除res以後空間複雜度為O(1)。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N)/O(1))\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-26T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-40-array-9/","title":"從LeetCode學演算法 - 40 Array (9)"},{"content":"1160. Find Words That Can Be Formed by Characters (Easy)\nQuestion You are given an array of strings words and a string chars.\nA string is good if it can be formed by characters from chars (each character can only be used once).\nReturn the sum of lengths of all good strings in words.\nExample 1 1 2 3 4 Input: words = [\u0026#34;cat\u0026#34;,\u0026#34;bt\u0026#34;,\u0026#34;hat\u0026#34;,\u0026#34;tree\u0026#34;], chars = \u0026#34;atach\u0026#34; Output: 6 Explanation: The strings that can be formed are \u0026#34;cat\u0026#34; and \u0026#34;hat\u0026#34; so the answer is 3 + 3 = 6. Example 2 1 2 3 4 Input: words = [\u0026#34;hello\u0026#34;,\u0026#34;world\u0026#34;,\u0026#34;leetcode\u0026#34;], chars = \u0026#34;welldonehoneyr\u0026#34; Output: 10 Explanation: The strings that can be formed are \u0026#34;hello\u0026#34; and \u0026#34;world\u0026#34; so the answer is 5 + 5 = 10. Note:\n1 \u0026lt;= words.length \u0026lt;= 1000 1 \u0026lt;= words[i].length, chars.length \u0026lt;= 100 All strings contain lowercase English letters only. 分析/解題 給定字串陣列words和一個字串chars，\n如果陣列中的一個字串能被定義為good，\n代表它是能由chars的中的字元組成(每個字元最多只能使用一次 )，\n試將所有good的字串長度加總回傳。\n一般用來描述某個項目儲存多少值都會使用HashTable/HashMap，\n對應到Python則通常可使用dictionary。\nHashTable相關的儲存方式有搜尋為O(1) 的特性，\n和一般常見的搜尋資料結構如Binary Search Tree需要O(log N) 不同，\n原因是因為會實作hash function，令不同的值儲存的時候能夠得到不同的hash值，從而直接找到對應的位置。\n(但當hash function的選擇不好 ，或儲存的東西太多時，\n有機會發生碰撞(collision) 問題，導致查找時間加長，這裡暫不討論。)\n在題目的條件限定在英文字母相關的時候或有特定長度限制時，\n我們常可以用很簡單的方式來進行hash table/hash map的操作，\n例如英文字母a~z只有26個，\n如果題目和計算字母出現的次數有關聯性的話，\n我們可以直接以一個長度為26的陣列/串列來記錄 。\n以這題來說，題目所要求的檢查方式，\n就是先確認chars裡面有幾個a, 幾個b, \u0026hellip;\u0026hellip; , 幾個z ，\n接下來對每個字串 確認其組成，\n一旦組成需要的個數大於chars所擁有的，我們就可以直接跳過它 ；\n反之若每個字母所需的個數都滿足，\n則將要回傳的結果加上這個字串的長度，\n一直到全數檢查完畢即可回傳結果。\n下面Java的程式碼部分演示了上面所提到的步驟。\n裡面用到語法蜜糖(Syntactic sugar)的作法，讀者應稍加掌握，\n如for迴圈Java有提供連續從array中依序取出單個變數的寫法，\n類似於Python中**”for word in words”** 的方式。\n我們將check的部分獨立出來，作為檢查並回傳長度的部分，\n一旦沒有成立，直接回傳0，若最終檢查通過則將len(word)回傳。\n之前應該也提到過char可以使用ASCII的代表數字來加減 ，\n所以這邊取a到z來做為index 0到26，起始的基準點是\u0026rsquo;a\u0026rsquo;。\nJava Python的部分，使用Counter 可以很簡便的計算一個字串中的字母組成，\n我們可以直接檢查每個key的值的大小來確認是否足夠組成，\n但需留意Counter並不會 放置沒有出現的字母的key，\n故每次要先檢查是否dic中本來就沒有現在要檢查的key值，\n避免發生錯誤。\n更簡便的方式是直接使用count 來計算某個字母在字串裡面出現的次數。\n這個應該是目前Python答案中跑最快的方法，\n但可能是因為測試資料中比較常出現False的狀況，\n導致word不用每個字母都算完就結束了 。\n不然在最糟的狀況下，word的每個字母應該都會算一次count，\n且相同的字母在不同的位置上還會重新再算過一次；\n雖然時間複雜度還是一樣(字串最長限定是100)，\n若整份資料比較容易是good的字居多的話，\n並不建議用這樣子的方式操作。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(Java: O(N)/O(1)，\n準確來說，最大要走完所有字的長度(所以應該可以說N個字*長度L)，\n空間的部分，使用了26個字母來做為查表用的分類，\n所以同一時間用到的只會有2組長度26的陣列及幾個暫存用變數\nPython: 對二個解也都是 O(N)/O(1)，\n但第二個解在最差的狀況下會每個字母都重覆掃過。)\n相似及延伸 Special Thanks suggestions/corrections from viewers:\n(迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-25T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-39-array-8-hash-table-1/","title":"從LeetCode學演算法 - 39 Array (8) / Hash Table (1)"},{"content":"0088. Merge Sorted Array (Easy)\nQuestion Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.\nNote:\nThe number of elements initialized in nums1 and nums2 are m and n respectively. You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. Example:\n1 2 3 Input: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [2,5,6], n = 3 1 Output: [1,2,2,3,5,6] 分析/解題 這題雖然相對比較無聊，\n但merge的過程中其實蠻像merge sort的merge的，\n所以選來讓讀者熟悉一下merge的概念，對上上篇提的應該會有幫助。\n題目給定兩個陣列及有放元素的對應長度，兩者除了未放元素的0以外，\n其他均已排序。同時，題目也假設第一個陣列必定有足夠空間，\n可以放入全部的元素。請嘗試將兩個陣列merge成一個排序的陣列，\n放置在第一個陣列中 。\n由於最終要放在nums1裡，我們可以先考慮會有的情形：\nn等於0：不用搬了，因為只有nums1有非0值。 m等於0：只要把nums2的全搬過來即可 其他：按照merge的原則，將雙方依序填入nums1中。 到這邊讀者可能會想到常規的merge是開一個新陣列 將雙方依次比較，\n每次將較小的值放入新陣列，最後排序完成。\n現在說想放到nums1當然是可以，但nums1前面有值 ，\n直接這麼做會蓋掉耶！那怎麼辦呢？\n答案很簡單，我們已經知道兩邊的長度是m跟n，\n那麼合併後的長度就會是m+n ，尾端的index會是m+n-1 。\n我們只要將**「每次將較小的值放入開頭」** 改成**「每次將較大的值放入結尾」** ，最後即可達到相同的狀況。\n所以操作順序會是：\n令i, j, k分別為m-1, n-1, m+n-1 2. 當i和j都≥0 時：\n如果nums1的值比nums2的值大，\n將nums1的尾端放到k的位置，同時遞減i跟k以更新。\n如果nums1的值比nums2的值小(或相等)，\n將nums2的尾端放到k的位置，同時遞減j跟k以更新。\n重複這個迴圈直到跳出，代表有一邊陣列放完了 。\n當 i ≥ 0 時，表示其實我們已經做完了，所以不用任何操作。\n(剩下nums1前面的部分，不需要再動了)\n當 j ≥ 0 時，表示 i 的部分已經被用完了，\n剩下的就是一路將 j 的對應值填入即可。\nJava的部分，可以利用**”\u0026ndash;“** 讓對應index先填入以後再進行遞減，\n步驟流程請參考上面演算方式並對照。\nJava Python沒有++或 \u0026ndash; 這種東西，所以遞減時要乖乖的自己等於自己減一，\n不過可以將需要遞減的寫在同一行，會稍微簡潔一點點。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(m+n)，O(1)\n前者是典型merge的時間，後者是因為我們只有使用常數變數，\n其他都是原有的記憶體空間，故僅額外占用到O(1)的空間)\n相似及延伸 1.0021. Merge Two Sorted Lists (Easy) 2. 0148. Sort List (Medium) Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-23T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-38-array-7/","title":"從LeetCode學演算法  - 38 Array (7)"},{"content":"0121. Best Time to Buy and Sell Stock (Easy)\nQuestion Say you have an array for which the ith element is the price of a given stock on day i.\nIf you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.\nNote that you cannot sell a stock before you buy one.\nExample 1 1 2 3 4 Input: [7,1,5,3,6,4] Output: 5 Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. Not 7-1 = 6, as selling price needs to be larger than buying price. Example 2 1 2 3 Input: [7,6,4,3,1] Output: 0 Explanation: In this case, no transaction is done, i.e. max profit = 0. 分析/解題 買股票啦XD~題目給定一個陣列，第i個元素代表day i的股價。\n如果你只被允許完成一次交易(買一次然後賣一次)，\n嘗試找到最大的利潤為何。\n我們假定我們在某個時間點買了股票，\n那獲得的利潤每隔一天，就會變動這兩天的差價值。\n我們可以將當下的利潤定為cur，那麼cur不論從哪開始必定為0。\n(當天買當天賣)\n假定有一天股價低於 我們買的時候的價格，就表示我們買貴 了，\n應該要從現在這個點開始一定會比前面那個點還好 ，(買進的價格較低)\n我們可以將cur重設為0(從這個點重新出發) 。\n反之如果價格比較高的話，我們可以計算現在的利潤，\n並和全局最大值比較後再更新全局最大值。\n所以每次依序計算現在的利潤決定是否重新選擇出發點，\n再處理好全局最大值的紀錄即可解決此題。\n這邊Java和Python的程式碼僅差別在設定條件的方式不同而已，\n但本質一樣是在處理現有的值 及最大值 這兩項。\n讀者可以自行選用處理的方式。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1)，掃過整個空間一次，除cur跟res外不需其他變數。)\n相似及延伸 1.0053. Maximum Subarray 2. Best Time to Buy and Sell Stock系列題(XDDDDD)\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-22T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-37-dynamic-programming-8/","title":"從LeetCode學演算法 - 37 Dynamic Programming (8)"},{"content":"0148. Sort List (Medium)\nQuestion Sort a linked list in O(n log n) time using constant space complexity.\nExample 1 1 2 Input: 4-\u0026gt;2-\u0026gt;1-\u0026gt;3 Output: 1-\u0026gt;2-\u0026gt;3-\u0026gt;4 Example 2 1 2 Input: -1-\u0026gt;5-\u0026gt;3-\u0026gt;4-\u0026gt;0 Output: -1-\u0026gt;0-\u0026gt;3-\u0026gt;4-\u0026gt;5 分析/解題 試以O(n log n)的時間複雜度來排序一個linked list。\n這題其實還有設定一個constant space complexity的條件，\n但要達成這個條件的話，要很仔細的使用迭代的方式來做merge sort才行，\n這邊主要會講一般的遞迴解(也就是空間複雜度不會是O(1))，\n若對迭代解有興趣，可以參考 theoneneo 或 ** sladkey**** 的解法。**\n關於排序有很多不同的方式，\n我們這邊先來講一個相當常見且經典的排序法：合併排序法(Merge Sort)\n合併排序法的概念是先拆半再合併 ，一般在演算法中為了遞迴起見，\n會直接把拆半的部分叫mergesort ，而合併的部分就稱為merge 。\n什麼是拆半 ？就是每次將整組資料分成兩半，\n一路拆分直到只剩下一個，這時候每一個單位而言均為排序好的狀態。\n(廢話XD 就一個而已當然是排好的)\n拆分完以後，要進行合併 的動作。\n合併就是指將同一層的兩組資料，按大小由小到大 置入。\n我們可以參考範例的動畫，一開始由於拆到每組只剩下一個，\n可以很輕易的比較誰大誰小，進而每次將較小的放入到合併的陣列中，\n所以每一次合併 完以後，我們都可以得到一個**由小排到大的一組資料，\n同時下一次我們依舊可以使用兩組各自由小排到大的資料，\n使用two pointer的方式就可以依序將其合併。**最後合併回最開始那一層，我們就可以得到一個排序好的陣列了。\nMerge Sort範例\n最後排序完的結果\n這樣子將目標先拆小以後再進行合併的手段，\n我們通常稱之為分治法(divide-and-conquer) ，\n也就是將大問題拆成小問題解決的一套思路。\n由於一定要拆成每組只有單筆資料，每次拆分為一半，\n故拆分的時候，會拆成logN層；又每次合併也都需要掃過每筆資料，\n總時間複雜度必須再乘上N，所以最終的時間複雜度為O(NlogN) 。\n當中每次合併都需求一個新的位置來作為承接它的狀態，\n所以一般來說可使用O(N) 的空間來儲存。\n總體而言，一個mergesort的演算法流程大致如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 function mergesort(arr, l, r) { if r \u0026gt; l { m = (l+r)/2 mergesort(arr, l, m) mergesort(arr, m+1, r) merge(arr, l, m, r) } } function merge(arr, l, m, r) { 開一個新的陣列tmp，將arr的index l到index r的部分複製過去(包含r) i = l, j = m+1, cnt = 0 比較tmp[i]和tmp[j]，將較小的複製到arr[l+cnt]並遞增cnt跟有被複製的i/j其一 重複上一個步驟直到一方沒有可以比較的部分，將剩餘的數字全數依序放入arr中 } 回到我們的問題，\n現在要排序的應該是LinkedList，和陣列的唯一差別是，\n我們需要一些手段才能取到中間點，這裡同樣使用slow跟fast兩個pointer的方式，讓slow一次走一格，而fast一次走兩格，直到fast到底的時候(遇到NIL)就代表slow應該走到一半了，此時不要忘記將中間的slow的前一個節點prev跟slow進行斷開 ，prev的用途就是用來紀錄slow的前一個節點的。\n(因為不是陣列，我們是依靠next是否為NIL 這點來判斷節點的分組)\n接著在merge的部分，我們取用了一個n作為dummy node(也就是用來紀錄開頭用的節點)，接著使用iterator(ite)來進行檢查，同樣是檢查哪個比較小，\n這時對於Linked List而言應該是將節點串接在後面 即可。(不要忘記串接了某一個以後，該節點也要往下走，相當於陣列中的i跟j其一要遞增。)\n最後同樣，若有一方無法比較，則我們可以直接把剩下的節點接上去。\n(ite.next = n1或ite.next = n2)\n範例程式碼的部分這邊採用了leetcode使用者jeantimex的解法，\n筆者加了一點註解，搭配前面文章的說明，\n使用者應該可以較輕鬆地了解整個解題的思路和作法。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(NlogN), O(logN)\n將一個串列不斷拆成二等份，直到剩下單一節點，\n相當於在求N可以被二分拆幾次，乘上最終會有N個單節點再次合併，\n故總體時間複雜度為O(NlogN)。) (註:這只是很粗糙的說法，有興趣可以翻閱演算法書籍，會有較嚴謹的證明)\n(對於每一次的拆分搜尋都需要用O(1)的記憶體來儲存這層的stack，\n理想狀況下會有logN層，故平均空間複雜度為O(logN)，\n最差的狀況則為O(N))\n「還有一些常見的排序，你能說出它們的時間複雜度嗎？」\n(selection/insertion/bubble等均為O(N²)，quick/merge均為O(NlogN)，\n需留意quicksort的worst case是O(N²))\n相似及延伸 1.0021. Merge Two Sorted Lists (Easy) Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-36-merge-sort-1/","title":"從LeetCode學演算法  - 36 Merge Sort (1)"},{"content":"0108. Convert Sorted Array to Binary Search Tree (Easy)\nQuestion Given an array where elements are sorted in ascending order, convert it to a height balanced BST.\nFor this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differs by more than 1.\nExample:\n1 Given the sorted array: [-10,-3,0,5,9], 1 One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST: 1 2 3 4 5 0 / \\ -3 9 / / -10 5 分析/解題 給定一個陣列，其元素以升冪排序 (也就是後面的一定比前面大)，\n試將其轉成一個高度平衡的二元搜尋樹。\n高度平衡的樹由於已在先前的題目中講過了(0110. Balanced Binary Tree)，\n這邊就不再贅述，簡言之就是對每個節點，\n其兩邊的子樹深度相差均\u0026lt;=1就對了！\n我們知道要達到這個條件，最基本的就是一個root的左右兩邊要公平，\n所以最簡單的作法就是取中位數作為根，其左邊就是左子樹的所有節點，\n右邊就是右子樹的所有節點；再分別讓各自的左右子樹再次拆分，直到分到沒有節點為止。\n這樣作可以讓每一層都均分節點，從而讓每個分支的深度基本接近一致。\n故整體流程如下：\n檢查陣列是否是空的或者null，是的話直接回傳 呼叫一個用來遞迴建立BST的函式，這邊命名成getNode() getNode會輸入陣列以及當下的左右邊界(nums, l, r) (一開始l = 0, r = N-1, N是nums的總數) 每次先檢查左右邊界是否黃金交叉(表示已經完成了，可以回傳null) 讓mid = l加r的一半，直接建立一個root節點 root節點的左節點 就應該是呼叫getNode(nums, l, mid-1) 得到的結果 root節點的右節點 則會是getNode(nums, mid+1, r) 得到的結果 回傳root 我們可以看到每次會抓中間值產生一個節點，再利用已排序的特性，\n繼續進入遞迴往下將左邊和右邊的節點處理完畢。\n思考它的執行流程，應該會發現總體而言我們會先一路來到最左邊的節點，\n再回頭建立每個遞迴函式的右邊節點；\n也就是說，程式執行的優先順序是先往深處的方向走 而非先將這一層的狀況處理完，這種模式我們稱之為深度優先搜尋(Depth-First Search, DFS) ；\n如果換作是優先順序是先廣泛地處理完這一層，再往下一層走 ，這種模式就稱之為廣度優先搜尋(Breadth-First Search, BFS) 。\n程式碼的部分，僅需留意Java因為想避免overflow的狀況，\n計算的方式為 start + (end - start) / 2 ，而非(start + end) / 2。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(N)\n每個節點都會掃過一遍，且基本和其他節點沒有太多連帶關係。)\n「那麼如果要將一個BST轉成排序陣列 呢？」\n(原則上可用Inorder Traversal ，\n但留意不加NIL的狀況其實中間樹的架構資訊可能會就此流失掉)\n相似及延伸 0109. Convert Sorted List to Binary Search Tree (起始給的從陣列/串列改成排序好的LinkedList) Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-20T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-35-bst-3/","title":"從LeetCode學演算法 - 35 BST (3)"},{"content":"0977. Squares of a Sorted Array (Easy)\nQuestion Given an array of integers A sorted in non-decreasing order, return an array of the squares of each number, also in sorted non-decreasing order.\nExample 1 1 2 Input: [-4,-1,0,3,10] Output: [0,1,9,16,100] Example 2 1 2 Input: [-7,-3,2,3,11] Output: [4,9,9,49,121] Note:\n1 \u0026lt;= A.length \u0026lt;= 10000 -10000 \u0026lt;= A[i] \u0026lt;= 10000 A is sorted in non-decreasing order. 分析/解題 給定一個非遞減排序(也就是相等或遞增)的陣列，\n以排序好的狀況回傳其每個元素平方後所得的陣列。\n一般我們所熟知的排序應該需要至少O(NlogN)的狀況才能達成，\n(之後筆者會再挑一題來專門作排序這個部分的問題)\n但這題在平方過以後，並不算完全散亂的狀態，\n原先負整數的部分平方後會由大到小排列 ；\n原先0到正整數的部分平方後則會由小到大排列 。\n利用這點我們可以使用two pointer的模式來進行處理，\n每次將兩邊的元素絕對值進行比較，比較大的代表其平方後比較大，\n將其取出置於新的陣列/串列的最右邊，依序往回填。\n實作上，如果不限制A必須保持原樣的話，\n也可以先將負號的部分全數去掉，再進行後面的比較時，\n就可免去取絕對值了。\nJava的部分兩個方法皆有提供，讀者可依實際狀況決定寫法。\nJava Python的部分，還另外提供了一個偷吃步的方法：\n使用sorted函式搭配list comprehension，一行即可解決問題，\n但其時間複雜度為O(NlogN) (因為直接使用排序法)\n神奇的是，這個方法還比較快XD\n(估計是A的長度限制在比較小的範圍，可能測試資料也不是很大，\n所以主動用排序帶來的負面效益較低的原因)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(N)\n每個陣列均會掃過一次，且會產生一個新的陣列。)\n「這題在產生新的陣列的時候跟合併排序(Merge Sort)其實很像，\n可以概略描述Merge Sort的作法嗎？」\n(可以XD 這個我們之後會專門寫一題講解)\n(如果不想等的話，可以先查詢Merge Sort，應該有蠻多資料的，\n但簡言之，就是每次將陣列拆兩半，\n分別各自排序過後(mergesort)，再依序合併起來(merge)。)\n相似及延伸：\n1. 0021. Merge Two Sorted Lists (Easy)\n2. 0148. Sort List (Medium)\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-19T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-34-array-6/","title":"從LeetCode學演算法 - 34 Array (6)"},{"content":"0905. Sort Array By Parity (Easy)\nQuestion Given an array A of non-negative integers, return an array consisting of all the even elements of A, followed by all the odd elements of A.\nYou may return any answer array that satisfies this condition.\nExample 1 1 2 3 Input: [3,1,2,4] Output: [2,4,3,1] The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted. Note:\n1 \u0026lt;= A.length \u0026lt;= 5000 0 \u0026lt;= A[i] \u0026lt;= 5000 分析/解題 給定一個不含負整數的整數陣列A，回傳一個陣列，\n這個陣列的前面會是所有A的偶數的元素，\n跟在後面的是所有A的奇數的元素的部分。\n這題我們在先前的Move Zeros題目中有提到過類似的部分，\n如果當時我們只想把0往後挪而不需考慮保留原順序，\n可以從兩端開始掃描，找到左邊是0而右邊非0並交換 就可以解完此題；\n這題概念是一樣的，只是變成要左邊全是偶數，右邊全是奇數 。\n演算的順序大概會像這樣：\n分別取兩端的index作為起始(i = 0, j = l-1, l為A的長度) 先確認i的位置是否為奇數，若否，則遞增i，直到A[i]為奇數 再確認j的位置是否為偶數，若否，則遞減j，直到A[j]為偶數 交換A[i], A[j] 重複前述2~4的操作直到i不再小於j(開始前也要檢查) 此時全數交換完畢，所有偶數應排在奇數之前 這邊程式碼需要注意continue的作用，\n目的是讓每次index變動都進行i\u0026lt;j的檢查，\n唯有這個條件成立，我們才有可能需要進行交換。\nJava Python的部分後面提供了一個非in-place的作法，\n也就是各自將偶數和奇數的串列累積起來，\n最後再將其連接。好處是比較簡單，缺點是要額外的空間來存，\n端看使用者需求和題目需求來決定。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1)\ntwo pointer會掃過整個陣列，所以時間複雜度為O(N)；\n如果不另外開陣列/串列的話，可以用in-place達到則空間複雜度為O(1)，\n如果像Python額外提到的方法的話則由於額外儲存的關係需要O(N))\n「如果除了偶數在前，奇數在後以外，要按照原先順序排列呢？」\n(Python的另一個解就會按順序排)\n相似及延伸：\n1. ** 0283**. Move Zeros\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-18T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-33-array-5/","title":"從LeetCode學演算法 - 33 Array (5)"},{"content":"0700. Search in a Binary Search Tree (Easy)\nQuestion Given the root node of a binary search tree (BST) and a value. You need to find the node in the BST that the node’s value equals the given value. Return the subtree rooted with that node. If such node doesn’t exist, you should return NULL.\nFor example,\n1 2 3 4 5 6 Given the tree: 4 / \\ 2 7 / \\ 1 3 1 And the value to search: 2 You should return this subtree:\n1 2 3 2 / \\ 1 3 In the example above, if we want to search the value 5, since there is no node with value 5, we should return NULL.\nNote that an empty tree is represented by NULL, therefore you would see the expected output (serialized tree format) as [], not null.\n分析/解題 給定一個二元搜尋樹及一個值，試找到這個樹上含有該值的節點；\n如果找不到任何節點的值和此值相等的話，回傳NULL。\n一個Binary Search Tree在進行搜尋特定值上最大的好處就是，\n**碰到相等是目標，比完較小往左走，\n比完較大往右走，走到盡頭就沒有。(XDDDD)**類似binary search，只是我們的每次切半/改動上下界的操作，\n更改為往左走或往右走。\n所以我們只要進行遞迴，直到走到NULL(NIL)或走到剛好對的值即可，\n下面的程式碼中，由於判斷root是否為NIL 及root的值等於目標值 的狀況，\n均為回傳root (雖然一種情況是NIL，另一種情況不是)，\n所以我們可以將之合併。\n而當val \u0026lt; root.val 的時候，\n選擇往左走 去找比當下的root更小的值 來比較，反之則往右走。\n在實測上以筆者目前的觀察，是否全數使用if/elif連貫的判斷式，\n或者前面root的回傳是否合併成一個情況，\n均對執行的速度沒有特別明顯的影響 ，\n故讀者可依自己的喜好選擇撰寫的方式，只需邏輯正確即可。\n此外，之前可能有提到過的三元運算子 ( ? : )也僅是方便縮短行數，\n同樣對結果沒有影響。\nJava Python 如果讀者習慣於使用LeetCode解二元樹或二元搜尋樹的題目，\n應該會發現其實二元搜尋樹是可以使用陣列/串列的方式進行輸入 的。\n這麼做的好處是只要管理好index，就可以用index的操作 來達到走訪某個節點的目的，而不用真的去把每個節點都進行連結到left/right。\n缺點的部分則是有些地方必須輸入null進去(因為有可能會是null節點)。\n讀者可以找一些題目來思考一下，\n(像是前面的0094. Binary Tree Inorder Traversal)\n如果從index i想要走到其left/right節點，這兩個的節點index會是多少呢？\n讀者可以開啟Testcase中的Tree Visualizer，\n來觀看輸入的陣列會長成的樹的形狀。\n(註：這種表示法未必是通用的，但可以做為參考。)\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(Worst case O(N)/Average Case O(logN) , O(1)，\n最糟的狀況是所有節點集中在同一側，一路搜尋到最底下；\n平均來說，如果節點較接近平衡的分布的話，\n每次搜尋往下走能去掉一半的可能性，所以會是O(logN)。\n由於不需要額外的紀錄，所以空間複雜度為O(1))\n相似及延伸 1.0701. Insert into a Binary Search Tree Special Thanks suggestions/corrections from viewers: 感謝Tony Kuo 的建議，這邊附上之前講的BST定義及validation的文章。\n從LeetCode學演算法 — 16 BST (1) (0098. Validate Binary Search Tree)\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-16T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-32-bst-2/","title":"從LeetCode學演算法 - 32 BST (2)"},{"content":"0141. Linked List Cycle (Easy)\nQuestion Given a linked list, determine if it has a cycle in it.\nTo represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.\nExample 1 1 2 3 Input: head = [3,2,0,-4], pos = 1 Output: true Explanation: There is a cycle in the linked list, where tail connects to the second node. Example 2 1 2 3 Input: head = [1,2], pos = 0 Output: true Explanation: There is a cycle in the linked list, where tail connects to the first node. Example 3 1 2 3 Input: head = [1], pos = -1 Output: false Explanation: There is no cycle in the linked list. Follow up:\nCan you solve it using O(1) (i.e. constant) memory?\n分析/解題 給定一個Linked List，試檢查其是否含有一個環(Cycle) 在裡面。\n我們有一小段時間沒有講Linked List，這邊不再贅述其基礎特性，\n想要複習的讀者可以參閱第4篇的說明。\n當我們在考慮這個題目的時候，會留意到兩個特性：\n這個Linked List是指Single Linked List(也就是指向的方向只有單向)。 如果有環的話，應該會從最後一個節點再連接到前面的節點。\n(從中間的話就會產生分歧的狀況) 在以上的特性狀況下，假設有一個環在Linked List中的話，\n取一個節點從head開始不斷往其next走，會先經過最後一個節點，\n接著再接回到前面某個節點再往下走，這樣會是一個循環；\n更重要的是，顯然一進入這個環中，接下來就會一直在環內移動 。\n(因為走到尾端又會再接回來)\n這裡我們引入一個蠻常用的解題方式：設定快速和慢速的指標 。\n我們讓fast和slow先設定在head的位置，每次fast走兩步，slow走一步 ，\n它們就像是國小時針分針追趕的感覺一樣。\n接下來我們可以將狀況分成以下兩種：\n假設有環 的狀況，\n不管走多快多慢都會陷入這個環內 ，\n所以會變成每次fast多走了一步，這一步用來追趕slow 。\n因為slow也沒別的地方可以躲，所以fast每次多走一步一定可以趕得上\n(也因為一步一步趕所以沒有追上卻錯開的可能)。\n因此，我們知道fast和slow最終會來到相同的位置(也就是兩者相等 )\n假設沒有環 的狀況，\n由於不會重複，故最終fast一定會先走到尾端 ，最後看到NIL 。\n故我們要做的事情很簡單，只要先設定fast跟slow，\n在它們沒有走到NIL之前，每次去檢查fast是否有追上slow。\n追上的話就回傳true ，而如果看到fast的下一個節點是NIL 的話，\n就代表走到盡頭了 ，此時應該要回傳false 。\n整個演算的順序：\n考量起始的狀況，我們必須先檢查head跟head.next 當中是否有NIL值\n開始一個迴圈，\n開始前讓fast被設定為fast.next.next，slow則被設定為slow.next 。\n當fast還沒有遇到NIL前，每次各自走相應步數，再檢查兩者是否相等。\n(相等表示有環 ，回傳true )\n請注意：當fast和fast.next 都處於非NIL 的狀況時，迴圈才能夠執行。\n當fast或fast.next是NIL的話：表示走到盡頭了！跳離迴圈後，\n將其return false 以表示它當中並沒有環。\n寫成程式碼大概如下面所示：\nJava Python這邊額外提供了LeetCode使用者 StefanPochmann 的做法，\n這個做法使用了try…except來進行錯誤處理，\n有興趣的讀者不妨試試看。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1)\n由於fast比slow每次多走一步，我們可預期在走環的部分時，為了相遇走的長度的複雜度為O(K)。那麼K最大也頂多就是囊括所有節點，\n所以時間的複雜度最大就會取決於N 。\n當然，還有另一種狀況是裡面沒有環 ，\n時間複雜度也是O(N)。(走到底就結束了)\n另外，我們沒有另外需要存下其他整個LinkedList的節點，所以僅有一些必要的節點被宣告，故空間複雜度為O(1))\n相似及延伸：\n1. ** 0142.** Linked List Cycle II\nSpecial Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-15T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-31-linked-list-4/","title":"從LeetCode學演算法 - 31 Linked List (4)"},{"content":"0144. Binary Tree Preorder Traversal (Medium)\nQuestion Given a binary tree, return the preorder traversal of its nodes’ values.\nExample:\n1 2 3 4 5 6 Input: [1,null,2,3] 1 \\ 2 / 3 1 Output: [1,2,3] Follow up: Recursive solution is trivial, could you do it iteratively?\n分析/解題 題目給定一個二元樹，試求其Preorder Traversal(前序走訪)。\n先前我們介紹過Inorder Traversal，對於Preorder，大家應該也會有一個心理準備，就是使用遞迴會很簡單，迭代則會不容易思考XD。\n再複習一下，所謂的Preorder指的是走訪的順序依序為根-\u0026gt;左-\u0026gt;右 ，走訪的時候遇到根的時後先輸出，接著優先往左邊走，當左邊的全走完時，\n才檢查右邊的節點，依此順序將所有節點輸出。\n作為遞迴的方式，我們每次將根節點的值放進res(result)中，接著再呼叫遞迴依序進行左邊節點和右邊節點的走訪即可。\nJava中使用add，Python中則用append，在前面不要忘記檢查當走到NIL(null/None)的時候要退回到上一層(直接return)。\n那麼，迭代的方式呢？\n由於之前我們已經提到過在Python裡面，List的append/pop可以拿來當作stack的push跟pop來使用，要用Queue的話則必須用Deque。\n所以我們這邊依舊使用stack的思路來解題。\n我們已經知道對於stack來說有LIFO(後進先出) 的特性，\n利用這點，我們可以讓進入stack的順序設定為右-\u0026gt;左-\u0026gt;根，\n如此pop出來的時候順序即會符合根-\u0026gt;左-\u0026gt;右的狀態。\n思路如下：(前面應先檢查root是否為NIL)\n設置一個stack名為st，將root放入，再設一個記錄結果的串列res。 當st裡面有節點時，pop出一個節點n 。 將n的右節點 push至st(如該節點不為NIL) 將n的左節點 push至st(如該節點不為NIL) 將n的值 放到res中 重複2~5直到st中沒有任何節點 這樣一來，我們可以使用一個迴圈，令res依preorder的順序拿到節點值。\nJava Python 這題比較困難的部分就在於迭代法的解法，\n如果讀者一時無法理解，請嘗試用紙筆列出一些狀況操作，\n會較能夠體會該方法是如何利用迴圈來達到目標的。\n同時，存入根節點的值的時間點不同 ，\n基本就決定了它是哪一種Traversal。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(N)，因為最終都需要儲存整份樹攤平的結果)\n「樹的形狀會影響其時間空間複雜度嗎？」\n(只會影響中間空間暫存需要的大小(因為有stack或call stack)，\n但複雜度不變 )\n「給定一棵二元樹，\n請依序寫出preorder/inorder/postorder/levelorder的結果」\n(簡單卻重要，請讀者務必自己畫一棵並嘗試寫一下順序，\n看看是否有搞混的地方，尤其是每次印出根節點的時機很重要。)\n「如果該樹是BST，且改為inorder的話，\n能否找到任二節點相差的絕對值當中的最小值？」\n(利用inorder的狀態排出來的順序會是遞增排列，每次檢查相鄰的數即可。)\n相似及延伸 0145. Binary Tree Postorder Traversal Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-14T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-30-tree-7/","title":"從LeetCode學演算法 - 30 Tree (7)"},{"content":"0213. House Robber II (Medium)\nQuestion You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have security system connected and ** it will automatically contact the police if two adjacent houses were broken into on the same night**.\nGiven a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police .\nExample 1 1 2 3 4 5 Input: [2,3,2] Output: 3 Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses. Example 2 1 2 3 4 5 Input: [1,2,3,1] Output: 4 Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). Total amount you can rob = 1 + 3 = 4. 分析/解題 繼上一次偷完一排房子 以後，我們決定挑戰更高難度的偷竊XD\n(有完沒完啦！)\n保全狀態依舊是相鄰房子連續被偷就會響警報，不同的是，\n現在房子的分布是圓形！也就是第一間和最後一間是相鄰的，\n這就會造成我們上一次使用的算法會出現問題。\n那麼怎麼辦呢？\n第一間和最後一間有關聯是不是？\n那我們就來斷開魂結，斷開鎖鏈，斷開一切的牽連吧！(大誤)\n這裡我們為求方便起見，使用0為index開頭來描述，\n這樣等一下對照程式碼也比較方便。\n我們令nums的總長度為l ，\n並且使用dp[i] 來表示偷到index i的房子時當前所能得到的最大金額。\n如何處理index 0跟l-1的關係呢？\n針對index 0的話，只會分成偷 或不偷 。\n古語有云：\nTo rob, or not to rob, that is a question.\n莎士比亞沒有說過 所以我們可以分開來討論。\n假設今天無論如何就是要偷index 0 的房子的話，\n可以得到以下推論：\nindex l-1不能偷 dp[0] = nums[0], dp[1] = nums[0] (偷了0就不能偷1) 這狀況能得到的最大金額應為dp[l-2] (因l-1不能偷)\n這個狀況，我們可以給定2的起始條件並計算到dp[l-2]即可得到最大金額。 假設今天就是不偷index 0的房子的話，\n可以得到以下推論：\nindex l-1能不能偷只需要看index l-2 決定要不要偷 dp[0] = 0, dp[1] = nums[1] (因0不偷，dp[1]要選擇偷index 1) 這狀況能得到的最大金額應為dp[l-1] 所以依照這兩個狀況拆開來分別計算一次，\n將兩個結果比較大小，取較大的即為答案。\n同上一題描述的一樣，\n我們可以利用兩個變數及一個暫存變數，來達到dp的效果。\nJava Python的部分則再額外提供了將迴圈部分包裝成函式的程式碼，\n但實測上由於需要呼叫的原因，看起來平均會略慢於未包裝的狀況。\n(附在底下註解處，使用者可再多執行幾次試試看)\nPython 所以總體而言，這題的根本在於，當發現有些狀態是互相關聯時，\n嘗試將其進行拆解，從而重新得到線性可計算動態規劃的狀態。 再次強調， DP的精髓在於找到初始狀態，\n及找到從一個狀態推展到下一個狀態的方法。用骨牌來比喻的話，後者相當於 骨牌之間的關係，\n前者則相當於那個第一個倒下來的骨牌 。\n面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1)\n這次的範例程式碼已經不用dp陣列來記錄了，\n即便需要掃過nums兩次，但時間複雜度還是O(N))\n「如果保安增強，變成只要連續三棟房子內任二棟被偷即會有警報的話？」\n(可以嘗試用類似的方式來推導)\n相似及延伸 0337. House Robber III 2.0746. Min Cost Climbing Stairs Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-12T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-29-dynamic-programming-7/","title":"從LeetCode學演算法 - 29 Dynamic Programming (7)"},{"content":"0198. House Robber (Easy)\nQuestion You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night .\nGiven a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police .\nExample 1 1 2 3 4 5 Input: [1,2,3,1] Output: 4 Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). Total amount you can rob = 1 + 3 = 4. Example 2 1 2 3 4 5 Input: [2,7,9,3,1] Output: 12 Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1). Total amount you can rob = 2 + 9 + 1 = 12. 分析/解題 題目描述你是一個專業的強盜，即將進行入室行竊的勾當。\n每間房子都存有確定數量的金錢，但唯一的限制是，每間房都有安保設置，只要相鄰的二間房子在同一個晚上被闖入的話，系統就會自動報警。\n給定一個用來表示每間房子存放金額的陣列，試求在不驚動警察狀況下，\n最大可以獲得的金額。\n看到這個問題的時候，首先就想OS: 一間就報警的話不是最乾脆XD\n好吧，我們假設這個安保真的是有這種漏洞的話，\n那麼怎麼偷最好呢？\n由於題目條件的限制，我們先假設一路偷到第i間，\n所能獲得的最大金額為rob[i]，rob[i]會受到什麼限制呢？\n假設我們走到第i間，\n選擇要偷第i間的話，意味著我們前面不能偷第i-1間 。\n這種狀況下，我們可以將rob[i]的值拆開來算：\nrob[i] = rob[i-2] + num[i]\n(選擇不動第i-1間，並偷了第i間，\n而在此之前i-2間所能偷到的最大值是rob[i-2])\n那麼，選擇不偷第i間的話，意味著rob[i] = rob[i-1] (因為你沒偷嘛XD)\n既然有這兩種可能，那麼我們就該選當中比較大的，\n所以rob[i] = max(rob[i-1], rob[i-2] + nums[i]) 。\n讓我們考慮一下最前面的狀況：\nrob[0] = nums[0] (第一間不用考慮前面的影響)\nrob[1] = max(nums[0], nums[1]) (兩間選一間偷)\n所以接下來我們只需要一路用前面的式子，迴圈從i=2計算到i=n-1，\n最後將rob[n-1]回傳即可。\n所以一路下來，讀者會發現有關動態規劃的題目，\n一直在做的事情其實就是嘗試尋找在第n項的解，\n和前面的項次之間的關係，一旦能找到這個關係，\n並能確認初始的條件，就能一路從頭開始計算將其解出。\n在程式碼的部分，我們可以先行考慮nums為空跟長度為1的狀況，\n直接回傳結果以節省空間。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(N)，掃過一次nums陣列，\n並且也用相同長度來儲存最大的偷取金額)\n「空間複雜度可以降低嗎？」\n(可以！可以觀察出每個rob的值之間的關聯只有和前2個值有關(i-2和i-1)\n我們可以使用robprev, robnext搭配一個temp值，\n在迴圈中使用類似下面的方式，可以反復更新值，如此一來，\n就只需要O(1)的空間就可以解決此題。)\n1 2 3 int tmp = robprev; robprev = robnext; robnext = Math.max(robprev, tmp + nums[i]); 相似及延伸 1.0213. House Robber II (Medium) (從線性變圓形) 2. 0337. House Robber III (Medium) (變成二元樹 )\n(到底哪個鄉鎮會這樣子蓋房子啦XD)\nSpecial Thanks suggestions/corrections from viewers:\nFrom Medium:\nRaiy Kuo - 更正Python程式碼尾端，應回傳rob[-1]或rob[l-1]即可。\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-10T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-28-dynamic-programming-6/","title":"從LeetCode學演算法 - 28 Dynamic Programming (6)"},{"content":"0189. Rotate Array (Easy)\nQuestion Given an array, rotate the array to the right by k steps, where k is non-negative.\nExample 1 1 2 3 4 5 6 Input: [1,2,3,4,5,6,7] and k = 3 Output: [5,6,7,1,2,3,4] Explanation: rotate 1 steps to the right: [7,1,2,3,4,5,6] rotate 2 steps to the right: [6,7,1,2,3,4,5] rotate 3 steps to the right: [5,6,7,1,2,3,4] Example 2 1 2 3 4 5 Input: [-1,-100,3,99] and k = 2 Output: [3,99,-1,-100] Explanation: rotate 1 steps to the right: [99,-1,-100,3] rotate 2 steps to the right: [3,99,-1,-100] Note:\nTry to come up with as many solutions as you can, there are at least 3 different ways to solve this problem. Could you do it in-place with O(1) extra space? 分析/解題 題目給定一個陣列，將其往右輪轉k步，\n要求直接將該陣列調整成輪轉後的結果。\n這題一旦沒有Note的要求的話瞬間簡單一百倍 。\n舉例來說，我們可以直接將後k項和前l-k項合併起來(l為陣列長度)，\n就會是答案了；或者，將整個陣列重複銜接一次，取[(l-k):(2*l-k)]亦可。\n(這兩個解法筆者列在Python的註解中供讀者參閱)\n但，它們都不是in-place。\n要考慮到in-place的話，我們必須知道，\n一定有方法能讓他們跑到該有的地方，且不需用到超過O(1)以外的空間，\n一般就意味著會在陣列進行swap的操作(交換兩個元素)。\n先看一下原本的例子：\n[1,2,3,4,5,6,7] and k = 3 -\u0026gt; [5,6,7,1,2,3,4]\n先不論其他的部分，我們可以發現57從最尾端3個變成最前面的3個了；\n與此同時，14自然從最前面4個變成最尾端4個。\n我們先不論大家的順序，先將整個陣列倒過來的話，\n可以先達到14，57分別占據目標的區塊的效果：[7,6,5 ,4,3,2,1]。\n接著再比對一下，發現區塊是對了，但各自剛好被顛倒過一次 ，\n那麼我們再對75及41分別各進行一次反轉 ，就會得到我們要的結果。\n所以整個流程就會變成：\n將整個陣列 進行反轉 將前k個數 進行反轉 將後l-k個數 進行反轉 反轉是很基本的操作，希望讀者能熟練掌握，\n原則上利用two pointer的方式，每次將兩個元素進行交換 ，\n並對pointer位置進行遞增/遞減的操作，直到相交 為止。\n(例: [1 ,2,3,4 ]-\u0026gt;[4,2 ,3 ,1]-\u0026gt;[4,3,2,1])\nJava的部分的兩數交換需要宣告一個暫存值tmp(temp)，\nPython的部分則可直接使用a, b = b, a的方式進行交換。\n最後，操作之前不要忘記將k先取除以l的餘數。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1)(如果是使用3次reverse的方法))\n「如不限制空間複雜度必須O(1)？」\n(可以參照上面Python程式碼中註解的做法)\n相似及延伸 0031. Next Permutation (可以用到swap跟reverse的操作來解題) Special Thanks suggestions/corrections from viewers:\n(歡迎提供意見協助更正歐~)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-27-array-4/","title":"從LeetCode學演算法 - 27 Array (4)"},{"content":"0096. Unique Binary Search Trees (Medium)\nQuestion Given n, how many structurally unique BST’s (binary search trees) that store values 1 … n?\nExample:\n1 2 3 4 Input: 3 Output: 5 Explanation: Given n = 3, there are a total of 5 unique BST\u0026#39;s: 1 2 3 4 5 1 3 3 2 1 \\ / / / \\ \\ 3 2 1 1 3 2 / / \\ \\ 2 1 2 3 分析/解題 還記得什麼是二元搜尋樹嗎？\n不知道的話，可以翻閱前面的第16篇的介紹歐！\n簡言之，一個合法的BST除了左邊的節點要全小於根節點，右邊的節點要全大於根節點 外，\n其左右子樹也要是BST 才行。\n觀察n=3的狀況，我們可以將其歸納成3類：\n以1為根節點/以2為根節點/以3為根節點。\n首先是1為根節點的狀況：\n左邊沒有比其小的節點，故只有一種可能；\n右邊有2跟3的組合，相當於n=2的時候的狀況(2種)。\n(2跟3等價於1跟2兩個節點會有的組合)\n再來是2為根節點的狀況：\n左邊只有1種可能(1這個節點)；\n右邊也只有1種可能(3這個節點)。\n最後是3為根節點的狀況：\n左邊是1跟2的組合(2種)，\n右邊只有1種可能。\n如果我們將n的組合命名為函式f(n)，\n那麼顯然f(0)=1(只有一種可能)，f(1)=1。\n計算n=3的組合算法為：\nf(0)*f(2) + f(1)*f(1) + f(2)*f(0)\n掌握這個規律的狀態，我們可以得到f(n)的計算方式：\nf(0)*f(n-1) + f(1)*f(n-2) + … + f(n-1)*f(0)\n那麼，從f(1)開始起算的話，\n我們可以一路疊加將f(1)到f(n-1)都算出來，\n最後得到我們要的f(n)。\n讓f(n)能夠化成f(n-1)或較小的項次的組合，一路化簡到能直接確認的值，\n所以這個就是典型的動態規劃的範例。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n²), O(n)\n由於計算時兩層迴圈最大都要經歷n，故時間上會和n的平方相關)\n「可以改成遞迴 的方式嗎？」\n(可以，我們只要將dp改成字典或HashMap，開一個函式search，\n令其在找不到值的時候呼叫自己如 sum += search(i-1) * search(n-i)，\n最後也會如同迴圈的解法一樣一路拆解到最底下，\n讀者可以自行嘗試看看，實測上兩者速度在實作正確的狀況下，\n應該是感受不出太明顯的差異的。)\nSpecial Thanks suggestions/corrections from viewers:\nFrom Python Taiwan\n曾淯銘: 更正BST的筆誤(連結是對的，本文打錯，是左\u0026lt;根\u0026lt;右，已更正)\nChenRay Hsieh: 本文的解其實等同於Catalan number，讀者可參考閱讀。\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-07T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-26-dynamic-programming-5/","title":"從LeetCode學演算法 - 26 Dynamic Programming (5)"},{"content":"0283. Move Zeroes (Easy)\nQuestion Given an array nums, write a function to move all 0\u0026rsquo;s to the end of it while maintaining the relative order of the non-zero elements.\nExample:\n1 2 Input: [0,1,0,3,12] Output: [1,3,12,0,0] Note :\nYou must do this in-place without making a copy of the array. Minimize the total number of operations. 分析/解題 題目給定一個陣列nums並要求將所有當中的0全部都放到最後面，\n且必須保持所有非0的元素的原有相對排列。\n另外Note中還要求必須要in-place且最小化總共操作的次數。\n這題其實有很多變形，雖然簡單，\n務必請留意題目所要求的條件，不要倉促作答。\n首先題目強調必須in-place(in-place的部分先前的文章有提到過)，\n故諸如開一個ArrayList/List來將所有非0的部分一個一個存起來的方法，\n在這裡就完全行不通了。\n直覺上或許讀者會想到諸如以下的方法：\n從頭開始找到第一個0元素(位置假設為a) 找到從這個0元素以後第一個非0的元素 將兩者交換 從a+1開始找到下一個0元素 再找到從這個0元素以後第一個非0的元素 按照這樣的邏輯直到沒有更多的0元素，或找到0元素以後，\n其後沒有非0的元素為止。\n(上面的方法沒有很嚴謹，因為1有可能就已經找不到0元素了，\n僅為大概的範例) 但這樣的方法對每一個0元素都有可能需要掃瞄過一整個陣列，\n總體的時間複雜度會來到O(N^2)。\n有更好的方法嗎？\n我們可以先考慮：\n如果我們將原先的陣列當成額外開的ArrayList或List來使用的話呢？\n先將所有的非0值從index 0開始放入，直到沒有非0的元素為止，\n接著，和開新的空間不同，後面多出來的部分相當於被排開的0 ，\n所以我們要將後面的值全部設為0 。\n這麼做只需要記錄當前非0的部分放到哪邊，在其後再進行補0的動作即可，\n最極端的狀況是全部都是0(即完全不用更動陣列)，\n以及全部都非0(即將原本的位置複寫相同的數字一次)；\n一旦中間有出現0的狀況，只代表其後的數字被往前挪一格，\n讀者可以紙筆稍加操作看看即可確認不會有非0的數字會被吃掉XD~\n我們使用了index來記錄下一個即將被寫入非0數字的位置，\n遍歷整個陣列/串列，當元素非0時，則將其寫入index的位置，\n並遞增index，其程式碼如下所示。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1)，因為最多只須掃過陣列兩次即可)\n「如果不要求順序保持相同的話呢？」\n(使用two pointer的方式，i由頭至尾，j由尾至頭，\n分別找到0和非0的元素進行交換，直到彼此交會即可。\n時間/空間複雜度相同但可預期因只須掃過一次陣列，有機會較快)\n「如果不要求要in-place呢？」\n(以python為例: res=[x for x in nums if x != 0]\nres += (len(nums)- len(res))*[0]\n(後面再接上對應個數的0即可)\n(時間/空間複雜度O(N),O(N))\n所以，有些題目簡單歸簡單，看到的時候，還是請留心限制條件，\n它有可能跟你熟悉的題目有些出入！有時候一旦限制條件不同，\n可以用的手段和時間/空間複雜度可能就會完全不同了！\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-06T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-25-array-3/","title":"從LeetCode學演算法 - 25 Array (3)"},{"content":"0063. Unique Paths II (Medium)\nQuestion A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).\nThe robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).\nNow consider if some obstacles are added to the grids. How many unique paths would there be?\nAn obstacle and empty space is marked as 1 and 0 respectively in the grid.\nNote: m and n will be at most 100.\nExample 1 1 2 3 4 5 6 7 8 9 10 11 12 Input: [ [0,0,0], [0,1,0], [0,0,0] ] Output: 2 Explanation: There is one obstacle in the middle of the 3x3 grid above. There are two ways to reach the bottom-right corner: 1. Right -\u0026gt; Right -\u0026gt; Down -\u0026gt; Down 2. Down -\u0026gt; Down -\u0026gt; Right -\u0026gt; Right 分析/解題 這題基本上就是前面Unique Paths I的續集，在棋盤上存在障礙物。\n如果我們考慮某個點是障礙物的話，其造成的影響會是什麼呢？\n建議讀者可以自行畫幾條路徑試試看，這個狀況下，\n會造成的結果為：\n能到達該點的方法數為0(已經是障礙物了) 承1，因此對1個點來說，\n加總的方式應該是先看這個點是否是障礙物 ，\n不是的話，才需要考慮它左邊 和上面 是否有可以到達的方法數。 我們最開始先檢查輸入的方格是否正常，且第一個如果被擋的話，\n代表完全走不出去，直接回傳0即可。扣除掉這個狀況的話，\n接著從原點開始的方法數就是1 。接下來便可由此開始進行dp。\n先定義好儲存path的二維陣列並將1放到原點，\n依序對每個方格檢查，只要確定它不是障礙物，\n就依照判斷將該加上去的部分加上去。\n(加到左邊或上面是障礙物的點沒關係，因為它已經是0了)\n全部遍歷過一次以後，回傳右下角的值即可。\nJava Python的部分要特別留意二維列表的生成，\n請勿使用[[0]*n]*m，這樣在第二層會產生m個指向相同位址的列表 。\n(第一層不會，因為0的部分還是基本型態而非物件)\n(也就是動其中一個row會同步改到其他的row)\n我們可以使用二層的List Comprehension來處理，或者第一層用*，\n第二層用List Comprehension亦可，這裡示範後者。\n(實測上兩者速度並無明顯差異 )\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(m*n), O(m*n)，因我們會遍歷整個二維列表，\n且需要另一個二維列表來儲存中間的方法數)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-05T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-24-dynamic-programming-4/","title":"從LeetCode學演算法 - 24 Dynamic Programming (4)"},{"content":"0229. Majority Element II (Medium)\nQuestion Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.\nNote: The algorithm should run in linear time and in O(1) space.\nExample 1 1 2 Input: [3,2,3] Output: [3] Example 2 1 2 Input: [1,1,1,3,3,2,2,2] Output: [1,2] 分析/解題 跟上一篇相似，這篇將出現超過二分之一改變為三分之一，\n要求求所有出現超過三分之一次數的數值，\n這使得可能超過三分之一的種類會變成2種，但並不保證一定會有2種。\n按照上一篇的摩爾投票算法的思路，\n我們可以取2個數(n1, n2)暫存，\n每次拿一個新的來檢驗並處理每三個相消的動作，\n這樣我們即可以保證留下來的會有當中超過三分之一的元素。\n要特別留意的是，兩個數有可能會是一致的，\n且不一定每次都存在2種超過三分之一的元素，\n所以最後我們要個別重新確認留在n1及n2上的元素，\n其個數是否有超過三分之一。\nJava Python的部分，我們這邊除了同於Java的解法以外，\n再提供一個簡單的作法：使用Counter。\n利用Counter可以將一個列表轉換成Counter物件，\n儲存的方式是(key:元素 及 value: 該元素出現的次數)\n在迴圈中的取用基本上跟字典類似。\n只要檢查每個元素出現次數是否大於三分之一的數量即可加至結果。\n(請留意如果認真按照題目要求的話，\n這個解法因為會佔用額外O(n) 空間，\n故不是一個在O(1)空間內可以完成的算法。)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n), O(1)。\n要經過整個陣列兩次，且額外並沒有需求常數次數以外的空間)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-08-03T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-23-array-2/","title":"從LeetCode學演算法 - 23 Array (2)"},{"content":"0169. Majority Element (Easy)\nQuestion Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.\nYou may assume that the array is non-empty and the majority element always exists in the array.\nExample 1 1 2 Input: [3,2,3] Output: 3 Example 2 1 2 Input: [2,2,1,1,1,2,2] Output: 2 分析/解題 嗨，大家今天過得好嗎？歡迎回到軟工宅宅(誤)。\n接下來的幾題我們會著墨一下有關陣列(Array)或列表(List)相關的內容。\n題目給定了一個長度為n的陣列，\n已知當中有一個majority element(佔大多數的元素)，\n這個數的個數會多過於⌊ n/2 ⌋。\n(此符號代表向下取整數，如⌊ 5/2 ⌋=2。\n別忘了是more than，所以如果n是5的話，\n代表majority element至少要有3個)\n題目還貼心地告訴我們，可以假定陣列不是空的，\n且一定存在majority element，所以這邊可以省掉一些常用的檢查。\n怎麼解這題呢？\n一般來說的直覺可能會想使用HashMap來解(Python則用dict)，\n將每個數塞入HashMap/字典中，最後找最大的那個數就是了。\n這麼做的時間複雜度為O(n)，空間複雜度亦為O(n)，\n因為插入耗費的時間為O(1)，插入n個數即為O(n)，\n同時，我們只能保證最多有n - ⌊ n/2 ⌋的不同種類的數，\n所以空間上還是保持在O(n)的複雜度。\n在中途過程中在去檢驗是否有超過半數的element也可以，\n但由於過程不保證會先碰到超過半數，所以額外檢驗的時間，\n和省下來後面可能不用做完的時間相比，是不能肯定誰效率比較好的。\n那麼，有沒有比較節省空間的做法呢？\n有的！這裡介紹一個演算法，全名叫做：\nBoyer–Moore majority vote algorithm(摩爾投票算法)\n這個算法的核心在於，\n刪去一個數列中的兩個不同的數字，不會影響該數列的majority element。\n假想有一群人要投票，候選人有A、B、C，假設A已知會過半數的話，\n任取其中2個人取消他們的投票資格，會有以下的狀況：\n被取消資格的是B跟C -\u0026gt; 顯然A還是過半數(而且比例更高了XD) 被取消資格的是(A, B)或(A, C) -\u0026gt; 一個投A的和一個不投A的同步被排除，所以無法改變A會過半數的狀況。 同理，在不只3個候選人(數字)的時候，每次取2個人取消投票資格(移除)，亦無法改變投票結果(A還是會是majority element)。\n註：\n所以我們可以知道，當你跟你的家人政治立場不同時，\n只有兩個人的狀況下都不去投票是沒有用的，\n有用的方式是在投票前夕帶著跟你立場相反的家人們出國去玩 ，\n多於1人時，每多一個人你就多賺一張選票差距 ，但你的荷包可能會哭。\n(不要說是我教的！)\n依此，我們可以使用下列的方式來進行陣列運算：\n取出第一個數放到一個暫存的變數(res)，\n將計數器(cnt)設定為1，代表這個數出現1次。 取出下一個數nums[i]，如果和res相等，則將計數器+1；\n如果和res不同，且計數器\u0026gt;0時，將計數器-1；(代表取這兩個數成對移除)\n如果和res不同但是計數器=0時，將res更改為nums[i]並將計數器+1(代表res已經用完了，現在還沒被移除的是nums[i]) 反覆進行步驟2直到陣列結尾，剩下的res即為答案。\n(因為兩兩移除到最後一定是非majority element的先被移光) Java 還有另一種作法，是將陣列進行排序，\n無論如何majority element一定會通過中間的位置。\n這種方式的時間複雜度為O(nlogn)，空間複雜度視你的呼叫方式而定，\n可能是O(1)也可能是O(n)(將排序的結果放到別的地方的話)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(n), O(1)，除了一些變數以外我們沒有使用到額外的空間)\n「各方法的優劣為何？」\n(可以參照Solution的頁面，這篇作者分析的內容很完整)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-31T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-22-array-1/","title":"從LeetCode學演算法 - 22 Array (1)"},{"content":"0062. Unique Paths (Medium)\nQuestion A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).\nThe robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).\nHow many possible unique paths are there?\nAbove is a 7 x 3 grid. How many possible unique paths are there?\nNote: m and n will be at most 100.\nExample 1 1 2 3 4 5 6 7 Input: m = 3, n = 2 Output: 3 Explanation: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner: 1. Right -\u0026gt; Right -\u0026gt; Down 2. Right -\u0026gt; Down -\u0026gt; Right 3. Down -\u0026gt; Right -\u0026gt; Right Example 2 1 2 Input: m = 7, n = 3 Output: 28 分析/解題 有一個m x n大小的格子，其左上處有一台機器人，每次機器人僅能選擇往右或往下走，目的是要達到右下角的Finish的位置，題目問說當給定m和n時，有多少種不同的方法可以從左上走到右下？\n這題也是典型的動態規劃題目，只要稍稍思考一下，\n我們就能發現一件事情：\n走到任何一個點的方式，取決於走到其左的方法數 加上走到其上的方法數 。\n那麼，再思考一下走到左邊跟走到上面會有重複的狀況嗎？顯然是不會的。\n因為走到一個格子的左邊顯然和走到其上面會相差往下走一格及往右走一格的動作，而且因為機器人也只能往下或往右，所以沒辦法再回頭，故已經走過的部分不可能再繞得回來。\n在這個狀況的特例有幾個：\n機器人所站的原點 (按我們的定義一開始就在此，故可以將方法數定為1) 最左邊 的一排格子 (僅取決於走到其上面格子的方法數) 最上面 的一排格子 (僅取決於走到其左邊格子的方法數) 而實際上從第1點來推算的話，\n我們可以知道最左邊一排跟最上面到達的方法數都會是1 。\n所以我們可以先將這三點的部分先設定為1，接著從較小的index開始沿途把到達每個點的方法算出來，直到最後將整個grid算完。\n在這個方法下，我們需要一個m x n的陣列用以儲存方法數，為了方便起見，我們就直接叫它dp，讀者亦可命名為grid，請留意這些命名都只是方便起見，只要你的命名能和面試官溝通即可，我們現在並不是在寫一個大的project，簡短命名並告知你的面試官你的目的是筆者推薦的做法。\n最後僅需回傳dp[m-1][n-1]即可。\n(註:由於這邊row跟column的交換並不影響結果，\n故我們這邊不特別去在意m和n的前後順序。)\nJava Python這邊收尾的時候可以用dp[-1][-1]來表示尾端的元素，\n宣告的時候則採用list comprehension(列表解析式/列表表達式)。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(均為O(m*n))\n「空間複雜度是否可以降低？」\n(理論上可以，因為實際每次處理的關連部分僅有兩行或兩列，\n反覆利用應該可以讓空間需求降低到O(m)或O(n)，但時間複雜度一致)\n「是否有更簡單的解？」\n(DP的話，沒有，數學的話，有。\n假設往下叫D，往右叫R，求不同走法的過程，\n即相當於在求**(n-1)個D和(m-1)個R的不同排列方法** ，\n故答案會是(m-1+n-1)!/(m-1)!(n-1)!，\n此時空間複雜度為O(1)，時間複雜度為O(m+n) 。\n但階乘的部分當值過大時有可能會有超過int的可能性。)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-29T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-21-dynamic-programming-3/","title":"從LeetCode學演算法 - 21 Dynamic Programming (3)"},{"content":"0110. Balanced Binary Tree (Easy)\nQuestion Given a binary tree, determine if it is height-balanced.\nFor this problem, a height-balanced binary tree is defined as:\na binary tree in which the depth of the two subtrees of every node never differ by more than 1.\nExample 1 Given the following tree [3,9,20,null,null,15,7]:\n1 2 3 4 5 3 / \\ 9 20 / \\ 15 7 Return true.\nExample 2 Given the following tree [1,2,2,3,3,null,null,4,4]:\n1 2 3 4 5 6 7 1 / \\ 2 2 / \\ 3 3 / \\ 4 4 Return false.\n分析/解題 題目給定一個二元樹，試檢查其是否為高度平衡的狀態。\n前面已經提到過很多次，若是一棵樹長得不夠平均(例如都長在同一邊)，那麼在進行一些操作的時候會相當耗時間，\n這也是為什麼我們會在意一棵樹高度是否平衡的原因。\n而題目給的條件其實以更常見的定義來說，會定義成如下所述。\n假如底下3點成立，一棵非空的二元樹就被稱作是平衡的：\n二元樹的左子樹是平衡的 二元樹的右子樹是平衡的 二元樹的左右子樹高的差不大於1 對於一個樹的高度(或稱作深度)，\n是指從樹的根節點走到葉節點的最大長度，所以基於這點，我們的流程應該是從根節點往下，檢查以每個節點為基準的左右子樹高的差均不大於1，該二元樹即為平衡的，反之則為不平衡。 依此，我們會需要知道除了根以外，每個節點的深度，\n故可以簡單利用遞迴來操作：\n先試寫看看maxdp這個函式的虛擬碼(假設你要求root這個node的深度)：\n1 2 3 4 5 6 maxdp(root) { if root == NIL return 0 l = maxdp(root.left) r = maxdp(root.right) return max(l, r) + 1 } 當我們要求某個節點的深度時，\n就相當於求其左右兩邊子樹深度的較大值+1 。\n(+1是因為經過了自己這個節點)\n回到我們原本的問題，我們想要求左右子樹的深度差不能大於1的話，只需要在maxdp函式中增加去判斷左右深度差即可。\n我們同時可以使用一個變數res來記錄是否已經發生不平衡的情況，\n一旦發生，其實可以不用繼續往下做。\n1 2 3 4 5 6 7 8 9 10 11 let res = true maxdp(root) { if (root == NIL or !res) return 0 l = maxdp(root.left) r = maxdp(root.right) if (abs(l-r) \u0026gt; 1) { res = false return 0 } return max(l, r) + 1 } 在一開始的解答的isBalanced函式中呼叫maxdp，\n最後將res回傳即可得到答案。\nJava Python這邊展示了一個再進一步的思路：\n如果我們已經發現不平衡的狀況，可以使用-1做為代表，因為深度只可能大於或等於0，那麼，只要每次檢查是否出現-1，就不用使用額外的res變數來儲存結果，我們只需要檢查回傳是否為-1就可以判定二元樹是不是平衡了！\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(最差狀況是樹很平衡，每一層都要檢查，時間複雜度是O(N)\n自行宣告的額外空間是O(1)，但遞迴中需有Call Stack，\n最糟的狀況也是O(N)(全擠在同一邊))\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-27T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-20-tree-6/","title":"從LeetCode學演算法 -  20 Tree (6)"},{"content":"0111. Minimum Depth of Binary Tree (Easy)\nQuestion Given a binary tree, find its minimum depth.\nThe minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.\nNote: A leaf is a node with no children.\nExample:\nGiven binary tree [3,9,20,null,null,15,7],\n1 2 3 4 5 3 / \\ 9 20 / \\ 15 7 return its minimum depth = 2.\n分析/解題 題目給定一個二元樹，要求找到最小的深度，也就是從根節點到最近的葉節點的路徑長。(葉 節點是指它底下沒有其他小孩 了)\n上一題我們講解了一題Hard的題目，讓我們稍微喘口氣，\n來看個這個比較基本的題目吧！\n這題概念並不複雜，只要稍微弄明白要被遞迴的主體即可。\n對一個節點來說，我們已經知道所謂的深度就是從根走到這個節點的長度 。\n既然我們要求最小的路徑長度，可以選擇的方式就是分別看兩邊有多深，\n最後選擇較小的那邊 ，加上1即可。(因為從根走到根的左/右節點要計算到)\n那麼，左右各自有多深同樣也要取最小的路徑，\n故一樣使用相同的方法再往下遞迴。\n依此嘗試寫成遞迴的虛擬碼：\n1 2 3 4 5 6 7 8 9 minDepth(root) { if root == NIL return 0 l = minDepth(root.left) r = minDepth(root.right) if l == 0 or r == 0 return l + r + 1 // 等同於取非NIL那條的路徑或取1(當左右都是NIL) else return min(l, r) + 1 // 左右都有時取較小的路徑 } 再化成程式碼如下：\nJava Python的部分使用判斷是否是None來處理，\n本質上是一樣的，讀者可依個人喜好來選用寫法。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(由於必須遍歷所有節點，時間複雜度為O(N)，空間複雜度則依照stack深度而定，最糟的狀況也是O(N)，最好的狀況則是O(logN))\n「可以用迭代解嗎？」\n可以，但比較難想，有興趣的讀者可以嘗試使用我們還沒有仔細講過的level-order traversal 來解此題，大致的思路是使用Queue來保存相同深度的所有節點 ，並且用另一個Queue和level進行記錄，一旦在某次出現了node.left和node.right均為NIL 的狀況，代表在這層就遇到葉子 ，那麼就可以回傳level即為解答 。\n這麼做的時間複雜度和空間複雜度均和最小深度 有關，若最小深度為D，\n時間空間複雜度均為O(2^D)，雖然看起來比較可怕，\n但其實最糟的狀況是這棵二元樹是平衡的，這時2^D-1 = N；\n而其他狀況下複雜度肯定小於O(N)。\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-25T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-19-tree-5/","title":"從LeetCode學演算法 - 19 Tree (5)"},{"content":"0124. Binary Tree Maximum Path Sum (Hard)\nQuestion Given a non-empty binary tree, find the maximum path sum.\nFor this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along with the parent-child connections. The path must contain at least one node and does not need to go through the root.\nExample 1 1 Input: [1,2,3] 1 2 3 1 / \\ 2 3 1 Output: 6 Example 2 1 Input: [-10,9,20,null,null,15,7] 1 2 3 4 5 -10 / \\ 9 20 / \\ 15 7 1 Output: 42 分析/解題 題目給定一個二元樹，試求其上最大的路徑和的值。\n所謂路徑，就是在二元樹上任意挑兩個節點，從一個節點走到另一個節點，包含它們自己，所經過的所有節點值的和。\n最小的條件是兩個節點相同，這時候的路徑長等同於這個節點的值。\n嫌前面太簡單了嗎？別急，Hard等級的題目這不就來了嗎XD\n在講解以前，建議讀者先思考一下有沒有任何頭緒並寫下來，再接著往下面看分析，相信會有比較好的收穫。\n3~\n2~\n1~\n開始囉！\n如果我們多拿幾組節點來進行觀察，會發現從一個節點要走到另一個節點，要先經過它們最低的共同祖先節點(這邊指從雙方往上走第一個碰頭的位置)，再走下來才行。\n以Example 1來說，2和3的最低共同祖先是1，\n以Example 2來說，15和7的最低共同祖先是20。\n那麼，我們怎麼決定兩個節點的路徑長呢？\n假設我們知道AB兩個節點的話，它們一定會有一個最低的共同祖先節點，\n當中可能是A或B自身，也可能是其他節點 (如前面的範例就都是其他節點，而如果取的是-10跟15的話那最低的共同祖先節點就是-10)，\n所以每個節點都可以有做為節點的最低共同祖先節點的可能 。\n我們姑且將最低共同祖先節點叫做中繼點好了，比較方便XD\n接著，將不含中繼點的左邊的最大路徑和叫做l，右邊的最大路徑和叫做r，對於某個中繼點(node n)而言：\n通過中繼點n的最大路徑和 = max(n.val, n.val + l, n.val + r, n.val + l + r)\n(因為l或r都有可能是負的，所以要把這四種都考慮在內)\n接著我們要考慮的是，如果中繼點是別的點而不是現在這個點 ，\n我們只是經過 它但想知道包含這個點往下走最大路徑和 是多少的話，\n那我們只能去考慮n.val/n.val+l/n.val+r 這三種狀況。\n(因為n.val+l+r代表這個點是做為中繼點才會有分支)\n所以我們可以嘗試用遞迴的方式解題，從root開始往下走到每個節點，計算該節點往下走的最大路徑和 ，並且每經過一個節點就考慮看看這個節點是中繼點的狀況，一旦發現最大值比現有記錄的大，就更新成新的最大值 。\n由於用來遞迴的函式是一路優先往下一層節點進入(一直到最底下才能回頭依序得到各自的l跟r)，這種優先往深的方向走的方式我們一般稱為深度優先搜尋 (DFS, Depth-First Search)。\n寫成虛擬碼如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 define res maxPathSum(root){ res = root.val dfs(root) return res } dfs(n){ l = (n.left != NIL) ? dfs(n.left) : 0 r = (n.right != NIL) ? dfs(n.right) : 0 m = n.val m = max(m, l + m, r + m) // 單做為經過點的最大路徑和 res = max(res, m, l + r + n.val) // m已比過3種可能，故只需再考慮中繼點 return m } 在這個虛擬碼當中，我們先考慮左右是否還有連接節點 ，有的話就進行dfs往下找出經過點 的最大路徑和，沒有的話則補上0 ；接著先考慮m的部分，再利用已經比過大小的m來和作為中繼點的狀況比較，最後和當前最大路徑和相比並更新結果，完整走完所有流程即可得到回傳的答案。\nJava的部分，這邊使用了if來作比較，實測上和一組一組依序使用Math.max來相比並沒有明顯速度上的區別，讀者可依自己喜好使用。\nJava Python的部分，留意呼叫時加上的self.即可，\n且max可適用於多個傳入值，比起Java會再方便一點。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(每個節點均會走過一遍，故時間複雜度為O(N)\n除了res, l, r, m以外沒有額外的空間了，自行宣告的空間複雜度為O(1)，\n但進入遞迴會用到Stack，最大應該是這棵二元樹的高度 ，\n也就是最糟的狀況下可以到O(N)，最好的狀況則是O(logN))\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-23T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-18-tree-4/","title":"從LeetCode學演算法 -  18 Tree (4)"},{"content":"0094. Binary Tree Inorder Traversal (Medium)\nQuestion Given a binary tree, return the inorder traversal of its nodes’ values.\nExample:\n1 2 3 4 5 6 Input: [1,null,2,3] 1 \\ 2 / 3 1 Output: [1,3,2] Follow up: Recursive solution is trivial, could you do it iteratively?\n分析/解題 給定一個二元樹，題目要求以inorder(中序)方式回傳其節點值。\n由於上一題的關係(讀者可以回頭參照第16篇)，我們已經講解過In-order的方式了，原則上就是經過左邊的部分-\u0026gt;中間的部分-\u0026gt;右邊的部分 的順序。\n請留意這題輸出並不一定會由小到大(因為並沒有限制是二元搜尋樹)。\n我們先來嘗試遞迴解法，通常較為簡單，這邊重新列出上一篇提到的：\n1 2 3 4 5 6 inorder(root) { if root == NIL return inorder(root.left) print(root.val) // Or add/append to the list inorder(root.right) } 若讀者感到不太能夠掌握這個流程的運作，可回頭參考第16篇的gif動畫。\n總體而言，每次我們都會走到當前所能走到的左邊 ，直到左邊再也沒有node(變成NIL )時，會回到上一層 (return)，印出值 (或將其放到list中)，接著再往自身的右邊找 ；每次同樣的模式操作完以後，我們可以保證對於每個子樹，都是先拿到其左邊的節點值(們)，再來是自身，最後才是右邊的節點值(們)，從而保證這個演算法是得以遵照目標的順序完成的。\n由於我們會使用一個ArrayList或List來存放inorder得到的值，所以下面是採用先宣告再將其放置到另一個遞迴用函式中處理的方式。當然，如讀者只想使用一個函式來遞迴，也可以宣告一個Solution的class變數，這樣就不需要每次傳遞了。兩者各有好處，讀者可依自己喜好決定。\nJava Python 那麼，如果是要求要迭代解(iterative solution)呢？\n我們回顧一下前面的作法，遞迴的時候之所以我們能回到上一層，其實是因為我們的程式有記錄上一層的函式的執行狀態，從而在return時能返回到應該繼續的那一行執行。由於最後一層函式在返回時必須先被呼叫到 ，所以電腦在儲存時是採用Stack 的形式(因為要後進先出)。(這個堆疊又叫做The Stack或Call stack(呼叫堆疊))\n因此，我們想要能夠不用遞迴解的話，\n顯然我們應該要自己使用一個Stack來處理整個流程。\n在In-order的流程中，首先我們是先一路走到最左邊的node，\n中途經過的node我們應該要將其放進Stack中，這樣才能回到上一層去，\n我們將這個node暫時命名為curr(current)。 curr一路向左最終一定會遇到NIL，表示這排從root一路向左邊走，\n沿途的node全數放入到Stack中了。 那麼我們應該要將最後一個node從Stack中拿出來(因為後進先出，最後一個node應該是最左邊的node才對)，將其放到list當中。 接著將curr設為自己右邊的node。 反覆上面的流程，一直到curr和stack都空掉為止。 寫成虛擬碼如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 create a list named res create a stack named stack curr = root while ( curr != NIL or !stack.isEmpty() ) { while (curr != NIL) { stack.push(curr) curr = curr.left } curr = stack.pop() res.add(curr.val) curr = curr.right } return res Java Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n（O(N), O(N)，因為要走訪過整棵樹，且list要儲存整個二元樹攤平的結果）\n「如果我將res放在class Solution的level有什麼優缺點？」\n(優點：\n有機會速度快一點點，且通常不用傳位址給函式，因為直接能存取到。\n缺點：\n對整個class均為可見，如果這個函式是要被反複使用的話，\n要注意初始化的問題，且也有可能被其他函式修改到。)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-22T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-17-tree-3/","title":"從LeetCode學演算法 - 17 Tree (3)"},{"content":"0098. Validate Binary Search Tree (Medium)\nQuestion Given a binary tree, determine if it is a valid binary search tree (BST).\nAssume a BST is defined as follows:\nThe left subtree of a node contains only nodes with keys less than the node’s key. The right subtree of a node contains only nodes with keys greater than the node’s key. Both the left and right subtrees must also be binary search trees. Example 1 1 2 3 2 / \\ 1 3 1 2 Input: [2,1,3] Output: true Example 2 1 2 3 4 5 5 / \\ 1 4 / \\ 3 6 1 2 3 Input: [5,1,4,null,null,3,6] Output: false Explanation: The root node\u0026#39;s value is 5 but its right child\u0026#39;s value is 4. 分析/解題 題目給定一個二元樹，檢查它是否是二元搜尋樹(Binary Search Tree)。\n終於我們來到二元樹的進階版了！\n二元搜尋樹如同題目說明，要符合以下三個特性：\n任一個節點的左子樹的所有節點值 均小於 該節點自身的值 任一個節點的右子樹的所有節點值 均大於 該節點自身的值 二元搜尋樹的左子樹 和右子樹 也都是二元搜尋樹 直觀來說，當我們從某個節點開始往左邊走的時候，一定要比自己小；\n反之往右邊走的時候，要比自己大。也因為這個特性，當這棵樹足夠平衡時(節點分布的很均勻時)，會相當有利於搜尋值，因為每次都幾乎可以排除掉一半的可能性 。\nBinary Serach Tree (Balanced, Complete, Perfect)\n以下面的圖來說，我們想要從一個有15個節點的二元搜尋樹找到58這個值，\n就要從根節點開始，每次比較大小，若58比較大就往右邊走，比較小就往左邊走，直到找到剛好的值，或是碰到NIL(沒有別的節點可以搜尋)為止 。\n可以看到圖中由於深度一樣 的關係，不論搜尋什麼值，我們可以預期最多就只需要4次 的比對就可以找出任意一個值是否在這棵樹裡面；每次刪去一半的可能性 ，所以如果總節點有N個的話，搜尋的複雜度最高即為O(logN) 。\n(記得我們提過二元樹不一定非得要全部都有連接節點，這個結果是建立在這棵二元搜尋樹是平衡(balanced) 的狀況，如果這棵樹全部都改成只有左邊的節點的話，結果可是會變成O(N)的！)\nBinary Search for value 58\n我們同樣以上面這棵樹為例，\n如果我們想知道它從小到大的節點怎麼排序呢？\n這裡就需要使用到In-order Traversal了。\nIn-order的順序為左-中-右，代表每次我們目標要先拿到左邊的值，接著是中間，最後才是右邊的值；我們最後希望拿到的是[18, 20, 22, 33, 36, 37, 38, 43, 52, 54, 58, 61, 63, 66, 68]的話，我們要先一路走到最左邊 的節點，代表左邊沒有更小的值 了，才能將其印出來(18)，接著第二小的值則是最左邊節點的父節點(20)，而對33來說，還有20的右節點22比它還要小，最後以此類推，每次找到下一個最小值。\n寫成虛擬碼如下：\n1 2 3 4 5 6 inorder(root) { if root == NIL return inorder(root.left) print(root.val) inorder(root.right) } 讀者可以嘗試使用上面的遞迴的方式走過一遍，或者參照下面的示意圖，\n相信會較為理解這整個流程。留意上面由於當發現NIL的時候就直接return回到了遞迴的上一層，所以就會造成類似往上走一層 的效果。\nIn-order Traversal\n回到我們的題目，我們已經知道在In-order的狀況下，對於二元搜尋樹可以得到一個由小到大的順序，所以只要記住上一個節點，每次去比較上一個節點和現在走到的節點，當現在的節點跟上一個節點相比較小或相等時，表示這不是二元搜尋樹(因為越後面的節點必須較大才行)；反之，當每個節點都走完沒有錯誤時，這時候就可以確認這個二元樹是二元搜尋樹了。\n寫成虛擬碼如下：\n1 2 3 4 5 6 7 8 let last = NIL isValidBST(root) { if root == NIL return true if !isValidBST(root.left) return false if last != NIL and root.val \u0026lt;= last.val return false last = root // 更新上一個節點的位置 return isValidBST(root.right) } Java的寫法部分，我們可以宣告一個class的變數last，\n用來存放上一個走到的節點(放在函式內部的話會被洗掉)\nJava Python的部分，請留意到記得在呼叫時使用self的關鍵字，\n否則可能會無法在isValidBST中取得last。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n（O(N), O(1)，因為要走過整個BST，\n但除了幾個變數外，不需額外的資料結構）\n「可否不用遞迴呢？」\n(可以，使用Stack，可以用迴圈讓每次先將root塞入，一路向左邊走將每個左節點放入Stack中，接下來同樣每次取出一個節點，判斷和前一個的大小比較。最後每個左側處理完以後，再將位置移向右節點，迴圈重複即可。)\n「可以不用class的變數來解此題嗎？」\n(可以，有一種解法是記錄對某個節點的最小值和最大值限制 ，將遞迴函式增加為傳入root, min, max 並隨著每次看到的節點更新 其底下的限制條件，這樣就不需要按照in-order的方式移動，也不需要class的變數。Java的解法這邊收錄 ryanswizzle在Leetcode的解法如下。)\n1 2 3 4 5 6 7 8 9 10 11 12 13 public class Solution { public boolean isValidBST(TreeNode root) { return isValid(root, null, null); } public boolean isValid(TreeNode root, Integer min, Integer max) { if(root == null) return true; if(min != null \u0026amp;\u0026amp; root.val \u0026lt;= min) return false; if(max != null \u0026amp;\u0026amp; root.val \u0026gt;= max) return false; return isValid(root.left, min, root.val) \u0026amp;\u0026amp; isValid(root.right, root.val, max); } } 從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-21T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-16-bst-1/","title":"從LeetCode學演算法 - 16 BST (1)"},{"content":"0136. Single Number (Easy)\nQuestion Given a non-empty array of integers, every element appears twice except for one. Find that single one.\nNote:\nYour algorithm should have a linear runtime complexity. Could you implement it without using extra memory?\nExample 1 1 2 Input: [2,2,1] Output: 1 Example 2 1 2 Input: [4,1,2,1,2] Output: 4 分析/解題 給定一個非空的整數陣列，當中每個元素都出現兩次，只有一個出現一次而已，題目要求找出那個單獨的數字。\n在進一步往BST之前，先來一個簡單但一般不會想到的問題。\n這題如果我們以暴力法來解的話，假設不用任何額外的資料結構，我們可以每拿一個數字就對整個陣列做比較，直到找到沒有重複的數字為止。但這樣除了時間複雜度會是O(N)以外(對單一數字，所以每個數字都做完就是O(N^2))，最後會發現有可能會有拿到先前拿過一次的數字，所以顯然是不太行的。\n那輔以資料結構呢？\n比較常用的方法是使用HashMap(Python則用dict)，為每個數字計數，計數完以後就掃過整個對應，看誰只有被數到一次，就是我們要的答案了。\n這個方法要先走訪過一遍陣列，再走訪一遍HashMap或dict，時間/空間複雜度均為O(N)，但還是稍嫌慢了一些。\n那有沒有更厲害的解法呢？有！\n要了解這個解法怎麼操作，首先我們需要複習一下Bitwise Operation。\n當中的XOR的內容是：將兩個數的每個位元兩兩相對，一個0一個1的時候，結果會是1，否則結果會是0 。\n這可以讓數字運算得到一些神奇的特性，第一個特性是：\n1 a XOR a = 0 我們拿11=1011(二進位)來試試看：\n1 2 3 11 = 1011 11 = 1011 11 XOR 11 = 0000 = 0 因為每一位數都相同，XOR後每一位就都會是0。\n第二個特性是：\n1 0 XOR a = a, a XOR 0 = a 因為一邊都是0，所以那個位數是0或1，端看原先a的位元。\n再來其他一些重要的特性是：\n1 2 a XOR b = b XOR a (交換律) (因每個位元的結果端看該位元總共有奇數或偶數個1，和順序無關) 1 2 3 (a XOR b) XOR c = a XOR (b XOR c) = a XOR (c XOR b) = a XOR c XOR b (不論哪邊先做，結果都是看有奇數個1-\u0026gt;結果是1，偶數個1-\u0026gt;結果是0) (最前面的部分是標準的結合律) 推而廣之，我們可以得到XOR具有交換律 和結合律 。將它的運算的數字左右調換，或者哪個先做，哪個後做，均不影響結果。\n回到問題來，假設我們目標的答案是r，那麼將陣列中所有的數字XOR起來，會發生什麼事情呢？我們根據前面的已知，將陣列自己調換一下，應該可以變成：\nr XOR a XOR a XOR b XOR b XOR c XOR c ……的形式。\n(因為怎麼換都不應該影響結果)\n於是，陣列全部XOR的結果會等於r XOR 0 XOR 0 XOR…… = r\n(其它的兩兩XOR後會變0)\n也就是說，將每個數都進行XOR後，結果會留存下那個唯一單獨的數字。\n寫成程式碼如下，宣告變數為0後從index 0開始，或直接將陣列的第一個數指派給它並從index 1開始，實測上沒有特別感受到時間差異，讀者依照自己的喜好和習慣嘗試即可。\nJava的部分用了語法蜜糖 ，\nint e:nums代表自nums陣列按順序每次拿一個數並交給e。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(由於只要整個陣列掃過一次就結束了且無須額外的陣列空間，\n時間複雜度為O(N)，空間複雜度則為O(1))\n從LeetCode學演算法，我們下次見囉，掰~\n註：感謝zhoumax的提醒修正一些敘述和筆誤。\n","date":"2019-07-18T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-15-bitwise-operation-2/","title":"從LeetCode學演算法 - 15 Bitwise Operation (2)"},{"content":"0101. Symmetric Tree (Easy)\nQuestion Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).\nFor example, this binary tree [1,2,2,3,4,4,3] is symmetric:\n1 2 3 4 5 1 / \\ 2 2 / \\ / \\ 3 4 4 3 But the following [1,2,2,null,3,null,3] is not:\n1 2 3 4 5 1 / \\ 2 2 \\ \\ 3 3 Note:\nBonus points if you could solve it both recursively and iteratively.\n分析/解題 題目給定一個二元樹，要求檢查是否為左右對稱(Symmetric)。\n繼前一篇的樹的基本以後，今天同樣來談談另一個基本題，幫助大家熟悉以外，也介紹一個資料結構Queue，用來說明我們怎麼來解迭代解的。\n這邊講的左右對稱是指從根節點將左右切開來看，左邊和右邊恰巧要對稱。\n要解決這個問題並不困難，但要留意小細節。\n首先，如果給定的根是NIL(null/None) =\u0026gt; 沒有東西仍然是可以達成左右對稱，所以必須回傳真值 (true/True)。\n扣掉這個狀況，再來觀察上面的圖可以發現，根節點毫不影響，\n接著要比較的應該是左子樹跟右子樹是否對稱。\n和前一題不同，以[1,2,2,3,4,4,3]為例，要符合對稱的條件，\n應該要符合下面三點：\n左子樹根的值=右子樹根的值 左子樹 自己的左子樹 (以本例是最左邊的3)要和右子樹 自己的右子樹 對稱 左子樹 的右子樹 要和右子樹 的左子樹 對稱 請留意1的部分，\n如果兩者均為NIL ，表示下面不用比(空了)且兩者相等 ，\n這時候應該回傳真值 ；而接下來再判斷其一為NIL 的狀況，表示兩者一定不相等(一個有節點一個是NIL )，這個技巧在上一篇同樣有使用到。\n上面都沒成立的話，再判斷兩者值是否相等 。\n所以直觀上我們可以寫出這樣的遞迴模式：\n(註:留意我們這樣寫只是用來表達整個演算的流程，它通常並不能用來在某個語言執行，這樣的用來表達概念的代碼叫作虛擬碼(pseudocode)，虛擬碼通常不用嚴格按照特定規範，目的只是要先將你的流程想法釐清為主。 )\n1 2 3 4 5 6 7 8 9 10 11 isSym(root) { if root == NIL return true return isSymmetric(root.left, root.right) } isSymmetric(l, r) { if l == NIL and r == NIL return true if l == NIL or r == NIL return false if l.val != r.val return false return isSymmetric(l.left, r.right) and isSymmetric(l.right, r.left) } 寫成Java如下，注意我們這邊將isSymmetric函式的前2行合併了，\n使用者也可以依自己習慣決定要不要這麼寫，速度上並不會有明顯差異。\n同時，對Java而言，我們可以定義同名的函式，只要輸入的參數(parameter)型態或數量不同，JVM就可以知道哪一條式子是呼叫哪一個函式才正確。\n這個做法稱為函式多載(Method Overloading) 。\nJava Python並不支援函式多載，所以我們可以定義不同的名字來使用。\n(註: 對於所有程式語言來說，\n代表\u0026quot;且 \u0026ldquo;的操作，只要第一個條件為假 ，後面就不會再進行判斷；\n代表\u0026rdquo;或 \u0026ldquo;的操作，只要第一個條件為真 ，後面也不會再進行判斷。\n這個特性是為了節省時間，因為結果已經確定了 。\n讀者可以留意一下這點，\n避免將一些希望一定要被執行的函式放在判斷條件的第二個以後，\n以免發生預期要做的事情結果沒做的狀況。)\nPython 上面是遞迴的部分，接下來我們改成嘗試來使用迭代法解看看。\n這邊首先要介紹一個資料結構Queue(隊列/佇列)。\n隊列基本上就跟現場排隊名店一樣，扣除掉一些現實中的插隊之類的糟糕狀況外，基本上是先排隊的可以先離開排隊序列而進場，也就是說它的特性是先進先出(FIFO)。 我們將放一個東西到Queue中的操作叫作\u0026rdquo;Offer \u0026ldquo;(提供)，會放到隊列尾端；\n從Queue裡面拿一個東西出來的操作叫作\u0026rdquo;Poll \u0026ldquo;(獲得)，會從隊列頭拿出。\n這樣的特性對於解這題有什麼幫助呢？\n我們可以如下操作：\n首先判斷root的部分，沒有問題的話拿出其左右(l跟r)，放到Queue裡面。 此時Queue裡面有東西，一次拿兩個出來(poll兩次)，判斷l跟r本身\n(如同遞迴時一樣) 接下來我們應該要判斷的是l.left, r.right跟l.right, r.left ，\n所以我們將這四個節點依序offer至Queue中。 重複2~3的動作直到Queue空掉 或當中判斷為假 的狀況即回傳假 。 如果Queue空掉了才離開循環，代表結果為真 ，回傳真 值。 這裡我們利用了Queue的特性，只要依照我們目標的順序將東西放進Queue，我們就可以一直按照正確的方式拿到2個需要被判斷的節點。\n這邊要注意一點，如果兩個節點均為NIL，只代表這個部分往下沒有節點了，不能直接回傳真值 (因為其他部分還沒比較完)，只是我們在這個位置不需要再放節點進到Queue中而已。\n寫成虛擬碼如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 isSymmetric(root) { create a queue named q if root == NIL return true q.offer(root.left) q.offer(root.right) while q is not empty { l = q.poll() r = q.poll() if l == NIL and r == NIL continue if l == NIL or r == NIL return false if l.val != r.val return false q.offer(l.left) q.offer(r.right) q.offer(l.right) q.offer(r.left) } return true } 注意continue 是用來表示這輪的迴圈不再繼續，直接跳到下一輪。\nJava的LinkedList 已經有實作包含Queue的資料結構了，所以我們定義一個Queue時，實際上可以使用LinkedList作為宣告的物件。\nJava Python的部分，由於list的特性和Queue不太一致，\n從開頭取出 這點會讓用list模擬Queue的行為消耗大量的時間。\n針對這點，Python有提供一個deque 的物件可以使用，取出請用popleft() ，放入請用append() 即可。除了像Java這樣子的寫法以外，我們也可以將其使用list的形式每兩個作為一個單位來操作，請參閱下面的程式碼。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(最糟的狀況均為O(N)，因為要查完所有資料有可能要塞完全部的node\n遞迴的狀況如果該樹是平衡的話，空間複雜度可以降到O(logN))\n「可以將左右比較的順序調過來嗎？」\n(只要對應的節點是正確的，先比左邊還是先比右邊並無差異)\n「如果我不想在前面單獨判斷root的話，有可能嗎？」\n(去掉第4行，並將第一次offer的(root.left, root.right)改成(root, root)即可。)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-17T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-14-tree-2-queue-1/","title":"從LeetCode學演算法 - 14 Tree (2) / Queue (1)"},{"content":"0100. Same Tree (Easy)\nQuestion Given two binary trees, write a function to check if they are the same or not.\nTwo binary trees are considered the same if they are structurally identical and the nodes have the same value.\nExample 1 1 2 3 Input: 1 1 / \\ / \\ 2 3 2 3 1 [1,2,3], [1,2,3] 1 Output: true Example 2 1 2 3 Input: 1 1 / \\ 2 2 1 [1,2], [1,null,2] 1 Output: false Example 3 1 2 3 Input: 1 1 / \\ / \\ 2 1 1 2 1 [1,2,1], [1,1,2] 1 Output: false 分析/解題 給定兩個二元樹，試寫出一個函式來檢查二者是否相等。\n(相等的定義是指樹的結構相同，且其相同位置節點的值也相等)\n到了第13篇，終於來到樹的部分了，想當年大學時在演算法的課上被各種資料結構搞得眼花撩亂，當中二元樹/二元搜尋樹真的只能算小兒科XD\n(不信？有心更進階的讀者可以試試看了解一下紅黑樹)\n扯遠了，我們回頭來談樹。\n在程式的領域中，樹是指資料之間以一種長得像樹的方式連結在一起的資料結構(廢話XD)，以外型而言就像樹狀圖 或族譜 那樣子，不過它們有一點比較特別，那就是他們的根通常是畫在上方 ，下面才是支幹。\n如下圖我們所看到的：\n每個圈圈我們稱之為節點(node) 。2.最上面的節點是整棵樹的起始，所以我們就稱之為根(root) 。3. 就如族譜一樣，上面節點是下面直接連接的父母，\n所以我們稱如A是B和C的父節點(parent) (不要問我為什麼不叫母節點XD)，而B和C是A的子節點(child)， 同時B和C是兄弟節點(siblings) 。 任何從自身追尋血脈上去可以到達的節點均為你的祖先(ancestor) 。\n比如A是所有人的祖先，而B不是G的祖先。 From Wikipedia: Tree\n樹本身並沒有規定一個節點要連接多少個節點或總共有多少個節點，\n你可以子孫滿堂開枝散葉，也可以孑然一身孤苦伶仃，只要有一個根在，\n就可以被稱做一棵樹。\n不過這邊要介紹的是二元樹(binary tree) ，就有比較明確的限制了，\n每個節點最多只能有2 個分支。且左右分支是視作不同 的，將它們互相交換的話，前後兩個二元樹會被視為不同的二元樹。由於只有2個分支，所以一個節點的兩個子節點又可以分別被叫做左節點和右節點(left/right node)，\n單就這兩個節點來看，都可以各自視為一個二元樹，\n同樣依照左右被稱作左子樹/右子樹(left/right subtree) 。\n後續還有一個規範更嚴格，也更常被用到的二元樹稱為二元搜尋樹(Binary Search Tree, BST) ，這個我們之後會專門再開一篇講解。上面這些均為樹的相當基本的部分，並不困難，還請詳加閱讀後再往下。\n如同先前提過的linked list一樣，當一個節點它有一邊沒有連接，或者是已經沒有子節點的時候，嚴謹的資料結構會將其連接至NIL (表示什麼都沒有)，而在Java中用null，Python則用None 表示。\n一個Binary Tree, 15的左邊/17, 23, 25的左右其實都是NIL(恩，其實它也是BST)\n回到問題，其實問題的輸入是透過array或list的型式，但這邊LeetCode應該已經妥善處理好建造二元樹的過程了，我們暫且不管它。\n我們如何判斷兩個二元樹是否相等呢？\n由於相等的前提是結構相同且所有對應的節點的值 也相同，我們勢必要一個一個檢查才能知道結果，所以我們必須要走訪整棵樹(Tree Traversal )。\n一個標準的走訪分成四種模式：\n前序、中序、後序以及層序(Pre-order/In-order/Post-order/Level-order) 我們這次只會先從最直覺的前序遍歷開始。\n假設如題目所提，我們有兩棵二元樹，他們的root分別是p跟q，\n那麼檢查它們是否相等的話，我們要做的事情是：\n檢查p和q是否相等 檢查p的左子樹 和q的左子樹 是否相等 檢查p的右子樹 和q的右子樹 是否相等\n唯有這三項均成立，我們才能說p跟q兩棵二元樹相等，否則即為不相等。\n接下來，我們先考慮2和3的部分，\n其實就等同於反複拿更小的子樹去做1~3的動作，\n直到比對的兩邊當中有不同或空掉的狀況。 我們拿下面的圖為例，可以簡單推論出，\n當檢查兩個節點是否相等 的狀況有幾個可確定：\na. 一邊有節點，另一邊沒有節點 =\u0026gt; 結構已經不一樣了，所以兩棵樹不同 。\nb. 兩邊均無節點 =\u0026gt; 結構相同 且沒有子節點，所以這個位置的子樹相同 。\nc. 兩邊都有結點 =\u0026gt; 檢查值是否相同，相同的話，再檢查左右子樹 。\n(也就是回到上一段那邊的2~3)\n所以，我們可以用連續呼叫自己這個解題函式的方式來解決這個問題，\n其演算方式可以大致列成這樣：\n1 2 3 4 5 isSameTree(p, q) { 若p和q均為NIL，回傳真 若p或q為NIL，回傳假(因為表示恰有一個是NIL) 回傳 (p.val==q.val) 且 isSameTree(p.left, q.left) 且 isSameTree(p.right, q.right) } 注意這樣子的比較，我們每次是先比較根節點 ，再比較左節點 的部分，最後才是比較右節點 ，同時，每次呼叫isSameTree時，會一路往左邊先找下去，直到左子樹找完了才會走訪右子樹的部分，所以順序是根-左-右 ，也就是一般所謂的前序遍歷(Pre-order Traversal)。\n這種不斷呼叫自己來求解的方式，我們稱之為遞迴(Recursion，或譯遞歸) ，這樣的解法一般稱為遞迴解(Recursive solution) ，一般來說還會有另一種解法，主要是透過額外的資料結構及迴圈 ，來解決問題，這種方式叫做迭代法/迭代解(Iterative method/Iterative solution) 。比較熟練的讀者若有興趣，可以自行嘗試使用Queue或Deque來解本題看看。\nJava Python的部分，由於NIL是用None來表示，\n所以檢查可以用if not的方法來處理，且not運算的優先層級高於and/or ，\n所以我們不用額外幫它加括號。\nPython 面試實際可能會遇到的問題 「時間複雜度/空間複雜度？」\n(如果答案為真的話，那麼每個節點均會走訪一次，故為O(N) )\n(空間複雜度的話，遞迴同樣會佔用記憶體空間，層數則取決於樹的層數，\n如果是平衡樹(balanced tree)的話，因為分布要平衡(填滿)，\n每層的節點數量會是1, 2, 4, 8, 16, \u0026hellip;, 總和N=2的n次方-1，n為層數。\n所以空間複雜度會是O(logN) ，N為節點的總數。\n最差的狀況下，節點全部連在同一邊，那空間複雜度可以達到O(N)。)\n「可以不用遞迴解嗎？」\n(可以，有興趣的讀者可以嘗試看看，具體方式是使用Queue或Deque，先將兩個根節點放入，接著每次取出一組節點對；先比較節點，再將兩樹其左右node成對地放入裡面 ，重複迴圈，直到有不相等 的狀況產生，或直到Queue/Deque內再無節點 。)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-15T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-13-tree-1/","title":"從LeetCode學演算法  - 13 Tree (1)"},{"content":"0092. Reverse Linked List II (Medium)\nQuestion Reverse a linked list from position m to n. Do it in one-pass.\nNote: 1 ≤ m ≤ n ≤ length of the list.\nExample:\n1 2 Input: 1-\u0026gt;2-\u0026gt;3-\u0026gt;4-\u0026gt;5-\u0026gt;NULL, m = 2, n = 4 Output: 1-\u0026gt;4-\u0026gt;3-\u0026gt;2-\u0026gt;5-\u0026gt;NULL 分析/解題 給定一個linked list，在只經過一次的操作下(每個node不會額外再走訪)，\n題目要求將m到n的位置的節點進行反轉。\n由範例可知這邊的m跟n是以開頭為1而非0來計算，這點讀者請特別留意。\n我們先從理論上來看這題應該怎麼處理：\n首先根據題目要求，m可能和n相等，\n相等的狀況下其實完全不用做事，回傳head即可。\n那麼如果是不相等的狀況呢？\n在Linked List中，要知道某個位置的節點為何，唯有從頭一路走到該節點 。\n我們想要反轉的是mn的位置：\n以範例來說，會將24的位置進行反轉。\n如何反轉呢？首先我們要先走到2的左邊，當我們把中間的部分反轉後，\n我們還要將它們和左右兩邊接起來，要記得2的左邊跟4的右邊的節點才行。\n(不然接不起來就GG了XD)\n這邊將2的左邊命名為left，一路往下走的迭代節點命名為node，\n走到m-1以前先記錄下left節點，再繼續往下走。\n接下來問題來了，如何將2~4的部分反向連接呢？\n你可以選擇一個一個拆解並重新鍵結，\n但這裡筆者想介紹一個常用的資料結構：Stack(堆疊，或稱棧/堆棧)。\nStack的樣子，就跟某些苦命的辦公室人員的書桌一樣：\n你會嘗試將書桌上的文件/工作處理完，但老闆總是會往上面再加新的。 也就是說，每次如果你選擇從最上面開始拿 (別從中間或下面，這麼高的文件可是會塌的！)，你會拿到最新的 工作。\nStack也是如此，假設你將1, 2, 3, 4, 5依序放入Stack中，那麼當你從Stack裡面拿東西的時候，拿出來的順序會是5, 4, 3, 2, 1。最後放進去的會最先被拿出來 ，這樣子的特性我們稱之為Last In First Out(後進先出，簡寫為LIFO)。有另一種資料結構叫Queue(隊列，或稱佇列) 跟它剛好相反，是先進先出 ，我們以後找機會再講解它。\n如果這題應用上Stack的話，就簡單許多：\n我們將2~4的部分通通丟進Stack中，再一個一個拿出來 ，\n這時候順序就會變成4, 3, 2了！那麼，只要將剛剛存好的left，以及後面我們邊走邊看到4的時候，將它的右邊記錄起來的node，兩者再和中間的節點連結起來，就完成整個反轉的流程。\n重新整理解題的順序：\n判斷m是否和n相等，相等則直接回傳原先的head。 定義一個迭代用節點node，先走到m-1的位置以取得節點left。 讓node從m一路走到n，將每個node放入到Stack中。\n(註:放入的術語在堆疊中叫作push) node再額外走一步會走到n+1的位置 依次將Stack中的節點取出，並且依序連接所有節點的next，\n直到Stack中再也沒有節點。\n(註:取出的術語在堆疊中叫做pop) 將反轉完的尾巴和node做連接，結束整個反轉的流程。 這當中還有額外一點需要注意的是m=1 的狀況，\n因為我們最後回傳的是用head 來代表整個linked list，\n如果m為1的話，代表head其實已經被改變了，\n我們需要同步更新head的部分。\n請參照Java的寫法，我們採用了l1和l2兩個節點來處理依序連接的部分。\n我們會先取出堆疊中第一個節點，這個節點會被left連接，\n接下來使用l2 = st.pop(); l1.next=l2; l1 = l2;\n來進行一次取一個node，將前後連接好以後，\n將位置移到下一個準備連接的點。\n也就是說，每次l1所在的位置，都是當前準備進行連接next的節點 。\n(若讀者對這邊的說明感到抽象，請務必在紙上試著操作一下會較清楚)\n在Java中，Stack的宣告方式是：\n1 Stack\u0026lt;\u0026gt; st = new Stack\u0026lt;\u0026gt;(); 請在\u0026quot;\u0026lt;\u0026gt;\u0026ldquo;之中填入你想要使用的資料型態，\n在本例中為題目已經定義的class ListNode。\n函式用法的部分，push()用來放入節點，pop()用來取出節點，\nisEmpty()則是檢查Stack是否是空的。\n(還有一個peek()，是用來看Stack最上面節點，\n但不會真的將節點從Stack中移除)\nJava 在Python中，list的特性可以方便的用來當作Stack使用，\n放入節點可以使用append()，取出節點使用pop()。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(n-m)，因為我們的堆疊最多只需要存中間的部分和兩旁的node)\n「可以只用O(1)的空間嗎？」\n(可以，如果我們按順序一個一個處理m~n之間的連結，\n最後再將n和m和左右兩邊連起來，是可以不使用Stack的\n中間的連接方式會像是：\n1 2 3 4 third = cur.next cur.next = prev prev = cur cur = third 讀者有興趣的話可以嘗試看看。)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-12T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-12-linked-list-3-stack-1/","title":"從LeetCode學演算法 - 12 Linked List (3)/ Stack (1)"},{"content":"0089. Gray Code (Medium)\nQuestion The gray code is a binary numeral system where two successive values differ in only one bit.\nGiven a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.\nExample 1 1 2 3 4 5 6 7 Input: 2 Output: [0,1,3,2] Explanation: 00 - 0 01 - 1 11 - 3 10 - 2 1 2 For a given n, a gray code sequence may not be uniquely defined. For example, [0,2,3,1] is also a valid gray code sequence. 1 2 3 4 00 - 0 10 - 2 11 - 3 01 - 1 Example 2 1 2 3 4 5 Input: 0 Output: [0] Explanation: We define the gray code sequence to begin with 0. A gray code sequence of n has size = 2n, which for n = 0 the size is 20 = 1. Therefore, for n = 0 the gray code sequence is [0]. 分析/解題 格雷碼是一個二進位表示的編碼系統，當中每個連續(相鄰)的二個值之間的表示方式只會相差一個位元(bit)。題目給定n個bits，試求出其表達的格雷碼序列。(格雷碼序列一定是從0開始)\n在這邊簡單講解一下Bitwise Operation。\n(註:本題雖然不會用到太多，\n但熟悉這些操作對於一些題目和實際應用上很有幫助，\n故在此先行列出給讀者學習。)\n先前的文章中已經提到了，電腦對於二進位制的東西操作起來是較為得心應手的，當然我們可以不用像電腦這麼熟悉，但只要會用就可以了XD\n二進位之間的一些操作運算，就像是邏輯學上的運算一樣，\n有AND/OR/NOT/XOR，以及位移運算(bit shifts)等，這些速度在相同狀況下是由CPU進行支援的，運算速度往往會比一般的四則運算還快。\nAND(且):\n邏輯上的AND，代表著前後皆為真的狀況結果才為真，否則為假 ，\n也就是兩者皆成立才行。在位元運算中，1被視為真，0被視為假。\n(所以在如C/C++中你可能會看到使用IF 1或IF 0的開關)\n延伸到多個bit的狀況，就是將前後兩者每個bit兩兩相對，\n當兩者為1時，運算完的那個新的bit為1，否則為0。\n如 110 AND 100的結果會是100(只有最左邊的bit是兩個1)\nJava和Python中的AND運算符號均為\u0026quot;\u0026amp;\u0026quot; 。\n(請留意，如果判斷兩個運算結果的是否為真 的邏輯運算，\nJava是\u0026quot;\u0026amp;\u0026amp;\u0026quot;，Python則是\u0026quot;and\u0026quot; ，\n以位元為基準的運算和求真偽的邏輯運算是不同的，記得不要搞混了！)\nOR(或):\n前後兩者只要其一為真結果即為真，\n也就是只有兩者皆不成立時，結果才會是假 。\n所以在位元運算中，\n兩兩相對，除了兩個bit都是0的運算結果是0外，其餘都會是1 。\n如 110 OR 100的結果會是110(只有最右邊的bit是兩個0)\nJava和Python中的OR運算符號均為\u0026quot;|\u0026quot; 。\n(如果是邏輯運算的話，Java是\u0026quot;||\u0026quot;，Python則是\u0026quot;or\u0026quot; )\nNOT(非):\n邏輯上的NOT，代表將該真/假狀況轉為原先的相反 ，\n真的變假的，假的變真的 。\n在位元運算中，對每個bit操作，\n只要原先是1的均變為0，為先為0的則變為1 。\n如NOT 110的結果會是001。\nJava和Python中NOT運算符號均為\u0026quot;~\u0026quot; 。\n(如果是邏輯運算的話，Java是\u0026quot;!\u0026quot;，Python則是\u0026quot;not\u0026quot; )\nXOR(互斥或，Exclusive OR):\n邏輯上的XOR，代表前後兩個狀況剛好有一個成立時為真 ，\n即前真後假/前假後真，其餘皆為假。\n位元運算的部分，兩兩相對檢查，當發現是一個1一個0的時候，\n結果為1，否則均為0。\n如1100 XOR 1010的結果會是0110。\nJava和Python中的XOR運算符號均為\u0026quot;^\u0026quot; 。\n位移運算:\n將一個數的所有bit的東西往左或往右移動指定的位元數，\n超出儲存空間的部分捨棄，被位移走的原處則補0。\nJava和Python中使用\u0026quot;\u0026laquo;\u0026ldquo;和\u0026rdquo;\u0026raquo;\u0026ldquo;分別代表向左位移及向右位移。\n例如:\n2 \u0026laquo; 1 的結果會是4，因為2的二進位是\u0026quot;10\u0026rdquo;，\n這個操作代表2向左位移1個bit，空白的部分補零，\n所以會得到\u0026quot;100\u0026quot;也就是十進位制的4。\n9 \u0026raquo; 2的結果會是2，因為9的二進位是\u0026quot;1001\u0026quot;，\n這個操作代表向右位移2個bit，所以\u0026quot;01\u0026quot;的部分移出儲存範圍了被捨棄掉，\n會得到\u0026quot;10\u0026quot;，也就是十進位的2。\n直觀上我們可以將位移N個bit視作乘以或除以2的N次方，\n但要注意範圍是否正確，以及是否要處理正負號 的部分。\n上面介紹了位元運算以後，讓我們回到題目。\n在通訊傳輸的過程中，有可能因為受到雜訊干擾等狀況，\n使得當中的位元反轉(0變成1，1變成0)。倘若我們按照正常的表達方式，\n例如7=0111, 8=1000，對於某些臨界狀況而言，小範圍的變動值會需要大幅度的修改bit，同時當某個高位數的bit出錯的狀況，值就有可能受到大幅度的改變，這顯然是比較糟糕的。\n所以格雷碼的設計就是希望能夠讓更動小數值的時候，只更動較少的bit數量即可，且當有其中的bit受到干擾而出錯時，數值的影響範圍也較小。\n那怎麼計算呢？\n我們從1個bit開始推導看看：\n由於要求要從0開始，\n故我們應該是拿0代表0，1代表1，這樣就完成了1個bit的格雷碼。\n2個bit的話，由於用10來表示會一次更動2個bit(01-\u0026gt;10)，\n所以我們只能拿11來表示2，而10則表示3。\n1 2 3 4 00 - 0 01 - 1 11 - 2 10 - 3 當然，也可以用00, 10, 11, 01來進行表示，但這種方式相對較複雜，\n我們直接去考慮前面的方式的邏輯就好。\n再來我們可以思考，在不要動到前面的數的狀況下，\n下面我們要怎麼表達3個bit的狀況呢？\n已經知道：\n1 2 3 4 000 - 0 001 - 1 011 - 2 010 - 3 我們想要剛好用3個bit表示07，\n那唯有讓47的部分的最左邊的bit均為1才行。\n(因為前面的2個bit組合已經被用過了)\n同時我們又想要符合相鄰只動一個bit 的原則，\n所以4的表示方式就只剩下110了!\n1 2 3 4 5 6 7 8 000 - 0 001 - 1 011 - 2 010 - 3 110 - 4 1xx - 5 1xx - 6 1xx - 7 同時，我們也知道前面03符合這個只動一個bit的表達方式，\n那麼後面填入57的方式，就可以按照上下鏡向 的狀況填入，\n自然會符合格雷碼的要求。也就是除了最左邊是1以外，\n4對應到3，5就對應到2，6對應到1，7對應到0即可。\n1 2 3 4 5 6 7 8 000 - 0 001 - 1 011 - 2 010 - 3 110 - 4 111 - 5 101 - 6 100 - 7 同樣的道理，變成4個bit時，將後面的8個數的最左邊的bit填入1，\n其它的部分鏡向填入即可。\n歸納一下這題的解法：\n先放入0(最開始的部分，也是n=0時的解答) 定義一個變數adder，用來表示這輪要加上去的bit所代表的值\n(初始值是2的0次方=1) 每次將答案的尾端加上一個新的值，\n這個新的值是鏡向對應到的值加上adder。\n(鏡向對應的方式，可以從尾端開始往回算，或者用adder-1-index來計算) 計算完畢一輪以後，將adder變為2倍，作為下一輪要額外加上去的值。 一路操作直到完成n輪為止，最後將結果回傳。 Java Python 讀者可以看到兩個解法中一個使用+adder，另一個使用|add，\n結果上是一樣的，因為加上去的那個bit一定是跟0相加，\n故可以用OR運算會加快一點速度。(讀者可以修改成+來比較看看速度)\n*2和\u0026laquo;=1的部分，同樣可以等價於位移一個bit，\n但速度上應該不會有特別差異才對。\n面試實際可能會遇到的問題 「時間複雜度？」\n(O(2的n次方)，因為n個bit可以表示2的n次方個數)\n「(Python)能不能不要用append來解？」\n(可以用extend，\n每次將res的部分反轉接上後，再進行add的加總)\n「為什麼你要用\u0026quot;_\u0026quot;？」\n(因為第一個迴圈事實上只是處理執行n次這件事情，\n我們並不需要用到其數值，在習慣上會盡量用底線來命名，\n避免去用到有意義的命名方式。)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-11T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-11-bitwise-operation-1/","title":"從LeetCode學演算法 - 11 Bitwise Operation (1)"},{"content":"0083. Remove Duplicates from Sorted List (Easy)\nQuestion Given a sorted linked list, delete all duplicates such that each element appears only once.\nExample 1 1 2 Input: 1-\u0026gt;1-\u0026gt;2 Output: 1-\u0026gt;2 Example 2 1 2 Input: 1-\u0026gt;1-\u0026gt;2-\u0026gt;3-\u0026gt;3 Output: 1-\u0026gt;2-\u0026gt;3 分析/解題 題目給定一個已排序好的linked list，要求將所有重複的node皆刪除，\n使得每個元素均只出現一次。\n這題也算是比較簡單的linked list類型，只要確定連接正確的話並不難解。\n由於已經排序過的原因，所有會重複的元素值均會相鄰，那麼我們所要做的就是遇到重複時總共只保留一個就好了 。\n保留哪一個呢？當然是保留第一個囉！\n我們可以先宣告一個ListNode，命名為ite用來做為iterator(迭代器)，\n每次取得ite的下一個node(命名為tmp)做為暫存。\n接下來開始一路往下尋找，如果ite和tmp前後值相等時，就讓tmp開始往下一直走到底部(表示後面值都一樣) 或者找到下一個不同的值。 對於前者的狀況 而言，表示結束，tmp會指到null(或None)，\n只要將ite.next指向到tmp 即可。\n對於後者的狀況 ，這時候tmp的位置就在下一個相異值的點 。\n像是1-\u0026gt;2-\u0026gt;2-\u0026gt;2-\u0026gt;3-\u0026gt;4這樣子，從ite在碰到第一個2以後，\ntmp會一路找到3的位置，所以我們只要將ite.next指向到tmp ，\n即可將第一個2接到3的位置，從而中間的部分就等於被我們刪去了。\n討論完兩者狀況後，我們會發現無論是哪一種，\n結果都會是將ite.next指向到tmp，\n最後要記得ite本身要遞移到下一個開始找的位置，\n所以我們還需要將tmp的位置交給ite。\nJava 以Python的部分來說，還記得判斷式可以直接適用於if的話，\n就可以寫得看起來簡潔一些。\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1))\n其它應該沒什麼好問的，至少我沒想到XD\n這篇主要是協助讀者再熟悉一下這些連接/斷開的操作。\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-10T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-10-linked-list-2/","title":"從LeetCode學演算法 - 10 Linked List (2)"},{"content":"0070. Climbing Stairs (Easy)\nQuestion You are climbing a staircase. It takes n steps to reach to the top.\nEach time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?\nNote: Given n will be a positive integer.\nExample 1 1 2 3 4 5 Input: 2 Output: 2 Explanation: There are two ways to climb to the top. 1. 1 step + 1 step 2. 2 steps Example 2 1 2 3 4 5 6 Input: 3 Output: 3 Explanation: There are three ways to climb to the top. 1. 1 step + 1 step + 1 step 2. 1 step + 2 steps 3. 2 steps + 1 step 分析/解題 題目描述有一個要爬n階才能到頂端的階梯，每次只能爬1階或2階，\n試求有多少種不同的方法可以走到頂端。\n如果以窮舉的話我們可能需要列很久，\n所以這時候又回到了看看是否能找出相互關係的時候了。\n我們考慮要爬n階的話，首先要先爬到n-1 階或n-2 階，因為只有一次走1階或一次走2階的選擇。也就是說，走到n階的方法，就相當於走到n-1階的方法和走到n-2階的方法和 。因為最後的步伐已經固定了，我們同時還可以保證這兩個方法的組合之間不會互相重複 (一個最後走1步，一個最後走2步)。\n同樣的，走到n-1階的方法=走到(n-2)階的方法+走到(n-3)階的方法，\n以此類推拆解，最終我們來到走到第1階的方法跟走到第2階的方法，\n分別是1跟2。\n我們可以選擇開一個res的陣列，初始化前2階以後，\n一路加上去最終得到到第n階的方法數，下面Java的版本因為陣列由0開始，\n有刻意將數字不先行化簡，讀者應該可以很簡單地對照。\nJava Python的部分，則採用兩個數s1, s2來輪替使用，可以節省記憶體。\n每次應該要做的，是將s1+s2的值擺到s2，而將s2的值擺到s1的位置。\n(等於把兩個數代表的位置遞移了一層)\n(Java也可以用類似的作法，但需要多宣告一個暫存值進行儲存)\nPython 面試實際可能會遇到的問題 「時間/空間複雜度？」\n（O(N), 依方法而定，\n上面Java的寫法需要O(N)，Python的寫法則只需O(1)）\n「哪個寫法比較好？」\n(以空間節省的角度來說是Python版本的寫法較佳，\n但如果我們不止需要算一次的話，執行一次n階，\n其實可以將n階以下的走法數量全部記起來，\n這樣被讀取的時候可以先查是否可以直接拿結果回傳，\n所以反覆執行的效率會變比較好，不過這個就需要再修改一下程式就是了)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-09T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-9-dynamic-programming-2/","title":"從LeetCode學演算法 - 9 Dynamic Programming (2)"},{"content":"0067. Add Binary (Easy)\nQuestion Given two binary strings, return their sum (also a binary string).\nThe input strings are both non-empty and contain only characters 1 or 0.\nExample 1 1 2 Input: a = \u0026#34;11\u0026#34;, b = \u0026#34;1\u0026#34; Output: \u0026#34;100\u0026#34; Example 2 1 2 Input: a = \u0026#34;1010\u0026#34;, b = \u0026#34;1011\u0026#34; Output: \u0026#34;10101\u0026#34; 分析/解題 題目給定兩個二進位字串，試求其和(同樣以二進位字串表達)。\n在電腦的世界裡，本質上是由0和1所構成的，因為對它來說，最容易的表達方式就是電路的開路和斷路兩種狀態。\n如果大家忘記二進位的表示方式，可以從wiki的說明大概回憶一下XD\n這裡只要知道要轉為10進位的話，就是由右至左從2⁰開始相乘相加就對了。\n例: 1010 -\u0026gt; 0*2⁰ + 1*2¹ + 0*2² + 1*2³ = 0 + 2 + 0 + 8 = 10\n每個位數之間是2倍，每滿2就要向左邊進一位。\n那麼給定的是字串的話，要怎麼做處理呢？\n這題很重要的一點是要先確認你是使用什麼程式語言做操作的。\n如果是C/C++/Java等規範相對嚴格的語言的話，\n以Java 為例，其int變數型態一般是用32-bit 來儲存並且含有正負號，\n也就是它只可以接受範圍在**-2³¹~2³¹-1** 之間的數字，超過這個範圍即會overflow(溢位)，這也是這個題目之所以會用字串表達的原因。\n(不同的語言的int變數所涵蓋的範圍不一定相同)\nPython就沒有這種限制，直譯器已經處理好很多事情了，\n所以下面就會看到一些比較簡單(偷吃步)的做法。\n對Java而言，我們既然擔心會溢位導致不能夠直接轉換，\n那麼只好一位一位去做操作了。我們可以使用StringBuilder這個處理字串的類別，從第0位開始將兩邊的數字相加，並且處理進位(carry)的部分。\n對Java而言，字串(String)拆出來的每個單位叫字元(char)，\n使用String.charAt(i)函式，可以將index i的字元拆解出來。\n拆出來的字元其實已經可以用數字的形態印出了，\n但它是代表ASCII code表上的位置，而非真的數字，\n要得到它實際的數字的話，由於'0\u0026rsquo;~\u0026lsquo;9\u0026rsquo;在表上是連續的，\n我們可以減去'0\u0026rsquo;的位置48，即可得到實際的數字；\n或者記不了的話，直接拿該字元去減掉'0\u0026rsquo; ，也可以得到相同的結果。\n這樣的操作也適用於大小寫的英文字母上，請多留意。\n那麼問題就簡單了: 只要是還有位數的狀況下，就取出字元減掉'0\u0026rsquo;，\n否則就當作是0(代表另一個字串比較長)，最後比到兩邊長度都用完，\n這時候StringBuilder應該沿路將所有位數從最低位組合到最高位 了，\n最後處理最高位有可能的進位後，只要再將其進行反轉(reverse)操作，\n再轉為字串(toString)即可。\nJava Python的部分相對簡單的多(可以偷吃步XD)，\n只要將a跟b先轉成int，相加後再轉成二進位即可。\n轉成int的作法是int(num, base) ，\nnum表示你的字串，base表示這段字串的進位方式 。\n相加後轉成bin要特別注意Python的表達方式是以**’0b’** 為開頭，\n所以我們只保留index 2以後的部分。\nPython 簡單吧!\n面試實際可能會遇到的問題 「時間複雜度？」( O(max(len(a), len(b))) )\n「Python解是很簡單啦，但可以用一個一個比較的方法嗎？」\n(請仿照Java的方式寫給他XD)\n(補充: Python的ASCII和數字順序的互轉是 ord(c)跟 chr(a)，\n前者字元轉數字，後者數字轉字元)\n「(Java)j++ 和**++j** 有什麼不同？」\n(++本身是代表將這個值增加1，\n而擺在變數後面代表這整行執行完畢以後，才進行遞增 ；\n後者則代表先將自己本身增加1以後，才執行這整行的操作 )\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-05T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-8-string-manipulation-1/","title":"從LeetCode學演算法 - 8 String Manipulation (1)"},{"content":"0053. Maximum Subarray (Easy)\nQuestion Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.\nExample:\n1 2 3 Input: [-2,1,-3,4,-1,2,1,-5,4], Output: 6 Explanation: [4,-1,2,1] has the largest sum = 6. Follow up:\nIf you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.\n分析/解題 題目給定一個整數陣列，要求找到其中一個連續的子陣列，這個子陣列的和是所有子陣列中最大的，並且回傳該總和值。\n這題如果以暴力法來解決的話，我們可以拿到的總連續子陣列數是\nN+(N-1)+(N-2)+…+1，每個子陣列中的計算下一組和(如[-2] -\u0026gt; [-2,1])，\n都只需一個加法，故時間複雜度會是O(N²)。\n但\u0026hellip;\u0026hellip;感覺很浪費(?)\n我們先思考一個問題：\n「假設我知道nums中1到i-1的最大子陣列和，\n有沒有辦法知道1到i的最大子陣列和呢？」\n我們討論1到i的最大子陣列和，應該分兩種情況：\na. 這個子陣列包括index i\nb. 這個子陣列不包括index i\n如果是b 的話，那答案其實就是1到i-1的最大子陣列和 ；\n但如果是a 的話，我們好像還需要一些條件？\n什麼條件呢？就是1到i-1中，包含i-1元素的最大子陣列和 。\n因為如果是前面所提到的a狀況的話，\n那麼1到i的最大連續子陣列，就必須從i-\u0026gt;i-1連回去才行(或乾脆是只有i)。\n所以這麼一來，條件就比較清楚了，我們會需要的有：\n到現在為止包含當前這個元素的最大子陣列和 ，我們命名為curr(current) 到目前為止的最大子陣列和 ，我們命名為res(result) 那麼我們就以範例的[-2,1,-3,4,-1,2,1,-5,4]來操作看看。\n該怎麼決定curr跟res的初始值呢？因為一開始只有一個值，\n所以curr和res應該都等於nums[0]=-2才對。\n所以一開始我們將curr和res都設為-2，接下來由i=1開始，\n一路往下到最後一個結束。\ni=1: [-2,1 *,-3,4,-1,2,1,-5,4]\n按我們的定義，curr應該是-2+1和1中較大的值，\n我們可以先將curr加上nums[1]，\n接下來檢查curr小於0* ，或者curr\u0026lt;nums[1] ，\n就表示其實我們只要取nums[1] 就好。\n(註1: 表示兩者的正負號為**(-, -), (-, +)** ，不論如何前面那部分貢獻均是負的 )\n(註2: 也可以拆成別的形式或調換順序，但先判斷\u0026lt;0的計算速度會比較快)\n(註3: 後面程式碼Java和Python的判斷方式就不同，可自行依喜好決定使用)\n所以新的curr為1, 接著再比較得知curr\u0026lt;res，故res也要改為1。\n接下來的流程，讀者可以嘗試自己操作一遍再對照一下。\n1 2 3 4 i=2: [-2,1,-3,4,-1,2,1,-5,4] -\u0026gt; curr = 1 + -3 = -2 \u0026lt; 0 -\u0026gt; curr = -3 -\u0026gt; res = 1 1 2 3 4 i=3: [-2,1,-3,4,-1,2,1,-5,4] -\u0026gt; curr = -3 + 4 = 1 \u0026lt; 4 -\u0026gt; curr = 4 -\u0026gt; res = 4 1 2 i=4: [-2,1,-3,4,-1,2,1,-5,4] -\u0026gt; curr = 4 + -1 = 3 \u0026gt; -1 1 2 3 i=5: [-2,1,-3,4,-1,2,1,-5,4] -\u0026gt; curr = 3 + 2 = 5 \u0026gt; 2 -\u0026gt; res = 5 1 2 3 i=6: [-2,1,-3,4,-1,2,1,-5,4] -\u0026gt; curr = 5 + 1 = 6 \u0026gt; 1 -\u0026gt; res = 6 1 2 i=7: [-2,1,-3,4,-1,2,1,-5,4] -\u0026gt; curr = 6 + -5 = 1 \u0026gt; -5 1 2 i=8: [-2,1,-3,4,-1,2,1,-5,4] -\u0026gt; curr = 1 + 4 = 5 \u0026gt; 4 所以最後我們得到res = 6，再回傳即可。\n這個解法第一次並不是很容易上手，而且並非相當直觀的方式，\n但它常常可以在特別的地方有效地解決問題。\n適用於這類型的解法的問題會有一個特性：\n「N=i+1時的解，通常和N=i時的解以及第i+1的值有關連性」\n(也有可能跟更前面幾個值同時有關連性)\n而我們通常很難直觀地直接用簡單的方式去算出N=i+1的解，\n所以會依靠其本身和前面的連動關係，\n讓答案像堆積木一樣，從i=0開始堆到最後面得到最終的答案。\n有些問題可能未必是一層一層疊上去，\n也有可能是把一個大問題拆成數個小問題，\n最後將其組合起來得到大問題的答案。\n但通常我們最常見的形式還是如上面那樣子按順序堆疊的。\n上面這樣子形式的解題方法，\n被稱之為動態規劃(Dynamic Programming) ，或者也常簡稱為DP。\n每個動態規劃的問題都會有些不一樣，\n但只要抓到其中的連動性，找到從i -\u0026gt; i+1 中間的關聯，\n就可以順利解開題目。\nJava Python 面試實際可能會遇到的問題 「時間/空間複雜度？」\n(O(N), O(1))\n「如果不使用DP是否有O(N)解？」\n(可以使用分治法，請參見 *LeetCode這篇討論 *底下的回應)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-04T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-7-dynamic-programming-1/","title":"從LeetCode學演算法  -  7 Dynamic Programming (1)"},{"content":"0035. Search Insert Position (Easy)\nQuestion Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.\nYou may assume no duplicates in the array.\nExample 1 1 2 Input: [1,3,5,6], 5 Output: 2 Example 2 1 2 Input: [1,3,5,6], 2 Output: 1 Example 3 1 2 Input: [1,3,5,6], 7 Output: 4 Example 4 1 2 Input: [1,3,5,6], 0 Output: 0 分析/解題 給定一個排序的陣列和目標值，假定陣列的數字不會重複。\n題目要求找到目標值在這個陣列中的位置；\n若無，則回傳如果要將其插入時，應插入的位置。\n這題是很典型的二元搜索法(Binary Search) 。\n所謂的Binary Search，就是資料已處於被排序的狀態，那麼在這些資料內搜索某個特定值就不用一個一個找，我們可以用比較快的方法來搜尋。\n假設我們有一組排序過的陣列，\n搜尋的第一步就是取得中間點的那個值，我們先稱之為mid，\n那mid左邊的數必然小於mid，反之mid右邊的數必然大於mid 。\n(按順序排的嘛XD)\n所以我們拿目標值target跟mid比較，\n如果target == mid ，那mid所在的位置 就是我們要的答案；\n如果target \u0026gt; mid ，表示答案只可能在mid右邊到尾端之間(不含mid) ；\n如果target \u0026lt; mid ，表示答案只可能在mid左邊到開頭之間(不含mid) 。\n如此一來，每次取得區塊的中間點的值，並和target做比較，\n則每次都可以至少刪掉一半的可能的數量 ，\n直到找到答案(target == mid) ，\n或是區塊上下限交錯(那就表示target不存在於陣列之中) ，\n我們同樣可以將下限 的index輸出，因為它就代表應該被插入的點。\n例1. nums=[1,3,5,6], target=2 首先取下限lo = 0, 上限up = 3(頭跟尾), 中間點mi = (lo + up) / 2 = 1 -\u0026gt;\nnums[1]為3, 3 \u0026gt; 2 -\u0026gt; 將up改為mi-1=0 -\u0026gt; mi = (0 + 0) / 2 = 0 -\u0026gt;\nnums[0]為1, 1 \u0026lt; 2 -\u0026gt; 將lo改為mi+1=1 -\u0026gt; lo和up已交叉，故結果應輸出1。\n中間的值的變化如下：\n1 2 3 4 lo up mi nums[mi] 0 3 1 3 0 0 0 1 1 0 0 1 例2. nums=[1,3,5,6], target=5\n首先取下限lo = 0, 上限up = 3(頭跟尾), 中間點mi = (lo + up) / 2 = 1 -\u0026gt;\nnums[1]為3, 3 \u0026lt; 5 -\u0026gt; 將lo改為mi+1=2 -\u0026gt;mi = (2+3)/2 = 2 -\u0026gt;\nnums[2]為5, 5==5 -\u0026gt; 直接輸出mi的值2即是答案。\n中間的值的變化如下：\n1 2 3 lo up mi nums[mi] 0 3 1 3 2 3 2 5 下面也列出[1,3,5,6], 7跟[1,3,5,6], 0的值變化的過程，\n有興趣或對整個邏輯還沒有弄得很明白的讀者可以嘗試推導一遍。\nnums=[1,3,5,6], target=7 -\u0026gt; ans = 4\n1 2 3 4 5 lo up mi nums[mi] 0 3 1 3 2 3 2 5 3 3 3 6 4 3 3 6 nums=[1,3,5,6], target=0 -\u0026gt; ans = 0\n1 2 3 4 lo up mi nums[mi] 0 3 1 3 0 0 0 1 0 -1 -1 6 #(這個是用python輸出的，所以nums[-1] == 6) 底下的解法看個人喜好命名均可。\nJava Python 在這個解題過程，由於每次我們都會將範圍縮小一半，\n所以總共比對的次數就相當於求這個陣列的長度是2的幾次方，\n故時間複雜度為O(logN) 。\n(電腦科學領域的對數一般不特別提的話通常是以2為底)\n事實上，Java中也有提供 Arrays.binarySearch(int[] a, int key) 於utils的函式庫中，但有一點不一樣的是，當找不到target的時候，\n如果插入該key所在位置為index，則回傳值為**-index-1** 。\n取負號是為了和key存在於陣列的狀況做分隔，\n額外減1則是為了將key在0的位置 及key應該要插入在0的位置 做區分。\n(因為0取負號還是0)\nBinary Search是在排序陣列或一些有序的資料結構中很常用到的演算法，\n以後在談到二元搜尋樹(BST, Binary Search Tree) 的時候也會用到它。\n所以如何寫一個二元搜尋的簡單方法是很有用的，可以的話務請熟練XD\n面試實際可能會遇到的問題 「(Java)如果上限接近Integer.MAX_VALUE的話相加有overflow的可能？」\n(將(lo+up)/2改成lo + (up-lo)/2，可以保證不會溢出)\n「時間/空間複雜度？」\n(O(logN), O(1))\n「我想知道到底結果target是否存在array中，但不想額外加回傳的值？」\n(如上面提到的，將插入 的狀況改為**-index-1** 來表達)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-03T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-6-binary-search/","title":"從LeetCode學演算法 - 6 Binary Search"},{"content":"0026. Remove Duplicates from Sorted Array (Easy)\nQuestion Given a sorted nums array, remove the duplicates in-place such that each element appears only once and return the new length.\nDo not allocate extra space for another array, you must do this by modifying the input array ** in-place** with O(1) extra memory.\nExample 1 1 Given nums = [1,1,2], 1 Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. 1 It doesn\u0026#39;t matter what you leave beyond the returned length. Example 2 1 Given nums = [0,0,1,1,1,2,2,3,3,4], 1 Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively. 1 It doesn\u0026#39;t matter what values are set beyond the returned length. 分析/解題 題目要求將一個已排序陣列中所有的重複數字刪去，使得這個陣列的每個數字只出現一次，並且必須要以in-place的方式來處理。\n最終處理過後，回傳新陣列的長度。\n題目其實並不困難，設定一個i用來記錄目前存放到哪個位置，\n再設定一個j用以完整遍歷整個陣列，\n每當發現有不同的數字時，就將j的數字塞到i的位置，再往下推進即可。\n最後由於要回傳的是新陣列的長度，所以應該要回傳i+1。(陣列由0開始)\n這邊要順便提到的一個名詞叫in-place algorithm 。\n所謂的in-place，就是指所有的操作修改，除了一些計數用的變數外，\n基本上都在原先的資料結構內解決 ，像這題就是完全只有操作原陣列。\n如果沒有這樣的限制，這題也是可以使用ArrayList，每當發現一個不同的數就將其往List尾端加，最後再將其轉為array，\n同樣可以得到解，但它的空間複雜度就會變成O(N)，\n因為我們開了一組額外的記憶體來存放它。\n所以in-place algorithm會應用在一些不希望大量增加記憶體使用量 的狀況，且在這個限制條件下，有時候我們不一定能像這題這樣得到跟非in-place時一樣時間複雜度的解法。\n所以in-place algorithm通常會有拿時間換取空間效率的狀況 。\n總之，如果原先的資料被修改或打亂也沒關係 的話，\n就有使用in-place algorithm的機會，也有可能會被面試官問到，\n但請務必謹慎地確認是否這個狀況下，\n你真的會必須用比較差的時間複雜度達到相同的目的。\nJava Python 面試實際可能會遇到的問題 「時間複雜度跟空間複雜度為？」(O(N), O(1))\n「如果不要求in-place，改成新開list/arraylist來做會比較快嗎？」\n(不會，因為時間複雜度相同，但要額外花時間做記憶體配置)\n「如果題目今天給的是未排序陣列要去除duplicate，\n但不用in-place，也不用保留順序的話？」\n(使用HashMap/dict，將整個陣列掃過一遍，最後遍歷輸出)\n(時間/空間複雜度為O(N), O(N))\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-02T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-5-in-place/","title":"從LeetCode學演算法 - 5 In-Place"},{"content":"0021. Merge Two Sorted Lists (Easy)\nQuestion Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.\nExample:\n1 2 Input: 1-\u0026gt;2-\u0026gt;4, 1-\u0026gt;3-\u0026gt;4 Output: 1-\u0026gt;1-\u0026gt;2-\u0026gt;3-\u0026gt;4-\u0026gt;4 分析/解題 題目要求將兩個已排序的linked lists合併，\n且所產生的新list必須由原有的節點(node)所構成。\nLinked List是一個很常見的資料結構，資料與資料連接的方式是單向的，\n通常從第一個節點(node)往後連接到最後一個節點(node)。\n每個節點上會存放一個(或一組)資料以及連結(link)，\n每個連結會指向到下一個節點 的位置(記憶體位址)。\n(在C/C++裡面連結基本上就是指標(pointer))\n你可能會問，那麼最後一個節點呢?\n最後一個節點除了儲存資料以外，因為連結沒有東西了，所以會給定空值。在演算法的書中一般會稱為NIL ，NIL在英文裡面就是nothing 的意思，\n表示沒有任何東西。\n在Java中有LinkedList的資料結構，它同樣是List的一種。\n但一般遇到題目的時候會給的通常是一個node，\n用來指向到該List的第一個節點。\n我們會看到如果你打開LeetCode選擇Java時，\n上方已經先用註解告訴你這個ListNode的結構了：\n1 2 3 4 5 6 7 8 /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ 也就是說，題目預先定義了一個class叫做ListNode，\nval用來存放每個node的值，next用來指向到下一個node ，\n有一個ListNode(int x) 的建構子(constructor)，\n可以讓你在產生一個新的節點時給定其值。\n對於LinkedList來說，它最大的好處在於新增/刪除節點時相當方便。\n例如現在有a-\u0026gt;b，我想要加一個資料值為20的c節點，放在b後面的話，\n以Java而言只需要:\n1 2 3 ListNode b = a.next; // 因為一開始我們只知道a的位置而已XD ListNode c = new ListNode(20); b.next = c; 如果是插入在a跟b中間呢？也不難，\n只是我們要先記住b，不然一旦沒有人記它，它就消失在時空裂縫中了(誤)\n(會依照各自編譯器的規範，只是以我們而言是真的就沒辦法找到它了)\n1 2 3 4 5 // a -\u0026gt; c -\u0026gt; b ListNode b = a.next; ListNode c = new ListNode(20); a.next = c; c.next = b; 請留意如果你調動了一些節點的順序，留意他們的next是否被妥善處理，\n該被清空的請給定NIL。在Java中是用null來表示，而Python則是用None。 回到題目，我們該如何去合併排列好的兩個LinkedList呢？\n這邊提供一個很簡單的遞迴思路。\n(遞迴的概念，我們之後再專門做一篇相關的來講解)\n我們合併兩個list的狀況目標還是要呈現排序好的樣子，\n那麼怎麼排呢？\n由於原先的list已經是排好的，\n我們拿出最左邊的node比較，稱為l1跟l2。\nl1是全空的狀況下，那其實答案就是l2(因為後面就不用繼續排了)，\n反之l2是全空的話，答案就是l1。\n那麼如果l1的值小於l2的值的話，那麼l1應該要當頭，\n接下來我們要拿l1.next 跟l2 來做比較大小，比較小的，\n就會是新的l1連接的下一個節點。\n一直連接到最後，我們就可以得到合併好的list了！\n相等的狀況因為題目沒有特別要求要分辨是l1還是l2的節點，\n所以任取一個均可。\n例：\nl1: 1 -\u0026gt; 3 -\u0026gt; 5 -\u0026gt;8 -\u0026gt;10, l2: 2 -\u0026gt; 4 -\u0026gt; 4\n1先跟2比，1比較小所以當頭(1) -\u0026gt; 3跟2比，2比較小(1-\u0026gt;2) -\u0026gt;\n3跟4比(1-\u0026gt;2-\u0026gt;3) -\u0026gt;\n5跟4比(1-\u0026gt;2-\u0026gt;3-\u0026gt;4) -\u0026gt;\n5跟4比(1-\u0026gt;2-\u0026gt;3-\u0026gt;4-\u0026gt;4) -\u0026gt;\nl2的部分已經空了，填入l1中5以後剩下的部分\n(1-\u0026gt;2-\u0026gt;3-\u0026gt;4-\u0026gt;4-\u0026gt; 5 -\u0026gt;8 -\u0026gt;10)\n寫成Java的程式如下。\nJava:\n當然我們也可以用迴圈(迭代)的方法來解，\n但這時候我們就要比較仔細的去處理節點間的關係了。\n在Python中判斷是否為None可以使用if，\n通過if的話節點就代表該節點是有值的，\n你也可以加入not的關鍵字來處理你所需要的判斷式。\n比如我可以用if not (l1 and l2)來表達其中一個以上是空的狀況，\n並回傳不是None的那個node。\n操作上，我們需要一個dummy node做為旁觀者，\n讓它從頭到尾都只保持在同樣的位置 ，並指向到第一個節點。\n接著我們定義一個節點叫做prev，\nprev的next 會指定給下一個比較過後較小的那個節點 。\n那麼，每次將prev的next拿到以後，\nl1或l2(看哪個比較小)就自己遞移到下一個節點 ，\n並且prev也往下走到自己的next，準備接取下一個節點；\n重覆上面的動作直到其中一邊節點用光 ，\n即可把剩下的直接全接到prev.next上。\n最終我們回傳的答案是dum.next ，因為只有dum沒有被動過，\n其他的節點其實都已經被改動過指向的位址了。\nPython 在有關linked list的部分，因為牽扯到位址的概念，\n所以操作上要稍微再思考一下，比較不容易搞混。\n最重要的是，對於Java和Python來說，由於所使用的都是class來建立node，\n所以其實你看到的等號，除了給定val的狀況以外，\n其他其實都是在做把右邊放的記憶體位址存到左邊 的動作，\n所以指向的記憶體位址變了，代表的節點也就跟著變了 ，務必要留意這點。\n面試實際可能會遇到的問題 「請用iterative(迭代或迴圈)/recursive(遞迴)的方式來解」\n(上面Java是recursive solution，Python是iterative solution，\n讀者可以嘗試改成另一個語言試看看)\n「使用遞迴的話會有什麼限制？」\n(有可能受到編譯器規範的最大function stack上限限制，\n同時，連續的函式呼叫的效率，相對於在迴圈中執行來說會較差)\n「那為什麼你會用遞迴？」\n(因為遞迴比較好想啊XDDDDD)(別這麼誠實，雖然大家都知道XD)\n(因為在一般狀況下，遞迴解通常會較為容易閱讀，\n也比較符合人類的思路模式，就像推骨牌一樣，\n當起始條件和後續的脈絡定下來以後，後面的結果就會水到渠成。)\n「時間複雜度是？」\n( worst case是O(N1+N2)，best case是O(min(N1, N2))。)\n「如果希望你另外開一個新的linked list，不用原本的節點來解這題呢？」\n(這樣會比較簡單，一樣兩兩比較，但改成較小的取其val來產生一個新的ListNode，接在你的新的linked list後面，讀者可以嘗試看看，\n別忘記要留dummy node歐！)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-07-01T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-4-linked-list-1/","title":"從LeetCode學演算法 - 4 Linked List (1)"},{"content":"0015. 3Sum (Medium)\nQuestion Given an array nums of n integers, are there elements a, b, c in numssuch that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.\nNote:\nThe solution set must not contain duplicate triplets.\nExample:\n1 Given array nums = [-1, 0, 1, 2, -1, -4], 1 2 3 4 5 A solution set is: [ [-1, 0, 1], [-1, -1, 2] ] 分析/解題 題目要求從陣列中找出所有數組a, b, c，\n使得三者相加為0，且不能重覆。\n老話一句，請記得問有沒有排序XD~\n以暴力法解本題的話，會發現每次取三個做組合，\n顯然會得到一個O(N³)的時間複雜度的解。\n那麼，嘗試排序看看能得到比較好的解嗎？\n我們先拿題目的例子來看看，排序過後為\n[-4, -1, -1, 0, 1, 2]\n按順序排列會有什麼好處呢？\n假設我們先固定最左邊的-4為a(因為要組合，我們可以令a\u0026lt;=b\u0026lt;=c)，\n那麼b+c必須等於4，這邊使用一個簡單的技巧，\n先將b指定給-1的位置，c指定給2的位置，\n兩者相加等於1，表示應該要取更大的值 才有機會讓和等於4，\n於是我們可以將b的位置向右移一格(這裡是重覆的所以可以跳過)，\n再次檢查和目標的大小比較。\n那麼很容易可以發現一件事情：\n當現在的值比目標值大 時，表示應該要取更小的值 ，\n只有將c往左移動 才有可能達到。\n反之，\n當現在的值比目標值小 時，表示應該要取更大的值 ，\n只有將b往右移動 才有可能達到。\n因此，在固定a值的時候，只要將後面的數按照上面的方法，\n一次移動一格的掃過一遍，就可以得到這個a值所可以成立的組合。\n所以最終我們只要將a從0~len(nums)-3按順序跑過一遍，\n將中間符合的組合都放進list中，即可得到答案。\n重覆性的部分，只要記得檢查前一個和這一個用的數字是否相同即可避免。\n上述的做法，由於使用到兩個指標(指針)，並透過移動它們來達到掃描陣列的目的，我們通常稱這樣的解法為Two Pointer ，是蠻常用的技巧。\n時間複雜度的部分，排序的一般狀況是O(NlogN)，\n而a的長度是O(N)，每次都要掃完其後的長度，掃描部分即為O(N²)，\n所以總體的時間複雜度為O(N²)。\nJava 這邊使用i, j, k標記，要用a, b, c也可XD\n使用Arrays.asList可以將一串元素塞成ArrayList。\nPython Python的部分提供了另一個的思路，\n這是由 RouRouKerr在討論區所提出的解法，這邊是改成Python3版本。\n他的想法是，在固定第一個數v的狀況，那當其中一個數為x，\n另一個數只能是-v-x(因為加總要等於0)。\n故每次將對應的互補數加入到dict中，\n我們只要從頭到尾檢查，即可得到所有的正確組合。\n這個想法跟前面Two Sum的解法概念是一樣的。\n(對應到Java版本的解法也附在註解處)\n面試實際可能會遇到的問題 「(Python)前面不檢查的話後面你怎麼處理重覆？」(用set)\n「假設目標不是0的話？」(方法應該是一樣的)\n「(Python)dictionary的部分使用set代替會比較快嗎？」(實測過會變慢XD)\n「(Java)如果可以改變input/output的變數形態的話，你會希望改動什麼？」\n(改output，因為輸出應該固定會是3元組的組合(長度必然是3)，\n那大可以使用List\u0026lt;int[]\u0026gt;，用List\u0026lt;List\u0026gt;其實較不理想)\n只要掌握了Two Pointers的概念，很多題目其實可以在排序後輕鬆解決，\n但記得注意有些題目可以比O(NlogN)快的話，排序會提高時間複雜度歐！\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-06-29T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-3-two-pointers/","title":"從LeetCode學演算法  - 3  Two Pointers"},{"content":"0014. Longest Common Prefix (Easy)\nQuestion Write a function to find the longest common prefix string amongst an array of strings.\nIf there is no common prefix, return an empty string \u0026quot;\u0026quot;.\nExample 1 1 2 Input: [\u0026#34;flower\u0026#34;,\u0026#34;flow\u0026#34;,\u0026#34;flight\u0026#34;] Output: \u0026#34;fl\u0026#34; Example 2 1 2 3 Input: [\u0026#34;dog\u0026#34;,\u0026#34;racecar\u0026#34;,\u0026#34;car\u0026#34;] Output: \u0026#34;\u0026#34; Explanation: There is no common prefix among the input strings. Note:\nAll given inputs are in lowercase letters a-z.\n分析/解題 題目要求從一組字串陣列中找出其最長的共用前綴，\n字串只會由a到z所構成，若沒有的話則回傳空字串。\n同樣的，若遇到這個問題，請第一時間記得問他們有沒有排序XD\n依據資料的分布不同，不同的解法應該會有不同的優勢，\n但非特殊情況的話，總體時間複雜度應為: O(單一字串長 * 總字串數)\n最直觀的想法，就是從頭開始將每個相同位置的字元比對一次，\n相同則往下繼續做，不同則停下將結果輸出，\n但這麼做可能前面每次都要掃過相同位置的所有字元。\n我們可以換個角度想，若先拿第一個字串當作common prefix(命名作pre)，\n接下來用其餘的字串來檢查這個pre是否是其prefix，是的話則檢查下一個，\n不是的話就將pre的尾端刪去重新檢查，這樣一旦當中有一個字串有大幅度差異，我們很快就能將pre縮減到很短。\nJava 留意這當中我們使用了String.indexOf()來檢查，\n我們只想要pre在剛好0的位置，所以不論這個值是\u0026gt;0(表示出現在中間)\n或\u0026lt;0(根本沒出現)，都代表pre需要被調整。\n實測上這個解是當前LeetCode上對test cases跑最快的版本(0 ms)。\n如果是Python的話，會有比較有趣的解法。\nPython支援的min()和max()可以讓我們在List[str]中列出依字母排列順序 最小和最大的字串。當我們可以很簡單拿到這個值時，\n我們可以換一個思路，從頭到尾比較的時候，我們其實只需比最小和最大的兩個字串就好，當它們是相同字元時則往下繼續，否則就回傳至目前為止的substring。(因為排序最大和排序最小在某個index字元相同時，即代表著中間其他字串在此index字元亦相同)\nPython 面試實際可能會遇到的問題 「如果不能用indexOf的話你會怎麼做？」\n(可使用String.toCharArray()轉成陣列後再操作)\n「如果這組陣列被預期長短差異很大呢？」\n(先掃過一遍陣列，拿最短的當pre)\n「Best Case和Worst Case的時間複雜度？什麼狀況下會發生？」\n(依照你的解法應該有所不同)\n「如果加入\u0026lt;0的判斷式的話可以提升這個程式的效率嗎？」\n(不一定，因為不保證多快能遇到前綴完全不同的字串 ，\n所以端看這組資料是預期很有可能出現結果為空字串，\n還是大多數都會有共同前綴來決定。)\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-06-28T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-2/","title":"從LeetCode學演算法 - 2"},{"content":"0001. Two Sum (Easy)\nQuestion Given an array of integers, return indices of the two numbers such that they add up to a specific target.\nYou may assume that each input would have *exactly * one solution, and you may not use the same element twice.\nExample:\n1 Given nums = [2, 7, 11, 15], target = 9, 1 2 Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1]. 分析/解題 題目要求是，在一組陣列中找出兩個數，其加總恰等於給定值。\n每個數不能被重複使用，且必剛好只有一個解。\n像這種題目，由於被擺在第一題，大多數狀況都不會被拿來考XD\n但，凡事總有例外。\n我們先來分析一下，如果按照原題的要求該怎麼解。\n如果input長度為N，那麼暴力解就是將數字兩兩相加看是不是解，\n這樣的解法要算N(N-1)/2次，也就是O(N²)的時間複雜度。\n該怎麼降低複雜度呢？我們會希望每個數只要查一次就知道結果，\n有沒有這樣的結構？當然有，在Java中可以用HashMap ，\n而在Python中可以用dictionary 。\n只要每一次從map中確認當下target-num是否在map中，\n在的話就表示找到了，可以將結果取得，\n沒找到的話，就將一組(num, index)放進map中，\n依此流程，最壞的狀況整個array遍歷後，就可以得到答案。\n時間複雜度：\n由於HashMap在put和get最好的狀況都是O(1)，\n遍歷整個Map需要O(N)。\nJava:\nPython:\n面試實際可能會遇到的問題 這裡有一個原則：\n***不論是什麼問題，不論你當下想到的方法有多暴力有多爛，\n有想到方法就先講沒關係。***以這題為例，你應該先提出最先的O(N²)解，大概描述完以後，\n再說但這樣時間複雜度比較高，\n如果應用HashMap(python用dict)的話，\n可以讓每個數只需要花O(1)作搜尋，複雜度就會降到O(N)。\n先講出一個可能的解法，再想辦法延伸修改或者改進它，\n這是大多數公司建議(尤其Google)的方式，\n一來可以讓面試官知道你不是腦袋空空，至少先有個基本分，\n二來在講這個暴力解時，你可以有緩衝的時間去想更好的解法。\n還有一些需要注意的東西可以做為你和面試官互動和溝通的部分，\n或有可能是面試官問你的進一步問題，\n在平常每題解完後，都應該留點時間給自己去思考一下可能的變化。\n以此題為例：\n「請問這個陣列是否是排序好的？」(排好的解法就又不同了XD)\n「如果我想要的是回傳那兩個數字而非indices的話呢？」(修改pair即可)\n「你剛剛提到了排序，那怎樣的狀況先對陣列作排序會比較好？」\n「如果答案存在很多組，能否找出所有的解？」\n「如果當中存在重覆的數字的話呢？」\n「為什麼HashTable/HashMap的存取是O(1)？」(這可能就扯比較遠了XD)\n「那麼它們的worst case呢？什麼狀況下會發生？」\n從LeetCode學演算法，我們下次見囉，掰~\n","date":"2019-06-27T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-1/","title":"從LeetCode學演算法 - 1"},{"content":"你應該知道的面試基礎和解題技巧\nWhat is an algorithm?\n所謂的演算法，就是描述一個計算/操作的過程，\n這個過程可以用有限的長度來描述如何解決問題。\n或者更簡單的說法：\n*演算法，就是解決問題的方法流程。 *\nWhy do we need to learn algorithms?\n先講一下筆者的經歷：筆者當了7年多的工程師，當中有2.5年和Android kernel/HAL/framework相關，2年跟Android App和一般Software有關，後面則是ML/Deep Learning為主，在面試時也分別面過不同的職位，唯獨幾乎萬變不離其宗的，就是白板題。\n面試官拿出一道你見過或沒見過的題目，問你該怎麼解，\n你思考後給出回答，並且討論可以改進的方式及可能的錯誤，\n這應該是所有面試者都會歷經的流程。\n那麼，你是否經歷過這樣的狀況？\n「這個題目的類型看起來好眼熟，可是不知道從何下手，該怎麼辦 QQ」\n白板題的重點，就在於演算法 。掌握好演算法，就跟數學學會公式一樣，\n可以將一些複雜的東西簡單化，平常練習的題目多了，\n套起公式來自然得心應手，就算題目再怎麼變，也萬變不離其宗。\n當然，後面還會衍生出一個問題：一個題目該用哪種演算法比較好？\n但這是另一個故事了，我們以後再談XD\nWhy LeetCode?\n那麼，現在網路上可以供作練習的網站相當之多，除了LeetCode外，\n你可能還聽過HackerRank及CodeWar等，\n那麼為什麼是用LeetCode而不是其他呢？\n以筆者的經驗，HackerRank相當適合做為熟悉語言特性使用 ，但不適合目標是熟練解題的人。你可以在其 “LANGUAGE PROFICIENCY”的分類中針對特定的程式語言一路寫到尾，這樣可以對這個語言有一個比較基本的認識。\n而雖然它們有”Interview Preparation Kit”的部分，但相對題目較為簡單，涵蓋範圍也較少。舉例來說，在Tree的分類上只有5題，這一點點的量，其實相當不足。同時，HackerRank的題目往往較長，限制也通常較多，(這裡是指Problem Solving分類)，和一般面試會遇到的題目型態較為不同。\n但若今天的形式是給你1個半小時解3題 的話，\n那麼HackerRank的模式就會很適合你。\nCodewar的話，較為偏向打怪(題目)升級的模式，每個題目都會有一個等級，解決題目累積經驗值並提升自己的level會有一種練功的感覺。筆者不推薦的原因在於\n網站讀取速度偏慢 題目沒有編號 ，你會做到不知道哪裡去也不確定自己有沒有準備好XD Discuss區不像LeetCode傾向於分享整組解法 那LeetCode呢？\n當前(2019/06/26)的題目量總共有1096題，Easy佔了當中的319題。\n筆者練習的題目總量為348題: Easy 266, Medium 65, Hard 17。\n2020/08/18:\n當前的的題目量總共有1553題，Easy佔了當中的430題。\n筆者練習的題目總量為502題: Easy 288, Medium 179, Hard 35。\n以筆者的個人經驗，只要將LeetCode的Easy難度寫過一輪，\n搭上少量的Medium和些許的Hard題目，便足以應付絕大多數的白板題。\n這當中要求的是盡可能不要去翻別人的答案，自己先兜出解法後，\n在能力範圍內去盡力提升這個解的速度，\n真的不行或卡超過半小時才去參考別人的解答。\n在練習到一般的白板題都不能難倒你後，就可以將注意力集中在你主要經驗相關的領域了。(如筆者找AI職缺，那麼就會偏向ML相關的知識)\nWhat’s the plan?\n接下來的系列，將會以LeetCode從第1題開始順序往下，以Easy題目為主，參雜少量Medium題，搭配題目分析及演算法講解，在整理先前自我學習的過程中，希望能對大家有所幫助。解題所用的程式語言會以Java 及Python 為主，但概念基本上不會差多少，若是使用其他語言的朋友應該也可能從中理解思路。使用的解有些可能會因為我看到更好的解法，會使用其他人在Discuss區塊提出來的解，筆者會盡量標明是哪一位LeetCode user所寫的。\n除此以外，若文章中有錯字、寫錯或有任何讓人感到疑問的地方，\n歡迎留言告訴我！\n2020/09/05:\n容筆者工商一下， 「從Leetcode學演算法｜進階篇」及 加贈的**「從Leetcode學演算法｜面試篇」已經全數上傳完囉！**\n目前只剩下給讀者的進階篇+面試篇(3150) 和全套同捆優惠(3990) 了QQ\n「從Leetcode學演算法｜進階篇」+「從Leetcode學演算法｜面試篇」：\nhttps://bit.ly/leetcodeadv\n「從Leetcode學演算法」全套(基礎/進階/面試篇)同捆優惠：\nhttps://bit.ly/leetcodeall\n內容介紹：\n這次選了40道難度加深的LeetCode題目，\n同樣也會細部解說對應的技巧及須要掌握的演算法！\n同時這次購買進階篇的話，\n額外還加贈**「從Leetcode學演算法｜面試篇」** ！\n當中包含了面試準備須知分享 ，及訪談國內外不同經驗的工程師 ，\n讓你不論是想走前端/後端/一般軟工 或者是想找國外的工作 ，\n是初學想轉職 還是正在工作 ，都能夠從中得到收穫呦！\nPS. 因應建議，將文章目錄連結貼在底下，方便大家查找。\n(請使用Ctrl+F輸入想要查找的題目或題型)\n從LeetCode學演算法 - 1 Two Sum (Easy) 從LeetCode學演算法 - 2 0014. Longest Common Prefix (Easy)\n從LeetCode學演算法 - 3 Two Pointers 0015. 3Sum (Medium)\n從LeetCode學演算法 - 4 Linked List (1) 0021. Merge Two Sorted Lists (Easy)\n從LeetCode學演算法 - 5 In-Place 0026. Remove Duplicates from Sorted Array (Easy)\n從LeetCode學演算法 - 6 Binary Search 0035. Search Insert Position (Easy)\n從LeetCode學演算法 - 7 Dynamic Programming (1) 0053. Maximum Subarray (Easy)\n從LeetCode學演算法 - 8 String Manipulation (1) 0067. Add Binary (Easy)\n從LeetCode學演算法 - 9 Dynamic Programming (2) 0070. Climbing Stairs (Easy)\n從LeetCode學演算法 - 10 Linked List (2) 0083. Remove Duplicates from Sorted List (Easy)\n從LeetCode學演算法 - 11 Bitwise Operation (1) 0089. Gray Code (Medium)\n從LeetCode學演算法 - 12 Linked List (3)/ Stack (1) 0092. Reverse Linked List II (Medium)\n從LeetCode學演算法 - 13 Tree (1) 0100. Same Tree (Easy)\n從LeetCode學演算法 - 14 Tree (2) / Queue (1) 0101. Symmetric Tree (Easy)\n從LeetCode學演算法 - 15 Bitwise Operation (2) 0136. Single Number (Easy)\n從LeetCode學演算法 - 16 BST (1) 0098. Validate Binary Search Tree (Medium)\n從LeetCode學演算法 - 17 Tree (3) 0094. Binary Tree Inorder Traversal (Medium)\n從LeetCode學演算法 - 18 Tree (4) 0124. Binary Tree Maximum Path Sum (Hard)\n從LeetCode學演算法 - 19 Tree (5) 0111. Minimum Depth of Binary Tree (Easy)\n從LeetCode學演算法 - 20 Tree (6) 0110. Balanced Binary Tree (Easy)\n從LeetCode學演算法 - 21 Dynamic Programming (3) 0062. Unique Paths (Medium)\n從LeetCode學演算法 - 22 Array (1) 0169. Majority Element (Easy)\n從LeetCode學演算法 - 23 Array (2) 0229. Majority Element II (Medium)\n從LeetCode學演算法 - 24 Dynamic Programming (4) 0063. Unique Paths II (Medium)\n從LeetCode學演算法 - 25 Array (3): 0283. Move Zeroes (Easy)\n從LeetCode學演算法 - 26 Dynamic Programming (5) 0096. Unique Binary Search Trees (Medium)\n從LeetCode學演算法 - 27 Array (4) 0189. Rotate Array (Easy)\n從LeetCode學演算法 - 28 Dynamic Programming (6) 0198. House Robber (Easy)\n從LeetCode學演算法 - 29 Dynamic Programming (7) 0213. House Robber II (Medium)\n從LeetCode學演算法 - 30 Tree (7) 0144. Binary Tree Preorder Traversal (Medium)\n從LeetCode學演算法 - 31 Linked List (4) 0141. Linked List Cycle (Easy)\n從LeetCode學演算法 - 32 BST (2) 0700. Search in a Binary Search Tree (Easy)\n從LeetCode學演算法 - 33 Array (5) 0905. Sort Array By Parity (Easy)\n從LeetCode學演算法 - 34 Array (6) 0977. Squares of a Sorted Array (Easy)\n從LeetCode學演算法 - 35 BST (3) 0108. Convert Sorted Array to Binary Search Tree (Easy)\n從LeetCode學演算法 - 36 Merge Sort (1) 0148. Sort List (Medium)\n從LeetCode學演算法 - 37 Dynamic Programming (8) 0121. Best Time to Buy and Sell Stock (Easy)\n從LeetCode學演算法 - 38 Array (7) 0088. Merge Sorted Array (Easy)\n從LeetCode學演算法 - 39 Array (8) / Hash Table (1) 1160. Find Words That Can Be Formed by Characters (Easy)\n從LeetCode學演算法 - 40 Array (9) 0238. Product of Array Except Self (Medium)\n從LeetCode學演算法 - 41 Hash Table (2) 0242. Valid Anagram (Easy)\n從LeetCode學演算法 - 42 Backtracking (1) / Tree (8) 0257. Binary Tree Paths (Easy)\n從LeetCode學演算法 - 43 BFS (1) / Queue (2) 1161. Maximum Level Sum of a Binary Tree (Medium)\n從LeetCode學演算法 - 44 Linked List (5) 0160. Intersection of Two Linked Lists (Easy)\n從LeetCode學演算法 - 45 DFS (1) 0200. Number of Islands (Medium)\n從LeetCode學演算法 - 46 BFS (2) / Queue (3) 0199. Binary Tree Right Side View (Medium)\n從LeetCode學演算法 - 47 Array (10) 0204. Count Primes (Easy)\n從LeetCode學演算法 - 48 Trie (1) 0819. Most Common Word (Easy)\n從LeetCode學演算法 - 49 Hash Table (3) 0217. Contains Duplicate (Easy)\n從LeetCode學演算法 - 50 Tree (9) 0226. Invert Binary Tree (Easy)\n從LeetCode學演算法 - 51 BST (4) 0235. Lowest Common Ancestor of a Binary Search Tree (Easy)\n從LeetCode學演算法 - 52 Array (11) 0268. Missing Number (Easy)\n從LeetCode學演算法 - 53 Binary Search (2) 0278. First Bad Version (Easy)\n從LeetCode學演算法 - 54 DFS (2) 0114. Flatten Binary Tree to Linked List (Medium)\n從LeetCode學演算法 - 55 DFS (3) 0236. Lowest Common Ancestor of a Binary Tree (Medium)\n從LeetCode學演算法 - 56 Binary Search (3) 0240. Search a 2D Matrix II (Medium)\n從LeetCode學演算法 - 57 Binary Search (4) 0074. Search a 2D Matrix (Medium)\n從LeetCode學演算法 - 58 Two Pointer (2) 0075. Sort Colors (Medium)\n從LeetCode學演算法 - 59 Backtracking (2) / DFS (4) 0079. Word Search (Medium)\n從LeetCode學演算法 - 60 Backtracking (3) / DFS (5) 0078. Subsets (Medium)\n從LeetCode學演算法 - 61 Dynamic Programming (9) 1140. Stone Game II (Medium)\n從LeetCode學演算法 - 62 Tree (10) 0102. Binary Tree Level Order Traversal (Medium)\n從LeetCode學演算法 - 63 Backtracking (4) / DFS (6) 0077. Combinations (Medium)\n從LeetCode學演算法 - 64 Array (12) / Two Pointer (3) 0080. Remove Duplicates from Sorted Array II (Medium)\n從LeetCode學演算法 - 65 Array (13) 0926. Flip String to Monotone Increasing (Easy)\n從LeetCode學演算法 - 66 Bitwise Operation (3) 0190. Reverse Bits (Easy)\n從LeetCode學演算法 - 67 Bitwise Operation (4) 0191. Number of 1 Bits (Easy)\n從LeetCode學演算法 - 68 Bitwise Operation (5) 0201. Bitwise AND of Numbers Range (Medium)\n從LeetCode學演算法 - 69 Hash Set (1) 0202. Happy Number (Easy)\n從LeetCode學演算法 - 70 Linked List (6) 0203. Remove Linked List Elements (Easy)\n從LeetCode學演算法 - 71 Hash Table (4) 0205. Isomorphic Strings (Easy)\n從LeetCode學演算法 - 72 Linked List (7) 0206. Reverse Linked List (Easy)\n從LeetCode學演算法 - 74 Linked List (8) 0234. Palindrome Linked List (Easy)\n從LeetCode學演算法 - 75 Array (14) 0289. Game of Life (Medium)\n從LeetCode學演算法 - 76 Hash Table (5) 0290. Word Pattern (Easy)\n從LeetCode學演算法 - 77 String (2) 1071. Greatest Common Divisor of Strings (Easy)\n從LeetCode學演算法 - 78 Two Pointer (4) / Binary Search(5) 0392. Is Subsequence (Easy)\n從LeetCode學演算法 - 79 Hash Table (6) 0383. Ransom Note (Easy)\n從LeetCode學演算法 - 80 Linked List (9) 0082. Remove Duplicates from Sorted List II (Medium)\n從LeetCode學演算法 - 81 Backtracking (5) / DFS (7) 0093. Restore IP Addresses (Medium)\n從LeetCode學演算法 - 82 Linked List (10) 0086. Partition List (Medium)\n從LeetCode學演算法 - 83 Dynamic Programming (10) 0091. Decode Ways (Medium)\n從LeetCode學演算法 - 84 Tree (11) / DFS (8) 0116. Populating Next Right Pointers in Each Node (Medium)\n從LeetCode學演算法 - 85 String (3) 1332. Remove Palindromic Subsequences (Easy)\n從LeetCode學演算法 - 86 Hash Table (7) 1331. Rank Transform of an Array (Easy)\n從LeetCode學演算法 - 87 Bitwise Operation (6) 1342. Number of Steps to Reduce a Number to Zero (Easy)\n從LeetCode學演算法 - 88 Hash Table (8) 0575. Distribute Candies (Easy)\n從LeetCode學演算法 - 89 HashTable (9) 1346. Check If N and Its Double Exist (Easy)\n從LeetCode學演算法 - 90 Dynamic Programming (11) / DFS (9) 0576. Out of Boundary Paths (Medium)\n從LeetCode學演算法 - 91 String (4) 0678. Valid Parenthesis String (Medium)\n從LeetCode學演算法 - 92 String (5) 0680. Valid Palindrome II (Easy)\n從LeetCode學演算法 - 93 Tree (12) / DFS (9) 0687. Longest Univalue Path (Easy)\n從LeetCode學演算法 - 94 Hash Table (10) 0438. Find All Anagrams in a String (Easy)\n從LeetCode學演算法 - 95 Dynamic Programming (12) 1143. Longest Common Subsequence (Medium)\n從LeetCode學演算法 - 96 BST (5) 1008. Construct Binary Search Tree from Preorder Traversal (Medium)\n從LeetCode學演算法 - 97 Dynamic Programming (13) 0368. Largest Divisible Subset (Medium)\n從LeetCode學演算法 - 98 Tree (13) / DFS (10) 0129. Sum Root to Leaf Numbers (Medium)\n從LeetCode學演算法 - 99 Tree (14) / DFS (11) 0404. Sum of Left Leaves (Easy)\n從LeetCode學演算法 - 100 Dynamic Programming (14) 1510. Stone Game IV (Hard)\n從LeetCode學演算法 - 101 String (6) 1529. Bulb Switcher IV (Medium)\n從LeetCode學演算法 - 102 Tree (15) / DFS (12) 1530. Number of Good Leaf Nodes Pairs (Medium)\n從LeetCode學演算法 - 103 Tree (16) / DFS (13) / BFS (3) / Queue (4) 0112. Path Sum (Easy)\n從LeetCode學演算法 - 104 Tree (17) / DFS (14) / Backtracking (6) 0113. Path Sum II (Medium)\n從LeetCode學演算法 - 105 Tree (18) / DFS (15) / Backtracking (7) 0437. Path Sum III (Medium)\n從LeetCode學演算法 - 106 Tree (19) / DFS (16) 0563. Binary Tree Tilt (Easy)\n從LeetCode學演算法 - 107 String (7) / Stack (2) 1544. Make The String Great (Easy)\n從LeetCode學演算法 - 108 Tree (20) / DFS (17) 1379. Find a Corresponding Node of a Binary Tree in a Clone of That Tree (Medium)\n從LeetCode學演算法 - 109 Array (15) / Hash Table (11) 1640. Check Array Formation Through Concatenation (Easy)\n從LeetCode學演算法 - 110 Array (16) / Greedy Algorithm (1) 0881. Boats to Save People (Medium)\n從LeetCode學演算法 - 111 DFS (18) / Backtracking (8) 0784. Letter Case Permutation (Medium)\n從LeetCode學演算法 - 112 Binary Search (6) / Newton’s Method 0367. Valid Perfect Square (Easy)\n從LeetCode學演算法 - 113 BFS (4) / Queue (5) 1091. Shortest Path in Binary Matrix (Medium)\n從LeetCode學演算法 - 114 Stack (3) 0946. Validate Stack Sequences (Medium)\n從LeetCode學演算法 - 115 Graph(1) / Union Find (1) 0684. Redundant Connection (Medium)\n從LeetCode學演算法 - 116 Tree (21) / DFS (19) 0814. Binary Tree Pruning (Medium)\n從LeetCode學演算法 - 117 Array (17) 0941. Valid Mountain Array (Easy)\n從LeetCode學演算法 - 118 DFS (20) /BFS (5) / Queue (6) 0934. Shortest Bridge (Medium)\n從LeetCode學演算法 - 119 Graph (2) / DFS (21) 0797. All Paths From Source to Target (Medium)\n從LeetCode學演算法-120 (0547. Number of Provinces) Categories: Graph/Union Find, Level: Medium\nEnglish Version: https://desolve.medium.com/51a78df0670c\n從LeetCode學演算法-121 (0802. Find Eventual Safe States) Categories: Graph/DFS, Level: Medium\nEnglish Version: https://desolve.medium.com/b3b88410d561\n","date":"2019-06-26T00:00:00+08:00","image":"https://learnwithdesolve.netlify.app/img/default-leetcode.webp","permalink":"https://learnwithdesolve.netlify.app/post/learn-algorithm-from-leetcode-0/","title":"從LeetCode學演算法 - 0"},{"content":"一個三十歲的阿宅工程師的自省和觀察\n寫在前面\n子曰：\n「吾十有五而志於學，三十而立，四十而不惑，\n五十而知天命，六十而耳順，七十而從心所欲、不逾矩。」\n這段話或許不少人都能朗朗上口，甚至還有經典的笑話段子用上它，我自然也不例外。而今三十歲生日已過，不能無感。從十幾歲的青蔥少年，到三十歲的阿宅工程師，中間風風雨雨，難以細數。最近讀了一些書，也經歷了一些事情，有一點小小的心得，就在這裡整理分享吧。不同的人對於不同的事情總會有不同的看法，依照自身的經歷和所處的環境對於發生的事件做判斷，進而得出一套自己的處世哲學，這是每個人都會做的事情，也因此，我的看法並不代表這個世界就是這麼一回事，僅代表個人的觀察罷了。\n一、 沒有人有責任對你負責什麼，但你要對自己負責\n相信大學時期大家就有這樣的經歷，最典型的就是分組報告了：\n總有人拖著不認真完成，或者開會時不發表意見，等分到手上的時候才嫌自己的部分太多不好做不好查；更有甚者則是乾脆分好組後整堂課神隱，最後報告日再出來收割的……不過我相信也是有人願意撕破臉將真實的分工責任告訴教授的，所以這種人總還是會有遭受制裁的一天。\n出社會以後呢？\n坦白說其實沒太大區別，如果你想要和誰合作的話，對方未必是個不負責任的人，但他/她可能會遇到其他事情啊！假如你就很放心地交給對方，而不去理會進度，很可能你的事情就會因為其他工作的出現使優先順序往後排，最後結果很可能就是對方有做，但總不會如你所預期的在你想要的時間內弄完就是了。所以說，如果這件事情對你很重要，屬於你自己可以做的部分，不如就自己做完。 屬於別人才能做的部分，請務必盯緊對方，讓他/她知道，\u0026ldquo;I’m watching you.\u0026rdquo;\n另一方面，屬於你自己的責任，請務必好好完成它。\n在評估任務時，請仔細的審視自己的能力和估計會遇到的困難，並提出需求和修正目標，一旦接下來了，就請全力以赴。這是對你自己的尊重，同時也是為你的信用程度加分。沒有人會不喜歡和一個說到做到的人合作 。(但記得別隨便打包票啊！)\n同時，你也要為自己的人生負責。你的第一份工作，可能仰賴或受限 於你的最高學歷的校系 ，但其後在一間公司，你做了什麼案子，學了哪些東西，訓練出什麼樣的技能，這些基本上就和學校無關了。投資自己是最好的投資，在下班或假日放鬆之餘，也可以針對你想要的部分充實自己。\n另外，去運動吧！不要因為被主管凹加班累了就放空自己。\n(不然就會像我現在一樣，暫時從阿宅工程師變成肥宅工程師，Ｘ的。)\n二、 懦弱的選擇比輸還可怕的多，做好完全準備的人才有資格談運氣\n可能有些人知道這兩句話的出處。\n失誤絕對是在所難免，但是做出懦弱的選擇，\n只因為你不希望這回合輸，而放棄了整場比賽，\n這樣的事情我再也沒有做出過了。\n- Tom60229(陳威霖，2017爐石戰記世界冠軍)\n很多時候我們會因為害怕而放棄踏出去那一步。\n因為害怕被拒絕所以不敢讓對方知道自己喜歡他/她；\n因為害怕和人接觸所以放棄主動和人交流；\n因為害怕做新東西會做不出來所以永遠遵照前人留下的做法；\n因為害怕自己其實很弱所以抗拒面對挑戰\u0026hellip;\u0026hellip;等等，\n只因為害怕在這一回合「輸掉」，而選擇保守，選擇待在自己的舒適圈，\n永遠都覺得自己還沒有準備好，殊不知這只是藉口 而已。\n不論是學生時期的考試或者是出社會後的面試、簡報，\n認真說起來，永遠沒有「準備好了」的一天，\n更不用說，機會常常在你「還沒準備好」的時候到來。\n為自己訂下一個階段性的目標，就按部就班地朝著你的目標前行吧！\n當你確認過那是值得的，就放手去做，\n因為其實絕大多數的時候，你並沒有什麼好失去的 。\n沒有人不會失敗，願意正視自己的失敗並從中學習，\n才能為將來的成功鋪路。\n又或者，有些人總說**「要是考試/面試沒考這題就好了」** 或\n「怎麼就這麼剛好挑到我沒準備的題目呢？」\n嗯，那為什麼總是有人有準備到呢？\n「做好完全準備的人才有資格談運氣」這句話看似和前面矛盾，\n其實不然，我覺得就是**「按照自己的規畫，做到你力所能及的準備」** ，\n這樣就可以了。臨場的發揮，仰賴著事前的努力 ，而那並非臨時抱佛腳就可以做好的，而是根基於一點一滴的日常累積。不論如何，有所準備，總會讓今天的你，比昨天的你又更強一點點 ，可能這次問到你不會的東西，但隨著你的累積，你被問到完全不會的東西的可能性就會越來越低。\n（問那種方向完全和先前要求的不同的「問A考B」的情況那就算了，\n這並非你的問題，但人生中偶爾還是會遇到啦XD）\n做好自身的不斷積累，臨場考試/面試/報告時，把你應該有的東西拿出來，剩下的天時地利人和就看天意，就算結果不好，你也問心無愧，\n更重要的是，下一次的你，會更強。\n三、人生總要面臨選擇，選了就往下走，不要花時間在後悔上\n很多時候會聽到這樣的句型：\n「如果當初……」、「要是……就好了」、「為什麼當時不……｣\n但我們沒有哆啦A夢，人類也還沒發明時光機，\n所以這些「如果」通通都沒有任何意義。\n所以，可以花時間檢討，但不要花時間後悔。\n更多時候，我們則是面臨「有一好沒兩好」的狀況。\n大學時上課，教授們常常會提到一個概念，這個概念名為**「Trade Off」** 。\n舉例來說，在相同的電路裡，\n若想要頻率的響應範圍大，也就是頻寬(Bandwidth)範圍大，\n那麼用相同的功率下所能得到的訊號增益(Gain)的倍數就會小，\n反之亦然，兩者相乘大約會等於一個定值。\n也就是說，你想要其中一個，就可能要犧牲掉另一個 。\n人生也是差不多，每個人的時間有限，你將名為時間的籌碼推出去，\n要換什麼東西，是由自己決定的。我們都不是漩渦鳴人，沒辦法開掛用影分身術同時做一堆事情，所以我們必須選一個對我們最重要的去做。\n只要不是傷天害理殺人放火，選什麼並沒有對錯之分，\n所以也不要因為你選A，別人選B，結果選B的功成名就，\n你就覺得當初要是選B會比較好。\n(說不定你選B會更慘呦XD)\n四、掟は破るためにこそある(規則，是為了被打破而存在的)\n「陽泉酒家的傳統，就是顛覆傳統！」\n- 中華一番\n世界上沒有什麼是必然的，如果人生什麼事情都循規蹈矩的話，\n未免太過無趣了一點。\n而那些擁有創造力的人，都不是什麼遵守既有規則的人 。\n看看馬克祖克柏、比爾蓋茲、史蒂夫賈伯斯等人，又有哪個是乖乖牌呢？\n不要把規則都視為理所當然，不妨嘗試看看新的方法，探索更多的可能，\n或許一條嶄新的路就能由此開展也說不定。\n你說很可能失敗？那又如何？\n據統計，台灣新創企業第五年的平均存活率只有57.43%，\n公司營運逾三年、且自認創業成功的創業者更是僅占17%，\n請問你看過哪個是創業失敗就會死的嗎？\n（當然，你去借高利貸的話那當我沒說）\n如果覺得你的想法比起現行的規則好，那就勇敢地去嘗試吧！\n五、不要隨意信仰，如果要信仰的話，信仰自己\n倚天屠龍記當中，有一段描述張無忌向空聞詢問超度的意義：\n“方丈，在下有一事不明，要向方丈請教。人死之后，是否真有鬼魂？”\n空聞沉思半晌，道：“幽冥之事，實所難言。”張無忌道：“然則方丈何以虔誠行法，超度幽魂？”空聞道：“善哉，善哉！幽魂不須超度。人死業在，善有善報，惡有惡報。佛家行法，乃在求生人心之所安，超度的乃是活人。”\n-《倚天屠龍記》第四冊第四十章《不識張郎是張郎》\n世間所有正常的宗教，大多勸人為善，人們透過對於神祇的信仰，\n轉化為內心的安定力量，因此得以支撐心靈。\n但事到臨頭的時候，最能夠直接幫助自己的，還是自己。\n天助自助者，不是嗎？（笑）\n所以說，在你沒有真的看見神明顯靈的時候，\n我個人認為你可以不要信教，\n如果要信的話，就信仰自己吧！相信自己面對困難時能迎難而上，\n相信自己平日的積累能讓你臨場時得以發揮，相信自己一定做得到。\n**相信自己能給自己力量，而無須靠外界支撐。\n常常有人選擇不相信自己，只相信神。\n一旦遇到困難神沒有出現或者安排別人救場，\n他/她的世界就隨之崩塌。**何必呢？不如信仰自己，自己對自己負責，不要每次都要神明幫忙，\n就算祂每次都願意，鐵定也覺得你超煩的！\n結語：自信而不自傲，自知而不自卑\n「尺有所長，寸有所短」，每個人總會有自己擅長和不擅長的部分，\n同時也總會有比自己厲害的人存在，\n所以不要去和別人比較，要做的是和自己比較，將自己的長處發揮出來。\n不要因為一時的成功而膨脹自我，\n也不要因為一次臨場的沒有發揮好就妄自菲薄。\n跌倒了，就趕快拍一拍灰塵再站起來， Don’t cry over spilled milk，\n只要下次別再掉相同的坑就好了。\n這篇文章，寫給三十歲的自己，\n也寫給所有一同在人生的汪洋大海中浮浮沉沉的人們，\n願我們都能讓自己變得更好，活出屬於自己的精彩。\n","date":"2018-09-13T00:00:00+08:00","permalink":"https://learnwithdesolve.netlify.app/post/thirty-stood-firm/","title":"三十而立"}]