题目列表
面试题31:栈的压入弹出序列
public class Demo31 {
public static void main(String[] args) {
int[] pushArr = { 1, 2, 3, 4, 5 };
int[][] popArr = { { 4, 3, 5, 2, 1 }, { 4, 3, 5, 1, 2 } };
for (int i = 0; i < popArr.length; i++) {
System.out.println(isPopOrder(pushArr, popArr[i]));
}
}
public static boolean isPopOrder(int[] pushArr, int[] popArr) {
if (pushArr == null || popArr == null
||pushArr.length == 0 || popArr.length == 0
|| pushArr.length != popArr.length) return false;
Stack<Integer> stack = new Stack<Integer>();
int j = 0;
for (int current : pushArr) {
stack.push(current);
while ((!stack.empty()) && (stack.peek() == popArr[j])) {
stack.pop();
j++;
}
}
if (stack.empty()) {
return true;
} else {
return false;
}
}
}
面试题32:从上到下打印二叉树
public class Demo1 {
public static void main(String[] args){
BiTreeNode root = createBiTree();
System.out.println("一行打印:");
printBiTreeUpDown(root);
System.out.println("\n逐行打印:");
printBiTreeByLine(root);
BiTreeNode root2 = createBiTree2();
System.out.println("\n逐行Z字形打印:");
printBiTreeByZ(root2);
}
// 层次遍历,一行打印
public static void printBiTreeUpDown(BiTreeNode root) {
if (root == null) return;
Queue<BiTreeNode> queue = new LinkedList<BiTreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
BiTreeNode node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
// 层次遍历:逐行打印
public static void printBiTreeByLine(BiTreeNode root) {
if (root == null) return;
Queue<BiTreeNode> queue = new LinkedList<BiTreeNode>();
queue.offer(root);
int count = 1;
while (!queue.isEmpty()) {
int k;
for(k = count, count = 0; k > 0; k--){
BiTreeNode node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null) {
queue.offer(node.left);
count++;
}
if (node.right != null) {
queue.offer(node.right);
count++;
}
}
System.out.println();
}
}
// 层次遍历:逐行Z字形打印
public static void printBiTreeByZ(BiTreeNode root) {
if (root == null)
return;
Stack<BiTreeNode> S1 = new Stack<BiTreeNode>(); // 装正序
Stack<BiTreeNode> S2 = new Stack<BiTreeNode>(); //
S1.push(root);
while (!S1.isEmpty() || !S2.isEmpty()) {
if (!S1.isEmpty() && S2.isEmpty()) {
while (!S1.isEmpty()) {
BiTreeNode node = S1.pop();
System.out.print(node.val + " ");
if (node.left != null) {
S2.push(node.left);
}
if (node.right != null) {
S2.push(node.right);
}
}
} else if (S1.isEmpty() && !S2.isEmpty()) {
while (!S2.isEmpty()) {
BiTreeNode node = S2.pop();
System.out.print(node.val + " ");
if (node.right != null) {
S1.push(node.right);
}
if (node.left != null) {
S1.push(node.left);
}
}
}
System.out.println();
}
}
// 构造一颗树
private static BiTreeNode createBiTree() {
BiTreeNode root = new BiTreeNode(8);
BiTreeNode node2 = new BiTreeNode(6);
BiTreeNode node3 = new BiTreeNode(10);
BiTreeNode node4 = new BiTreeNode(5);
BiTreeNode node5 = new BiTreeNode(7);
BiTreeNode node6 = new BiTreeNode(9);
BiTreeNode node7 = new BiTreeNode(11);
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
return root;
}
// 构造一颗树
private static BiTreeNode createBiTree2() {
BiTreeNode root = new BiTreeNode(1);
BiTreeNode node2 = new BiTreeNode(2);
BiTreeNode node3 = new BiTreeNode(3);
BiTreeNode node4 = new BiTreeNode(4);
BiTreeNode node5 = new BiTreeNode(5);
BiTreeNode node6 = new BiTreeNode(6);
BiTreeNode node7 = new BiTreeNode(7);
BiTreeNode node8 = new BiTreeNode(8);
BiTreeNode node9 = new BiTreeNode(9);
BiTreeNode node10 = new BiTreeNode(10);
BiTreeNode node11 = new BiTreeNode(11);
BiTreeNode node12 = new BiTreeNode(12);
BiTreeNode node13 = new BiTreeNode(13);
BiTreeNode node14 = new BiTreeNode(14);
BiTreeNode node15 = new BiTreeNode(15);
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
node4.left = node8;
node4.right = node9;
node5.left = node10;
node5.right = node11;
node6.left = node12;
node6.right = node13;
node7.left = node14;
node7.right = node15;
return root;
}
}
输出结果:
一行打印:
8 6 10 5 7 9 11
逐行打印:
8
6 10
5 7 9 11
逐行Z字形打印:
1
3 2
4 5 6 7
15 14 13 12 11 10 9 8
面试题33:二叉搜索树的后续遍历序列
分析:二叉搜索树左子树节点比根节点小,右子树节点不根节点大。后序遍历序列,最后一个是根节点,从右往左找,找到第一个小于根节点的节点
- 若该节点挨着根节点,说明没有右子树
- 没有,则说明没有左子树
找到左右子树位置后,可以判断左子树所有节点是否小于根节点,右子树所有节点是否大于根节点,不满足则返回false。满足,则左子树和右子树依次递归下去。
public class Demo {
public static void main(String[] args) {
int[][] arrs = {
{ 5, 7, 6, 9, 11, 10, 8 }, // 满二叉树 true
{ 1, 2, 3}, // 左支树 true
{ 6, 5, 4}, // 右支树 true
{5}, // 一个节点的二叉树 true
{ 5, 9, 7, 6, 11, 10, 8 }, // 非二叉搜索树 false
{}
};
for(int [] arr :arrs){
boolean bool = isPostOrder(arr);
System.out.println(bool);
}
}
public static boolean isPostOrder(int[] arr) {
int len = arr.length;
if (arr == null || len < 2) // 把空的情况也作为true吧,这个看出题者意图归到哪边
return true;
return isPostOrder(arr, 0, len - 1);
}
private static boolean isPostOrder(int[] arr, int start, int end) {
if(end - start <= 1) return true;
int k;// 找到左子树根节点
for (k = end - 1; k >= start; k--) {
if (arr[k] < arr[end])
break;
}
// 检查右子树是否大于根节点
for (int i = k + 1; i < end; i++) {
if (arr[i] < arr[end]) return false;
}
// 检查左子树是否大于根节点
for (int i = start; i < k; i++) {
if (arr[i] > arr[end]) return false;
}
return isPostOrder(arr, start, k) && isPostOrder(arr, k + 1, end - 1);
}
}
面试题34:二叉树中和为某一值的路径
public class Demo {
public static void main(String[] args) {
BiTreeNode root = createBiTree();
printSumPath(root, 22);
}
public static void printSumPath(BiTreeNode root, int k) {
if (root == null)
return;
Stack<Integer> stack = new Stack<Integer>();
printSumPath(root, k, stack);
}
public static void printSumPath(BiTreeNode root, int k, Stack<Integer> path) {
if (root == null)
return; // 结束条件
if (root.left == null && root.right == null) { // 如果到了叶子节点
if (root.val == k) {
for (int i : path)
System.out.print(i + ", ");
System.out.println(root.val);
}
} else { // 非叶子节点递归
path.push(root.val);
// 每次减去root.val,到叶节点时刚好和叶节点相等
printSumPath(root.left, k - root.val, path);
printSumPath(root.right, k - root.val, path);
path.pop(); // 回退
}
}
// 构造一颗树
private static BiTreeNode createBiTree() {
BiTreeNode root = new BiTreeNode(10);
BiTreeNode node2 = new BiTreeNode(5);
BiTreeNode node3 = new BiTreeNode(12);
BiTreeNode node4 = new BiTreeNode(4);
BiTreeNode node5 = new BiTreeNode(7);
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
return root;
}
}
测试输出:
10, 5, 7
10, 12
面试题35:复杂链表的复制
public class Demo {
public ComplexListNode copyComplexLinkedList(ComplexListNode head){
if(head == null) return null;
Map<ComplexListNode, ComplexListNode> map = new HashMap<>();
ComplexListNode p1 = head; // 原链表指针
ComplexListNode newHead = new ComplexListNode(p1.val);
ComplexListNode p2 = newHead; // 新链表指针
map.put(p1, p2);
// 先遍历第一遍,建立单链表
while(p1.next != null){
p2.next = new ComplexListNode(p1.next.val); // 拷贝一个节点
p2 = p2.next; // p2指到最后一个节点
p1 = p1.next;
map.put(p1, p2); // HashMap保存对应<原节点,新节点>
}
// 再遍历一遍,建立sibling关系
p1 = head;
p2 = newHead;
while(p1 != null){
p2.next = map.get(p1.sibling);
p1 = p1.next;
p2 = p2.next;
}
return newHead;
}
}
面试题36:二叉搜索树与双向链表
public class Demo {
public static void main(String[] args) {
BiTreeNode root = createBiTree();
BiTreeNode head = convert(root);
// 遍历双向链表并打印
while (head != null) {
System.out.println(head.val);
head = head.right;
}
}
// 记录子树链表的最后一个节点,终结点只可能为只含左子树的非叶节点与叶节点
private static BiTreeNode leftLast = null;
public static BiTreeNode convert(BiTreeNode root) {
if (root == null)
return null;
if (root.left == null && root.right == null) {
leftLast = root;// 最后的一个节点可能为最右侧的叶节点
return root;
}
// 1.将左子树构造成双链表,并返回链表头节点
BiTreeNode left = convert(root.left);
// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
if (left != null) {
leftLast.right = root;
root.left = leftLast;
}
leftLast = root;// 当根节点只含左子树时,则该根节点为最后一个节点
// 4.将右子树构造成双链表,并返回链表头节点
BiTreeNode right = convert(root.right);
// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
if (right != null) {
right.left = root;
root.right = right;
}
return left != null ? left : root;
}
// 构造一颗树
private static BiTreeNode createBiTree() {
BiTreeNode root = new BiTreeNode(10);
BiTreeNode node2 = new BiTreeNode(6);
BiTreeNode node3 = new BiTreeNode(14);
BiTreeNode node4 = new BiTreeNode(4);
BiTreeNode node5 = new BiTreeNode(8);
BiTreeNode node6 = new BiTreeNode(12);
BiTreeNode node7 = new BiTreeNode(16);
root.left = node2;
root.right = node3;
node2.left = node4;
node2.right = node5;
node3.left = node6;
node3.right = node7;
return root;
}
}
面试题38:字符串的排列
public class Demo {
public static void main(String[] args){
Demo demo = new Demo();
String str = "abc";
ArrayList<String> ss = demo.permutation(str);
for(String s: ss){
System.out.println(s);
}
}
public ArrayList<String> permutation(String str) {
ArrayList<String> resultList = new ArrayList<>();
if (str.length() == 0)
return resultList;
// 递归的初始值为(str数组,空的list,初始下标0)
fun(str.toCharArray(), resultList, 0);
Collections.sort(resultList);
return resultList;
}
private void fun(char[] ch, List<String> list, int i) {
// 这是递归的终止条件,就是i下标已经移到char数组的末尾的时候,考虑添加这一组字符串进入结果集中
if (i == ch.length - 1) {
// 判断一下是否重复
if (!list.contains(new String(ch))) {
list.add(new String(ch));
return;
}
} else {
for (int j = i; j < ch.length; j++) {
swap(ch, i, j);
fun(ch, list, i + 1);
swap(ch, i, j);
}
}
}
// 交换数组的两个下标的元素
private void swap(char[] str, int i, int j) {
if (i != j) {
char t = str[i];
str[i] = str[j];
str[j] = t;
}
}
}
面试题39:数组中出现次数超过一半的数
public class Demo {
public static void main(String[] args) throws Exception {
int[] arr = { 1, 2, 3, 2, 2, 2, 5, 4, 2 };
int num = moreThanHalfNum(arr);
System.out.println(num);
int[] arr1 = { 1, 4, 3, 2, 6, 2, 5, 4, 2 };
int num1 = moreThanHalfNum1(arr1);
System.out.println(num1);
}
// 用HashMap保存:时间复杂度O(n), 空间复杂度 O(n)
private static int moreThanHalfNum(int[] arr) throws Exception {
if (arr == null)
throw new Exception("空数组");
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < arr.length; i++) {
if (map.get(arr[i]) == null) {
map.put(arr[i], 1);
} else {
map.put(arr[i], map.get(arr[i]) + 1);
}
}
int maxKey = 0;
int maxValue = 0;
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() > maxValue) {
maxValue = entry.getValue();
maxKey = entry.getKey();
}
}
// 这里应当检查一下该数是否真的过半
if (!checkMoreThanHalf(arr, maxKey)) {
System.out.print("没有过半的数:");
return 0;
}
return maxKey;
}
// 改进:时间复杂度O(n), 空间复杂度O(1)
private static int moreThanHalfNum1(int[] arr) throws Exception {
if (arr == null || arr.length <= 0) throw new Exception("空数组");
int result = arr[0];
int times = 1;
for (int i = 1; i < arr.length; i++) {
if(times == 0){
result = arr[i];
times = 1;
}else if (result == arr[i]) {
times += 1;
} else{
times -= 1;
}
}
// 这里应当检查一下该数是否真的过半
if(!checkMoreThanHalf(arr, result)){
System.out.print("没有过半的数:");
return 0;
}
return result;
}
private static boolean checkMoreThanHalf(int[] arr, int result) {
int count = 0;
for(int i = 0; i < arr.length; i++){
if(arr[i] == result) count++;
}
return count > (arr.length >> 1);
}
}
面试题40:最小的k个数
public class Demo {
public static void main(String[] args) {
int[] arr = { 1, 1, 1, 2, 3, 4, 5, 6 };
int k = 3;
ArrayList<Integer> smallK = GetLeastNumbers_Solution(arr, k);
for (Integer i : smallK) {
System.out.println(i + " ");
}
}
public static ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
ArrayList<Integer> result = new ArrayList<Integer>();
int length = input.length;
if (k > length || k == 0) {return result;}
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k,
new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
for (int i = 0; i < length; i++) {
if (maxHeap.size() != k) {
maxHeap.offer(input[i]);
} else if (maxHeap.peek() > input[i]) {
maxHeap.poll();
maxHeap.offer(input[i]);
}
}
for (Integer integer : maxHeap) {
result.add(integer);
}
return result;
}
}