剑指offer之21-25题解
目录
21. 栈的压入,弹出序列
(一)题目描述
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
(二) 思路
- 使用一个栈来模拟压入弹出操作。
- stack每入栈一个元素,就去判断栈顶元素是否与弹出数组的popIndex元素是否相同,相同就pop。
- 最后判断stack是否为null,为null说明弹出序列是正确的,否则错误。
(三)代码实现
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int[] pushA, int[] popA) {
int n = pushA.length;
Stack<Integer> stack = new Stack<>();
for (int pushIndex = 0, popIndex = 0; pushIndex < n; pushIndex++) {
stack.push(pushA[pushIndex]);
while (popIndex < n && !stack.isEmpty() && stack.peek() == popA[popIndex]) {
stack.pop();
popIndex++;
}
}
return stack.isEmpty();
}
}
22. 从上往下打印二叉树
(一)题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
(二) 思路
- 创建一个队列和list数组。
- 当队列不为null时获取队列的size,当cnt–>0,队列弹出一个元素,将元素值加入list数组,然后添加它的左右孩子。
- 跟着演变一遍就能看懂。
(三)代码实现
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
ArrayList<Integer> ret = new ArrayList<>();
queue.offer(root);
while (!queue.isEmpty()){
int cnt = queue.size();
while (cnt-->0){
TreeNode t = queue.poll();
if (t == null)
continue;
ret.add(t.val);
queue.offer(t.left);
queue.offer(t.right);
}
}
return ret;
}
}
23. 二叉搜索树的后序遍历序列
(一)题目描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
注:二叉搜索树中序遍历就是递增的,如下的中序遍历为1,2,3.
(二) 思路
- 输入的后序遍历,最后一个即为根节点,根节点的左边都比它小,根节点的右边都比它大。依次递归。
(三)代码实现
public class Solution {
public boolean VerifySquenceOfBST(int[] sequence) {
if (sequence == null || sequence.length == 0)
return false;
return verify(sequence, 0, sequence.length - 1);
}
private boolean verify(int[] sequence, int first, int last) {
if (last - first <= 1)
return true;
int rootVal = sequence[last];
int cutIndex = first;
while (cutIndex < last && sequence[cutIndex] <= rootVal)
cutIndex++;
for (int i = cutIndex; i < last; i++)
if (sequence[i] < rootVal)
return false;
return verify(sequence, first, cutIndex - 1) && verify(sequence, cutIndex, last - 1);
}
}
24. 二叉树中和为某一值的路径
(一)题目描述
输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
(二) 思路
- backtracking()方法中,当
target == 0 && node.left == null && node.right == null
说明已找到和为target路线,并且是最后一个节点。所以直接加入ret即可。否则递归回溯 - 因为不能确定只有一条路线,所以最后
path.remove(path.size() - 1)
(三)代码实现
public class Solution {
private ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
backtracking(root, target, new ArrayList<Integer>());
return ret;
}
private void backtracking(TreeNode node, int target, ArrayList<Integer> path) {
if (node == null)
return;
path.add(node.val);
target -= node.val;
if (target == 0 && node.left == null && node.right == null) {
ret.add(new ArrayList<>(path));
} else {
backtracking(node.left, target, path);
backtracking(node.right, target, path);
}
path.remove(path.size() - 1);
}
}
25. 复杂链表的复制
(一)题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
(二) 思路
- 在每个节点的后面插入复制的节点
- 对复制节点的random链接进行赋值
- 拆分
(三)代码实现
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if (pHead == null) {
return null;
}
//插入新节点
RandomListNode cur = pHead;
while (cur != null) {
RandomListNode clone = new RandomListNode(cur.label);
clone.next = cur.next;
cur.next = clone;
cur = clone.next;
}
//建立random连接
cur = pHead;
while (cur != null) {
RandomListNode clone = cur.next;
if (cur.random != null)
clone.random = cur.random.next;
cur = clone.next;
}
//拆分
cur = pHead;
RandomListNode pCloneHead = pHead.next;
while (cur.next != null) {
RandomListNode next = cur.next;
cur.next = next.next;
cur = next;
}
return pCloneHead;
}
}