面試中遇到的手撕程式碼(二)
阿新 • • 發佈:2019-01-29
8.棧的最大值問題
問題的描述和思路可以參考這裡
Java實現程式碼如下:
import java.util.Stack;
/**
* 棧的最大值問題 Title: Description: Company:
*
* @author 鄭偉
* @date 2018年4月12日下午8:57:29
*/
public class SpecialStack {
Stack<Integer> stack = new Stack<>();
Stack<Integer> maxStack = new Stack<>();
public void push(Integer num) {
if (stack.isEmpty()) {
maxStack.push(num);
stack.push(num - maxStack.peek());
} else {
stack.push(num - maxStack.peek());
if (num > maxStack.peek()) {
maxStack.pop();
maxStack.push(num);
}
}
}
public int pop() {
if (!stack.isEmpty()) {
if (stack.peek() >= 0 && !maxStack.isEmpty()) {
int result = maxStack.pop();
maxStack.push(result - stack.pop());
return result;
} else if (stack.peek() < 0 && !maxStack.isEmpty()) {
return (maxStack.peek() + stack.pop());
} else {
return -1;
}
} else {
return -1;
}
}
public int max() {
if (stack.isEmpty()) {
return 0;
}
if (maxStack.isEmpty())
return -1;
return maxStack.peek();
}
public static void main(String[] args) {
int arr[] = { 5, 4, 1, 2, 3, 10, 9, 8, 6, 7, 15 };
SpecialStack specialStack = new SpecialStack();
for (int i = 0; i < arr.length; i++) {
specialStack.push(arr[i]);
System.out.print("入棧:" + arr[i]);
System.out.println("最大值:" + specialStack.max());
}
for (int i = 0; i < arr.length; i++) {
System.out.print("出棧:" + specialStack.pop());
System.out.println("最大值:" + specialStack.max());
}
}
}
9.非遞迴實現二叉樹的遍歷
前序遍歷:
對於樹中的任意一個節點cur:
(1)訪問cur,並將節點入棧;
(2)判斷節點cur的左孩子是否為空。若不為空,則將cur的左孩子cur.left置為當前的結點cur;
(3)若為空,則取棧頂節點並進行出棧操作(根據出棧節點去找該節點的右孩子),並將棧頂結點的右孩子cur.right置為當前的結點cur,迴圈至1);
中序遍歷:
對於樹中的任意節點cur:
(1)若cur的左孩子不為空,將p壓棧,並將cur的左子樹置為當前節點cur,然後對當前節點重複操作。
(2)若cur的左孩子為空,將棧頂元素出棧並進行訪問,把當前節點置為cur的右孩子。
(3)直到棧為空且cur為空
後序遍歷:
對於樹中的任意節點cur
(1) 如果該節點沒有左孩子和右孩子可以直接訪問該節點;
如果其左孩子和右孩子被訪問過了,可以直接訪問該節點;
(2)如果不是情況(1),那麼就先將右孩子壓棧,再將左孩子壓棧,這樣出棧順序就是先出左孩子再出右孩子。
import java.util.Stack;
/**
* 非遞迴的樹的遍歷 Title: Description: Company:
*
* @author 鄭偉
* @date 2018年4月13日下午3:37:12
*/
public class Print_Tree {
// 先序遍歷非遞迴
// 如果發現右兒子沒有了,那麼出棧,指向cur,如果cur右兒子有那麼久列印右兒子,把右兒子入棧,如果沒有右兒子,那麼久繼續出棧,出棧的節點設為cur
public static void preOrder(TreeNode pNode) {
Stack<TreeNode> stack = new Stack<>();
while (pNode != null || !stack.isEmpty()) {
while (pNode != null) {
// 先列印當前節點
System.out.print(pNode.val+" ");// 若節點不為空先訪問再壓棧
stack.push(pNode);// 當前節點入棧
pNode = pNode.left;// 將當前節點置為p的左孩子,若不為空繼續訪問並壓棧
}
// 當p為空時,說明根節點和左孩子列印遍歷完畢了,接下來出棧遍歷右孩子
if (!stack.isEmpty()) {// 左子樹不存在,那麼就是講棧頂彈出,作為當前 節點
pNode = stack.pop();
// 講當前節點設定為右邊的節點
pNode = pNode.right;
}
}
}
// 中序遍歷非遞迴
// 就只如果節點有左子樹就不停的入棧,直到左邊沒有左子樹,然後出棧,列印當前值,然後cur指向右節點。
public static void InOrder(TreeNode pNode) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while (pNode != null || !stack.isEmpty()) {
// 不停的把左子樹入棧
while (pNode != null) {
stack.push(pNode);
pNode = pNode.left;
}
// 當左子樹沒有的時候,也就是如到底部了
if (stack != null) {
pNode = stack.pop();// 彈出一個節點
System.out.print(pNode.val+" ");
pNode = pNode.right;// 開始答應右邊的節點
}
}
}
// 後續遍歷
// 先右子樹壓棧,再左子樹壓棧
public static void PostOrder(TreeNode pNode) {
if (pNode == null)
return;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode preNode = null;
TreeNode curNode;
stack.push(pNode);// 根節點先入棧
while (!stack.isEmpty()) {
curNode = stack.peek();
// 如果當前節點的左右子節點都為null,那麼就直接答應當前節點;
// 當前一個節點不為空並且是當前節點的左孩子或者右孩子,當是左孩子時說明當前節點右孩子為空,
// 當是右孩子時,說明左右孩子都訪問過了,且都不為空
if (curNode.left == null
&& curNode.right == null
|| (preNode != null && (preNode == curNode.left || preNode == curNode.right))) {
System.out.print(curNode.val+" ");// 訪問當前節點
preNode = curNode;
// curNode指向棧頂,由於列印過了,就直接出棧
stack.pop();
} else {
// 當前節點為棧頂元素 如果當前節點不是葉子節點,在當前節點之前訪問的那個節點不是當前節點的孩子,則進行壓棧
// 先壓棧右節點再壓棧左節點 這樣出棧時是先左後右
if (curNode.right != null)
stack.push(curNode.right);
if (curNode.left != null)
stack.push(curNode.left);
}
}
}
public TreeNode buildTree(int[] nums, int i) {
if (i >= nums.length)
return null;
TreeNode root = new TreeNode(nums[i]);
root.left = buildTree(nums, i * 2 + 1);
root.right = buildTree(nums, i * 2 + 2);
return root;
}
public static void main(String[] args) {
Print_Tree pTree = new Print_Tree();
int[] nums = {1,2,3,4,5,6};
TreeNode buildTree = pTree.buildTree(nums, 0);
System.out.println("前序遍歷");
Print_Tree.preOrder(buildTree);
System.out.println();
System.out.println("中遍歷");
Print_Tree.InOrder(buildTree);
System.out.println();
System.out.println("後序遍歷");
Print_Tree.PostOrder(buildTree);
}
}
/**
*前序遍歷
*1 2 4 5 3 6
*中遍歷
*4 2 5 1 6 3
*後序遍歷
*4 5 2 6 3 1
*/