從數據結構分java
一。鏈表:node
思路:遞歸調用,調一次,加一次到list中正則表達式
兩個指針,第一個先走k步,第二個不動,而後第一個和第二個一塊兒走,知道第一個到尾節點。數組
思路,主要是調整指針。數據結構
思路:兩個鏈表先比較頭,頭比較小的作新鏈表的頭,新鏈表的next遞歸調用本函數。app
思路:三步走。第一步:鏈接到後面。第二步:構建隨機指針。第三部:拆除鏈接函數
最後記得把pClonedNode賦值給一個pClonedHead保存頭結點。用於最後的返回。測試
見第四。ui
思路:分別遍歷兩個鏈表,獲得他們的長度差,而後長鏈表走這個差值的步數。而後長鏈表和短鏈表一塊兒走,直到它們碰到,返回。spa
思路:用兩個指針,一個快指針一下走兩步,一個慢指針,一下走一步。而後走着直到它們相遇。而後把慢指針從頭走,快指針一步一步走,直到它們相遇就是環的入口節點。
思路:特別要注意須要保存節點到一個ListNode中,以防後面修改移動後找不到指針。須要Pre節點一個。指向前一個節點,pNode指向當前節點。因爲當前節點的前一個是沒有的,因此建立一個頭節點val爲-1.而後把它指向node。
二。數組
思路:從最右邊最上邊開始比較,target比之大,row++;比之小,col--,不然返回true
思路:本題考查二分查找。兩個下標,一頭一尾,循環條件是while(array[index1]>=array[index2])循環結束條件是index2-index1==1.循環的過程當中要不停的建立數組的重點,不停的去二分查找,若是中點值大於等於前半部分(隱含的條件是大於第二部分),那麼中點的值就位於第一部分,第一部分的下標就要變換爲mid。同理,若是中點值小於第一部分而且小於等於第二部分,那中點值必定位於第二部分,對於特殊狀況,如// 3 3 3 0 3, 3 0 0 0 3兩種狀況沒法判斷哪一個屬於旋轉部分。就須要經過普通的辦法來查找。
思路1:藉助一個輔助數組,遍歷第一遍把奇數放進去,第二遍把偶數放進去,再傳遞給原來的數組。
思路2:待思考
思路:遍歷數組的時候保存兩個值,一個是數組中的一個數字,另外一個是次數。但咱們遍歷到下一個數字的時候,若是下一個數字和咱們以前保存的數字相同,次數加一,不一樣次數減一:若是次數爲0,那麼咱們須要保存下一個數字,並把次數設爲1,有與咱們要找的數字出現的次數比其餘的數字次數之和還要多,MAME要找的數字確定是最後一次吧次數設爲1對應的數字。另外要驗證該數字是否大於長度的一半。
思路:快排+二分查找
思路:兩個變量,一個存當前的和,另外一個存最大值,而後遍歷數組,若是curSum小於0,就等於當前數組的值,不然就curSum+=num【i】,若是curSum比max大的話就更新。
思路:主要是考察對比較器的認識,比較器裏面定義兩個字符串,用字符串自帶的比較器比較便可。要比較的對象是o1+o2與o2+o1兩個字符串。
思路:參考歸併排序。
思路:改進的二分查找,注意等於的時候還要看狀況移動指針,覺得不必定是恰好是邊界。
思路:全部數組元素的異或結果就是兩個出現一次的數字的異或結果,因此把這兩個數字分別劃分到兩個數組裏,每一個數組的異或結果就是這個數,劃分規則是根據第一次出現1的位數那一位是0仍是1。例如數組{2,4,3,6,3,2,5,5}異或的結果是0010,咱們就根據倒數第二位是0仍是1來劃分。注意位數是從後往前的。
思路:有點相似二分查找或者partition過程,不一樣的是,兩個指針一個是從頭開始,另外一個從第二個元素開始。記錄small+big的和爲cursum,若是這個值等於要求的sum和的話,那麼就找到一個,small++;若是小於sum那麼big++,cursum也要加上big處的數,大於的話small也要++,可是cursum要把small去掉,這個時候可能就到了邊界,注意此處的邊界是mid=()sum+1)/2,從1和2開始循環
思路:準備兩個指針,一個指向頭,一個指向尾,而後若是頭的值和尾的值的和與要找的數相等的話就找到了,而後再找伺機最小的,注意指針的移動。若是不等,那麼 若是和大於num,那麼後面的指針前移,小於前面的指針後移。
思路:由於數組中的數字是從0-n-1,排序後每一個數字和它對應的下標相等,所以咱們能夠遍歷數組若是和下標不對應,就交換直到對應。
思路:不妨定義C【i】=A[0]*A[1]*...A[I-1],D[I]=A[i+1]*...A[n-2]*A[N-1]。c能夠自上而下的順序計算出來,即C【i】=C[I-1]*A[I-1],D能夠經過自下而上計算出來,即D【i】=D【i+1】*A【i+1】;
從代碼上看,第一個正序,第二個從後往前,注意第二次計算順帶把第一個的帶進去了,result數組的最後一個值和C數組的最後一個值是相等的,看圖就明白了。
思路:以{2,3,4,2,6,2,5,1}分析,主要要用到雙端隊列,在java中就是linkedList,數組的第一個數字是2,存入隊列。第二個數字是3,因爲它比前一個數字2大,所以2不可能成爲滑動窗口的最大值。先把2從隊列裏刪除,再把3存入隊列。何時結束呢,當一個數字的下標與當前處理的數字的下標之差大於或者等於滑動窗口的大小時,這個數字已經從窗口劃出,能夠從隊列中刪除了。
思路:分三步,1:把數組排序;2.統計數組中0的個數;3.統計排序以後的數組中相鄰數字之間的空缺總數。注意出現對子直接返回false。
三。字符串
思路:從後往前,設一個新的strbuilder,新str的長度是原來的長度+空格長度*2;從後往前挨着替換。因爲是在原有的sb上替換,因此只能從後往前。須要兩個下標,分別從後往前,新的下標三部頂舊下標的一步。已遠數組的大小進行循環。
思路:暴力遞歸。不停的去切換下標(下一個字符),而後遞歸調用。遞歸終止的條件是下標到了length-1.最後集合裏沒有的有的話再添加。(相似的題,求子序列,思路也是找下一個,能夠選擇加仍是不加這個字符串)
一個哈希表,沒有的話置爲1,有的話+1,最後找等於1的。
思路:主要是一個頭尾互換函數不停的調用。先總體調用。而後分出的兩塊分別調用。
思路:與上題有點像,一樣是字符串翻轉的應用。
注意:思路是result=result*10+c-'0';可是要注意第一個字符有正負號的狀況,下標要移動,若是第一個是+或者-可是長度只有1也要返回0;遍歷的過程當中也要判斷是否在0-9中間。
思路:主要分爲兩種狀況:模式的第二個字符(1)是*(2)第二個不是*,而後再分狀況遞歸調用,移動下標。
正則表達式瞭解一下
思路:回溯法,不停的往前走兩層循環,裏面用遞歸,回溯,分別取i-1,i+1,j-1,j+1,k取下一個字符,暴力遍歷,便可,若是訪問成功記得修改flag
四。二叉樹,二叉搜索樹
思路:先把中序遍歷的下標,健爲中序中的數字,值爲下標放入hashmap中。主要是下標變換.先創建根節點,root.left=遞歸調用。root.rigth=遞歸調用。
方法中的參數有(pre,pi,pj,ni,nj)index=map.get(pre[pi]).left=(pre,pi+1,pi+index-ni,ni,index-1) right=(pre,pi+index-ni+1,pj,index+1,nj)
思路:先判斷根是否相等,相等的話再比較左孩子和右孩子,左右的比較確定是遞歸。固然不是的話,咱們還要把左孩子和root2樹作一樣的對比。
遞歸,左右孩子互換,而後調用本身的方法直到終止條件。
思路:把節點放一個隊列裏(linnkedList)有左子樹就把左子樹放入,有右子樹就把右子樹放入隊列,而後再依次彈出,入隊和出隊是同在一個循環裏面的。出隊的時候放入ArrayList中。,要是有左右孩子就要把左右孩子依次放入隊列。總體看就是出隊的時候伴隨着入隊。出隊的元素就是之前入隊造成的。
思路:整體是遞歸思路。首先要想清楚二叉搜索樹的性質:全部的左子樹的值小於根節點的值,全部的右子樹的值大於根節點。後序遍歷的特色是:根節點在最後。
因而從頭開始遍歷,直到找到第一個數比根節點大的值的下標,若是以後的值有比根節點小的那麼直接返回false。if(i>start)遞歸左子樹 isPostBST(sequence,start,start+i-1);if(j<end) isPostBST(sequence,start+i,end-1);
思路:整體遞歸思路。兩個ArrayList一個放全部路徑,一個放一條當前路徑。須要用到遞歸,每當到葉子節點時候就要判斷是否等於target,target遞歸的過程當中不停的變換,findPath(root,target)target不不停的減去root值。開始的時候要把root.val放進去。最後到葉子節點記得把road(當前路徑的list)的最後一個元素刪掉(若是等於已經添加進roads裏面了,若是沒有找到就把最後一個值捨去,而後返回上一層節點)
思路:要注意點一點是要把T初始的TreeNode賦值給一個變量Head。而後遞歸調用,左節點去找,有節點去找。而後找到左孩子的最右邊節點和右孩子最左邊節點。而後把根節點和左孩子最右節點相連,右孩子最左和根節點相連。最後返回Head。
思路:遞歸。哪一個孩子的深度大,就把這個深度加上本身自己的1,就是實際的深度。
思路:與上題思路基本相同。可是要加上一句,if左右孩子深度差超過1,那麼return false。
思路:一個節點若是有右孩子,那麼它的中序遍歷的下一個節點就是它的右孩子的最左邊的節點,若是沒有右孩子,它的中序遍歷的下一個節點就須要:經過next向上遍歷直到它是它父節點的左孩子爲止。
思路:準備兩棵如出一轍的樹,這個題來講就是第一顆樹的左孩子和第二課樹的左孩子對稱而且,第一棵樹的右孩子和第二棵樹的左孩子對稱。而後遞歸,注意跳出循環的條件。
思路:準備兩個棧(linkedList或者Stack),一個放正序TreeNode,另外一個放逆序TreeNode,正序彈出來的時候,按從左到右的順序壓入,而後逆序棧彈出的就是逆序,而後按從右往左的順序壓棧,兩個棧相互交替完成。而後每次循環須要一個list。用來添加一行的數字。(注意循環條件,當任意一個不爲空就能夠循環)
思路:與上一題有點像,不一樣的是此處只須要一個數據結構,一個隊列便可。須要準備一個num遍歷存儲隊列的大小,當num>0時候要不停的出隊,固然出隊的同時它的孩子也要分別入隊。其餘操做基本相同。另外,隊列使用linkedList。(隊列和棧均可以使用)
思路:序列化是TreeNode到String字符串的過程,反序列化反之。注意用先序遍歷。
序列化:遞歸調用,String res=root.val+",";res+=serialize(root.left) ;res=serialize(root.right);遞歸終止條件是root==null 此時要把"#,"返回。
反序列化:一樣遞歸,首先要經過「,」分隔爲一個字符串數組,而後用一個下標index表示字符串的下標,經過下標的不停移動來遞歸調用。TreeNode node=new TreeNode(Integer.parseInt(s[index])),遞歸終止條件是 if(s[index]=="#") return null,而且index++;
思路:整體思路是中序遍歷,左中右,而後遞歸,左邊若是找到了那麼return,右邊找到了右邊return。中間是index++;而後if(index==k)return pRoot;
五。棧,隊列
思路:push直接進第一個棧,出棧的話,若是stack2不爲空纔出,爲空的話就把stack1以此pop彈出並壓入2.
思路:準備兩個棧,第一個放其餘元素,第二個放最小元素,push過程當中,若是minStack爲空或者新元素比minStack的棧頂元素小,則把新元素push進去,而後把新元素push進第一個棧。pop過程當中,若是第一個棧彈出的元素和minStack的棧頂元素相同,則須要把minStack元素和第一個棧的元素一併彈出。
獲取最小值的操做就是minStack.peek()。
思路:準備一個輔助棧。先壓入第一個要壓入的元素。若是下一個要彈出的元素不等於棧頂,則要壓棧,直到找到下一個要彈出的元素,若是下一個要彈出的元素等於棧頂元素,直接pop彈出。若是到最後都沒找到就返回false。要注意兩個下標:一個是pop數組的,這個是整個for循環的下標,另外一個是push數組的下標,這個index是push數組有沒有到頭的一個標誌。
六。二級制玩法
思路:一個數和這個數減去1取與的次數就是二進制1的個數。
七。矩陣
思路:start爲起點,因爲起點始終都是0,0或者1,1這種,至關於0,0的位置,注意循環條件是rows>start*2&&cols>start*2,向下打印的時候,須要加入判斷:endY>start,向左的時候:endY>start&&endx>start 向上的時候:endy>start+1&&endx>start。另外須要注意的是,轉一圈,也就是循環一次,start要加一。而且每次endx=cols-1-start,endy=rows-1-start;
思路:見字符串分類裏面。
思路:見數組
思路:二、三、5分別有本身的一個下標,每個醜數都是另外一個醜數乘以2/三、或者5。要用本身下標處的值乘以本身的2/三、或者是5,而後找他們中間的最小值放入list中,若是這個最小值和剛纔獲得的數字相等的話,那麼下標就++。
須要的輔助空間:三個num保存有可能進入到list中的醜數,三個index保存2/3/5的下標,一個Arraylist保存結果。