stack专题
20 Valid Parentheses
問題:沒有意識到字符串中只包含字符:’(‘, ‘)’, ‘{‘, ‘}’, ‘[’ and ‘]’
代碼:git代碼
682 Baseball Game
問題:錯誤在+操作:top1 先彈出,top2 再彈出,還原到stack里面的時候,要先放top2,再放top1,最后放score = top1+top2;從優秀代碼中學習到的優點:誰說棧就只能用stack了?linkedList也可以;每種操作都優先考慮放入棧中,再考慮加入到sum中。這是我沒有注意的,我的思考順序就很隨便了。
public int calPointsV2(String[] ops) {int sum = 0;LinkedList<Integer> list = new LinkedList<>();for (String op : ops) {if (op.equals("C")) {sum -= list.removeLast();}else if (op.equals("D")) {list.add(list.peekLast() * 2);sum += list.peekLast();}else if (op.equals("+")) {list.add(list.peekLast() + list.get(list.size() - 2));sum += list.peekLast();}else {list.add(Integer.parseInt(op));sum += list.peekLast();}} return sum;}代碼:git代碼
496 Next Greater Element I
問題:這道題目,自己首先是理解題意有問題。對于nums1中的每個元素,先查找num2中自己(這個元素)所在位置,從右側開始查找,最近的一個比當前元素大的元素。我理解成對應的下標了。從優先代碼學習到觀察之后能發現在一個遞減序列中,遇到一個大的元素,那這個元素就是這個序列中每個元素的下一個更大元素。
代碼:git代碼
735 Asteroid Collision
問題:我的問題是在寫代碼的時候沒有把if 情況合并起來,寫出來的代碼不夠簡潔。
代碼:git代碼
103 Binary Tree Zigzag Level Order Traversal
問題:遍歷節點和添加值到結果中這兩個步驟要分清楚
代碼:git代碼
144 Binary Tree Preorder Traversal
問題:if條件的位置影響程序的執行時間
代碼:git代碼
402 Remove K Digits
問題:這道題目最后卡在了超時問題上。參考了最佳答案。原始思路是:每次刪除一位數字,得到新的最小num,再刪除,直到刪除k個數字。需要求每次刪除一位數字,如果得到最小的num:從高位開始刪除,遇到比當前最小值大的刪除操作就停止。例如1432219刪除第一位的步驟是:刪除1,得到:432219;刪除4,得到:132219;刪除3,得到142219。因為142219>132219,所以停止本次循環。接著使用132219,再刪除一位,步驟是:刪除1,得到32219;刪除3,得到12219,;刪除2得到:13219;13219 > 12219 ,所以停止本次循環。依次處理k次。時間復雜度是O(nk)。
參考代碼:看了discussion,思路是這樣的。往棧里面push元素。如果當前元素比棧頂元素小,則pop。每一次pop,k需要減1;一直到當前元素大于棧中的元素。前提條件是k>0。
代碼:代碼位置
394 Decode String
問題:看了題目之后首先想到先計算內層的[],再計算外層的[]。始終用一個變量來記錄最后的結果。分析遇到數字應該做什么,遇到[、]、字母分別應該做什么,就能得到代碼。即使思路想明白了,在代碼實現上一點小的區別和改動,就能得到流暢的代碼和不優雅的代碼??磀ecodeStringV2和decodeStringV3的區別
代碼
385 Mini Parser
問題:本題和上一題類似,也有嵌套。區別是本題有效的全是數字。我學習到的是遞歸思路。上題分析了,找到遇到不同類型的字符時候怎么處理。還有一種是遞歸。對于:[123,[456,[789]]] ,我們可以先處理123,[456,[789]],進而可以處理:123 和 [456,[789]];對于123,直接處理轉為int;對于[456,[789]],我們可以先處理456,[789];進而分別處理456和[789]。對于[789],我們處理789。不斷遞歸,不斷縮小問題。
遞歸思想:先處理退出情況。處理不斷遞歸對結果的影響。
341. Flatten Nested List Iterator
問題:把嵌套的int展開。這里也是一個遞歸思想。
代碼
331 Verify Preorder Serialization of a Binary Tree
問題:題目中說明給定的字符串是一個二叉樹先序遍歷的結果。判斷是不是一顆有效的二叉樹。這里注意兩點:1 樹的葉子節點一定是空節點;2 可能會有多余的節點。
我的思路:第一感覺是用stack。我按著操作順序走一遍,覺得自己應該能寫出代碼;發現寫不出來;后來我就分開訪問節點與判斷節點是否有效,寫出了第一版的代碼。寫完后發現,因為是一顆二叉樹,所以最終就是判斷preorder[0]是不是一個有效節點就可以了。所以合并了訪問節點與判斷節點是否有效的操作。寫出來第一版的遞歸代碼。不滿意的地方是index使用了全局變量,處理得不好。
別人的代碼:所有的葉子節點是空節點,說明這顆二叉樹是一顆滿樹。二叉樹滿樹有一個特性:葉子節點數量=非葉子節點數量+1。利用二叉樹的性質。聰明。當然還有些解決方法用了入度、出度的概念,我就沒有繼續學習了。思維擴散開來就好了。
代碼
456 132 Pattern
問題:輸入int數組,判斷數組是否包含下標:i<j<k,數值a[i]<a[k]<a[j]就返回true。至于如何能想到這么解決,我想應該是題目做多了,自然就有感覺了吧。
代碼
739 Daily Temperatures
問題:輸入: [73, 74, 75, 71, 69, 72, 76, 73],輸出[1, 1, 4, 2, 1, 1, 0, 0]。直觀的解決方法很簡單。兩層循環,當i確認的時候,j比i大,找到第一個nums[i]<nums[j]的j,r[i] = j-i。時間復雜度是n2。
學習:使用棧,幾乎是O(n)的復雜度。自己也想過放棧里面,但是想著想著就不知道怎么做了,看著別人這么做,覺得好簡單。遇到下標i,放入棧中,接著向后遍歷(因為符合條件的元素肯定在后面)。當遇到nums[i]>nums[棧頂元素]的情況下,就是找到答案了。當然可能多個元素,符合條件的下標都是i,所以需要循環棧。需要處理的元素放入棧,每遍歷一個元素,看這個元素是否符合棧內元素的要求。和456題有點類似。
503 Next Greater Element II
問題:這是一個可循環的數組,找到每個元素下標最接近的下一個比較大的元素。這依然是一道找到較大值的題目。和上一個題目類似,用stack類解決。我的思路是先找一遍,再找一遍。循環兩次,因為畢竟是個循環數組。
public int[] nextGreaterElements(int[] nums) {int[] result = new int[nums.length];Stack<Integer> stack = new Stack<Integer>();for (int i = 0; i < nums.length; i++) {result[i] = -1;while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) {result[stack.pop()] = nums[i];}stack.push(i);}for (int i = 0; i < nums.length - 1; i++) {while (!stack.isEmpty() && nums[i] > nums[stack.peek()]) {result[stack.pop()] = nums[i];}}return result;}學習:有人總結了循環數組問題的解決思路。方法一:將原始數組擴大兩倍,當做普通問題處理。方法二:借助棧思想。就是上述代碼,只是不太優雅。參考代碼中的nextGreaterElementsV3。
代碼
71 Simplify Path
問題:這是關于文件夾路徑簡化的問題。
總結的規律是:大小寫區分;”/字母”這是一級目錄; “/.”可以忽略 ;”/..”回退一級目錄。題目思考的思路是按照一個字符一個字符去思考。思考遇到不同類型的字符,應該做什么操作。代碼經過不斷合并if條件,得到最后的代碼。
學習:有人思考的角度是把字符串按/分隔后,考慮字符的有效性和無效性。代碼簡潔了很多。只是執行速度慢了。
public String simplifyPathV2(String path) {Deque<String> stack = new LinkedList<String>();for(String str : path.split("/")){if(str.equals("..") && !stack.isEmpty()){stack.pop();}else if(!str.equals("..") && !str.equals(".") && !str.equals("")){stack.push(str);}}String r = "";for(String dir : stack){r = "/"+dir+r;}return r==""?"/":r;}代碼
173 Binary Search Tree Iterator
問題:這是關于二分查找樹的一個遍歷器,要求實現hasNext方法和next方法,時間要求平均是O(1),空間要求是O(h),h是樹的高度。根據二分查找樹的定義,我們知道所有左子樹節點的值小于根節點;所有右子樹節點的值大于根節點。當next方法要求依次返回最小值的時候,我們知道肯定是先返回左子樹的值,再返回節點值,最后返回右子樹上的值。只是在實現的時候不能在空間要求下實現。
學習:思路一:用stack存儲從根節點開始的所有左節點。當next被調用的時候,直接從stack pop節點tmpNode,返回tmpNode的值。在返回之前,將tmpNode.right作為根節點再次處理存入stack。我的問題是總想弄一個curNode,想怎么在三種狀態之間切換(左子節點、當前節點值、右子節點)
學習:思路二:看到一個有當前節點版本的。當前節點與要返回值的節點不是一個節點。這是重點
public class BSTIteratorV3 {private Stack<TreeNode> stack;private TreeNode cur = null;public BSTIteratorV3(TreeNode root){cur = root;stack = new Stack<TreeNode>();}public boolean hasNext() {return !stack.isEmpty() || cur !=null;}public int next(){while(cur!=null){stack.push(cur);cur = cur.left;}TreeNode node = stack.pop();//這一部是沒有想到的cur = node.right;return node.val;} }94 Binary Tree Inorder Traversal
問題:中序遍歷二叉樹。整個解題思路與上一題目完全相同。可以實現一下遞歸版本與迭代版本。
代碼
總結
- 上一篇: bzoj1679[Usaco2005 J
- 下一篇: 什么是word2vector