摘要:寫(xiě)在最前面導(dǎo)師貪腐出逃美國(guó),兩年未歸,可憐了我。拿了小米和美團(tuán)的,要被延期,失效,工作重新找。把準(zhǔn)備過(guò)程紀(jì)錄下來(lái),共勉。
寫(xiě)在最前面
導(dǎo)師貪腐出逃美國(guó),兩年未歸,可憐了我。拿了小米和美團(tuán)的offer,要被延期,offer失效,工作重新找。把準(zhǔn)備過(guò)程紀(jì)錄下來(lái),共勉。
二叉樹(shù)的基礎(chǔ) 結(jié)點(diǎn)定義public class TreeNode{ int val; TreeNode left; TreeNode right; public TreeNode(int val){ this.val = val; } }二叉樹(shù)的遍歷 前序遍歷
前序遍歷,遞歸法
public static void preorderTraversalRec(TreeNode root) { if(root == null){ return; } System.out.print(root.val + " "); preorderTraversalRec(root.left); preorderTraversalRec(root.right); }
前序遍歷,迭代法
思路:借助一個(gè)棧
public static void preorderTraversal(TreeNode root) { if(null == root){ return; } Stack中序遍歷stack = new Stack<>(); stack.push(root); while(!stack.empty()){ TreeNode cur = stack.pop(); System.out.println(cur.val); //后入先出,因而先壓右結(jié)點(diǎn),再壓左結(jié)點(diǎn) if(null != cur.right){ stack.push(cur.right); } if(null != cur.left){ stack.push(cur.left); } } }
中序遍歷,遞歸法
public static void inorderTraversalRec(TreeNode root) { if(null == root){ return; } inorderTraversalRec(root.left); System.out.print(root.val + " "); inorderTraversalRec(root.right); }
中序遍歷,迭代法
public static void inorderTraversal(TreeNode root) { if(null == root){ return; } Stack后序遍歷stack = new Stack<>(); TreeNode cur = root; while(true){ while(cur != null){ stack.push(cur); cur = cur.left; } if(stack.empty()){ break; } cur = stack.pop(); System.out.print(cur.val + " "); cur = cur.right; } }
后序遍歷,遞歸法
public static void postorderTraversalRec(TreeNode root) { if(null == root){ return; } postorderTraversalRec(root.left); postorderTraversalRec(root.right); System.out.print(root.val + " "); }
后序遍歷,迭代法
public static void postorderTraversal(TreeNode root){ if(null == root){ return; } Stacks = new Stack (); Stack output = new Stack<>(); s.push(root); while(!s.empty()){ TreeNode cur = s.pop(); output.push(cur); if(cur.left != null){ s.push(cur.left); } if(cur.right != null){ s.push(cur.right); } } while(!output.empty()){ System.out.print(output.pop().val + " "); } }
分層遍歷
public static void levelTraversal(TreeNode root) { if(null == root){ return; } Queue求二叉樹(shù)結(jié)點(diǎn)的個(gè)數(shù)queue = new LinkedList<>(); queue.push(root); while(!queue.empty()){ TreeNode cur = queue.removeFirst(); System.out.print(cur.val + " "); if(cur.left != null){ queue.add(cur.left); } if(cur.right != null){ queue.add(cur.right); } } }
遞歸解法 時(shí)間復(fù)雜度O(n)
public static int getNodeNumRec(TreeNode root){ if(null != root){ return 0; } return getNodeNumRec(root.left) + getNodeNumRec(root.right) + 1; }
迭代解法 時(shí)間復(fù)雜度O(n)
思路:與層級(jí)遍歷相同,遍歷的過(guò)程中紀(jì)錄結(jié)點(diǎn)數(shù)
public static int getNodeNum(TreeNode root){ if(null != root){ return 0; } int count = 1; Queue求二叉樹(shù)的深度(高度)queue = LinkedList<>(); queue.add(root); while(!queue.empty()){ TreeNode cur = queue.remove(); if(cur.left != null){ queue.add(cur.left); count++; } if(cur.right != null){ queue.add(cur.right); count++; } } return count; }
遞歸解法 時(shí)間復(fù)雜度O(n)
public static int getDepthRec(TreeNode root) { if(null != root){ return 0; } int leftDepth = getDepthRec(root.left); int rightDepth = getDepthRec(root.right); return Math.max(leftDepth, rightDepth) + 1; }
迭代解法 時(shí)間復(fù)雜度O(n)
public static int getDepth(TreeNode root){ if(null != root){ return 0; } int depth = 0; int curLevelNodes = 1; int nextLevelNodes = 0; Queue求二叉樹(shù)第K層的節(jié)點(diǎn)個(gè)數(shù)queue = new LinkedList<>(); queue.add(root); while(!queue.empty()){ TreeNode cur = queue.remove(); curLevelNodes--; if(cur.left != null){ nextLevelNodes++; queue.add(cur.left); } if(cur.right != null){ nextLevelNodes++; queue.add(cur.right); } if(curLevelNodes == 0){ depth++; curLevelNodes = nextLevelNodes; nextLevelNodes = 0; } } return depth; }
遞歸解法
思路:求以root為根的k層節(jié)點(diǎn)數(shù)目 等價(jià)于 求以root左孩子為根的k-1層(因?yàn)樯倭藃oot那一層)節(jié)點(diǎn)數(shù)目 加上 以root右孩子為根的k-1層(因?yàn)樯倭藃oot那一層)節(jié)點(diǎn)數(shù)目
public static int getNodeNumKthLevelRec(TreeNode root, int k) { if(null != root || k < 0){ return 0; } if(k == 1){ return 1; } int leftNodeNumKth = getNodeNumKthLevelRec(root.left, k - 1); int rightNodeNumKth = getNodeNumKthLevelRec(root.right, k - 1); return leftNodeNumKth + rightNodeNumKth; }
迭代法
思路:與求解樹(shù)深度的解法相同,需要
public static int getNodeNumKthLevel(TreeNode root, int k){ if(root == null || k < 0){ return 0; } Queue求二叉樹(shù)中葉子節(jié)點(diǎn)的個(gè)數(shù)queue = new LinkedList<>(); queue.add(root); int curLevelNodes = 1; int nextLevelNodes = 0; while(!queue.empty && k > 0){ TreeNode cur = queue.remove(); curLevelNodes--; if(cur.left != null){ queue.add(cur.left); nextLevelNodes++; } if(cur.right != null){ queue.add(cur.right); nextLevelNodes++; } if(curLevelNodes == 0){ curLevelNodes = nextLevelNodes; nextLevelNodes = 0; k--; } } return curLevelNodes; }
迭代法
public static int getNodeNumLeaf(TreeNode root) { if(root == null){ return 0; } Queue兩個(gè)二叉樹(shù)之間的關(guān)系 判斷兩棵二叉樹(shù)是否相同的樹(shù)。queue = new LinkedList<>(); queue.add(root); int leafNodeNum = 0; while(!queue.empty()){ TreeNode cur = queue.remove(); if(cur.left != null){ queue.add(cur.left); } if(cur.right != null){ queue.add(cur.right); } if(cur.left == null && cur.right = null){ leafNodeNum++; } } return leafNodeNum; }
遞歸法
public static boolean isSameRec(TreeNode r1, TreeNode r2) { if(r1 == null && r2 == null){ return true; } if(r1 == null || r2 == null){ return false; } if(r1.val != r2.val){ return false; } boolean leftRes = isSameRec(r1.left, r2.left); boolean rightRes = isSameRec(r1.right, r2.right); return leftRes && rightRes; }
迭代法
思路:遍歷一遍,比對(duì)即可
public static boolean isSame(TreeNode r1, TreeNode r2) { if(r1 == null && r2 == null){ return true; } if(r1 == null || r2 == null){ return false; } Stack判斷二叉樹(shù)是不是平衡二叉樹(shù)s1 = new Stack<>(); Stack s2 = new Stack<>(); s1.push(r1); s2.push(r2); while(!s1.empty() && !s2.empty()){ TreeNode n1 = s1.pop(); TreeNode n2 = s2.pop(); if(n1 == null && n2 == null){ continue; }else if(n1 != null && n2 != null && n1.val == n2.val){ s1.push(n1.right); s1.push(n1.left); s2.push(n2.right); s2.push(n2.left); }else{ return false; } } return true; }
遞歸解法
思路: (1)如果二叉樹(shù)為空,返回真 (2)如果二叉樹(shù)不為空,如果左子樹(shù)和右子樹(shù)都是AVL樹(shù)并且左子樹(shù)和右子樹(shù)高度相差不大于1,返回真,其他返回假
public static boolean isAVLRec(TreeNode root) { if(root == null){ return true; } if(Math.abs(getDepthRec(root.left) - getDepthRec(root.right)) > 1){ return false; } return isAVLRec(root.left) && isAVLRec(root.right); }樹(shù)的鏡像 判斷兩個(gè)樹(shù)是否互相鏡像
public static boolean isMirrorRec(TreeNode r1, TreeNode r2){ if(r1 == null && r2 == null){ return true; } if(r1 == null || r2 == null){ return false; } if(r1.val != r2.val){ return false; } return isMirrorRec(r1.left, r2.right) && isMirrorRec(r1.right, r2.left); }求樹(shù)的鏡像
遞歸解法
(1)如果二叉樹(shù)為空,返回空
(2)如果二叉樹(shù)不為空,求左子樹(shù)和右子樹(shù)的鏡像,然后交換左子樹(shù)和右子樹(shù)
破壞原來(lái)的樹(shù)
public static TreeNode mirrorRec(TreeNode root) { if(root == null){ return null; } TreeNode left = mirrorRec(root.left); TreeNode right = mirrorRec(root.right); root.left = right; root.right = left; return root; }
2.保存原來(lái)的樹(shù)
public static TreeNode mirrorCopyRec(TreeNode root) { if(root == null){ return null; } TreeNode newRoot = new TreeNode(root.val); newRoot.left = mirrorCopyRec(root.right); newRoot.right = mirrorCopyRec(root.left); return newRoot; }
迭代解法
破壞原來(lái)的樹(shù)
public static void mirror(TreeNode root) { if(root == null){ return; } Stackstack = new Stack (); stack.push(root); while(!stack.empty()){ TreeNode cur = stack.pop(); TreeNode tmp = cur.left; cur.left = cur.right; cur.right = tmp; if(cur.left != null){ stack.push(cur.left); } if(cur.right != null){ stack.push(cur.right); } } }
不能破壞原來(lái)的樹(shù),返回一個(gè)新的鏡像樹(shù)
public static TreeNode mirrorCopy(TreeNode root){ if(root == null){ return null; } Stack求二叉樹(shù)中兩個(gè)節(jié)點(diǎn)的最低公共祖先節(jié)點(diǎn)stack = new Stack<>(); Stack newStack = new Stack<>(); stack.push(root); TreeNode newRoot = new TreeNode(root.val); newStack.push(newRoot); while(!stack.empty()){ TreeNode cur = stack.pop(); TreeNode newCur = newStack.pop(); if(cur.left != null){ stack.push(cur.left); newCur.right = new TreeNode(cur.left.val); newStack.push(newCur.right); } if(cur.right != null){ stack.push(cur.right); newCur.left = new TreeNode(cur.right.val); newStack.push(newCur.left); } } return newRoot; }
遞歸法
思路:1. 如果其中一個(gè)結(jié)點(diǎn)為根結(jié)點(diǎn),則返回根結(jié)點(diǎn)
如果一個(gè)左子樹(shù)找到,一個(gè)在右子樹(shù)找到,則說(shuō)明root是唯一可能的最低公共祖先
其他情況是要不然在左子樹(shù)要不然在右子樹(shù)
public static TreeNode getLastCommonParentRec(TreeNode root, TreeNode n1, TreeNode n2) { if (root == null || n1 == null || n2 == null) { return null; } if(root.equals(n1) || root.equals(n2)){ return root; } TreeNode commonInLeft = getLastCommonParentRec(root.left, n1, n2); TreeNode commonInRight = getLastCommonParentRec(root.right, n1, n2); if(commonInLeft != null && commonInRight != null){ return root; } if(commonInLeft == null){ return commonInRight; } if(commonInRight == null){ return commonInLeft; } return root; }
迭代法
public static TreeNode getLastCommonParent(TreeNode root, TreeNode n1, TreeNode n2){ if(root == null || n1 == null || n2 == null){ return null; } Listlist1= new ArrayList<>(); List list2 = new ArrayList<>(); boolean res1 = getNodePath(root, n1, list1); boolean res2 = getNodePath(root, n2, list2); if(!res1 || !res2){ return null; } Iterator iter1 = list1.iterator(); Iterator iter2 = list2.iterator(); TreeNode last = null; while(iter1.hasNext() && iter2.hasNext()){ TreeNode tmp1 = iter1.next(); TreeNode tmp2 = iter2.next(); if(tmp1 == tmp2){ last = tmp1; }else{ break; } } return last; } private static boolean getNodePath(TreeNode root, TreeNode n, List path){ if(root == null){ return false; } path.add(root); if(root == n){ return true; } boolean found = false; found = getNodePath(root.left, n, path); if(!found){ found = getNodePath(root.right, n, path); } if(!found){ path.remove(root); } return found; }
本章參考http://blog.csdn.net/fightfor...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70112.html
摘要:很多前端同學(xué)在看到數(shù)據(jù)結(jié)構(gòu)和算法后會(huì)有一定的抵觸心理,或者嘗試去練習(xí),但是被難倒,從而放棄。本文選擇的數(shù)據(jù)結(jié)構(gòu)和算法的類別均是出現(xiàn)頻率最高,以及應(yīng)用最廣的類別。面試這是非?,F(xiàn)實(shí)的一點(diǎn),也是很多前端學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)和算法的原因。 一、導(dǎo)讀 據(jù)我了解,前端程序員有相當(dāng)一部分對(duì)數(shù)據(jù)結(jié)構(gòu)和算法的基礎(chǔ)概念都不是很清晰,這直接導(dǎo)致很多人在看到有關(guān)這部分的內(nèi)容就會(huì)望而卻步。 實(shí)際上,當(dāng)你了解了數(shù)據(jù)結(jié)構(gòu)和...
摘要:另外,由于篇幅有限,本篇的重點(diǎn)在于二叉樹(shù)的常見(jiàn)算法以及實(shí)現(xiàn)。常見(jiàn)的二叉樹(shù)實(shí)現(xiàn)代碼之前寫(xiě)過(guò)相關(guān)的文章,是關(guān)于如何創(chuàng)建及遍歷二叉樹(shù)的,這里不再贅述。同時(shí)我們注意到,在二叉樹(shù)深度比較大的時(shí)候,我們光是比較左右是不夠的。 本篇為復(fù)習(xí)過(guò)程中遇到過(guò)的總結(jié),同時(shí)也給準(zhǔn)備面試的同學(xué)一份參考。另外,由于篇幅有限,本篇的重點(diǎn)在于二叉樹(shù)的常見(jiàn)算法以及實(shí)現(xiàn)。 常見(jiàn)的二叉樹(shù)實(shí)現(xiàn)代碼 之前寫(xiě)過(guò)相關(guān)的文章,是關(guān)于如...
摘要:月下半旬攻略道題,目前已攻略題。目前簡(jiǎn)單難度攻略已經(jīng)到題,所以后面會(huì)調(diào)整自己,在刷算法與數(shù)據(jù)結(jié)構(gòu)的同時(shí),攻略中等難度的題目。 Create by jsliang on 2019-07-30 16:15:37 Recently revised in 2019-07-30 17:04:20 7 月下半旬攻略 45 道題,目前已攻略 100 題。 一 目錄 不折騰的前端,和咸魚(yú)有什么區(qū)別...
摘要:以下內(nèi)容編譯自他的這篇準(zhǔn)備下次編程面試前你應(yīng)該知道的數(shù)據(jù)結(jié)構(gòu)瑞典計(jì)算機(jī)科學(xué)家在年寫(xiě)了一本書(shū),叫作算法數(shù)據(jù)結(jié)構(gòu)程序。 國(guó)外 IT 教育學(xué)院 Educative.io 創(chuàng)始人 Fahim ul Haq 寫(xiě)過(guò)一篇過(guò)萬(wàn)贊的文章《The top data structures you should know for your next coding interview》,總結(jié)了程序員面試中需要掌...
閱讀 2490·2023-04-25 21:41
閱讀 1660·2021-09-22 15:17
閱讀 1931·2021-09-22 10:02
閱讀 2447·2021-09-10 11:21
閱讀 2586·2019-08-30 15:53
閱讀 1006·2019-08-30 15:44
閱讀 959·2019-08-30 13:46
閱讀 1149·2019-08-29 18:36