目录
- 第17题:合并两个排序的链表
- 第18题:树的子结构
- 第19题:二叉树的镜像
- 第20题:顺时针打印矩阵
- 第21题:包含min函数的栈
- 第22题:栈的压入、弹出序列
- 第23题:从上往下打印二叉树
- 第24题:二叉搜索树的后序遍历
- 第25题:二叉树中和为某一值的路径
第26题:复杂链表的复制
第17题:合并两个排序的链表
/**
* 题目描述:合并两个排序的链表
* 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。
*
* 解题思路:注意边界检验
*
* @author 焦含寒
*
*/
public class NO17 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
Node node7 = new Node(7);
Node node8 = new Node(8);
Node node9 = new Node(9);
Node node10 = new Node(10);
Node node11 = new Node(11);
//第一个链表
node1.setNext(node3);
node3.setNext(node5);
node5.setNext(node7);
node7.setNext(node9);
node9.setNext(node11);
//第二个链表
node2.setNext(node4);
node4.setNext(node6);
node6.setNext(node8);
node8.setNext(node10);
print(merge(node1, node2));
}
public static Node merge(Node head1,Node head2){
if(head1 == null)
return head2;
else if(head2 == null)
return head1;
Node mergeNode = null;
if(head1.getData() < head2.getData()){
mergeNode = head1;
merge(head1.getNext(), head2);
}else{
mergeNode = head2;
merge(head1, head2.getNext());
}
return mergeNode;
}
private static void print(Node root){
if(root != null){
System.out.println(root.getData());
print(root.getNext());
}
}
}
class Node{
private int data;
private Node next;
public Node(int data) {
super();
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
## 第18题:树的子结构 ##
import java.util.ArrayList;
import java.util.List;
/**
* 题目描述:树的子结构
* 输入两颗二叉树A和B,判断B是不是A的子结构。
*
* @author 焦含寒
*
*/
public class NO18 {
public static void main(String[] args){
//第一棵树
BinaryTreeNode node1 = new BinaryTreeNode(8);
BinaryTreeNode node2 = new BinaryTreeNode(8);
BinaryTreeNode node3 = new BinaryTreeNode(7);
BinaryTreeNode node4 = new BinaryTreeNode(9);
BinaryTreeNode node5 = new BinaryTreeNode(2);
BinaryTreeNode node6 = new BinaryTreeNode(4);
BinaryTreeNode node7 = new BinaryTreeNode(7);
node1.setLChild(node2);
node1.setRChild(node3);
node2.setLChild(node4);
node2.setRChild(node5);
node5.setLChild(node6);
node5.setRChild(node7);
//第二棵树
BinaryTreeNode node_1 = new BinaryTreeNode(8);
BinaryTreeNode node_2 = new BinaryTreeNode(9);
BinaryTreeNode node_3 = new BinaryTreeNode(2);
node_1.setLChild(node_2);
node_1.setRChild(node_3);
System.out.println(hasSubTree(node1, node_1));
}
public static boolean hasSubTree(BinaryTreeNode root1,BinaryTreeNode root2){
boolean result = false;
if(root1 != null && root2 != null){
if(root1.getData() == root2.getData()){
result = doseTree1HaveTree2(root1,root2);
if(!result){
result = hasSubTree(root1.getLChild(), root2);
}
if(!result){
result = hasSubTree(root1.getRChild(), root2);
}
}
}
return result;
}
private static boolean doseTree1HaveTree2(BinaryTreeNode root1, BinaryTreeNode root2) {
if(root2 == null)
return true;
if(root1 == null)
return false;
if(root1.getData() != root2.getData())
return false;
return doseTree1HaveTree2(root1.getLChild(), root2.getLChild())
&& doseTree1HaveTree2(root1.getRChild(), root2.getRChild());
}
}
class BinaryTreeNode{
private int data;
private BinaryTreeNode LChild;
private BinaryTreeNode RChild;
public BinaryTreeNode(int data) {
super();
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public BinaryTreeNode getLChild() {
return LChild;
}
public void setLChild(BinaryTreeNode lChild) {
LChild = lChild;
}
public BinaryTreeNode getRChild() {
return RChild;
}
public void setRChild(BinaryTreeNode rChild) {
RChild = rChild;
}
}
## 第19题:二叉树的镜像 ##
/**
* 题目描述:二叉树的镜像
* 请完成一个函数,输入一个二叉树,该函数输出它的镜像
*
* 解题思路:先先序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换
* 它的两个子结点,当交换完所有非叶子结点的左右结点的时候,即结果。
* @author 焦含寒
*
*/
public class NO19 {
public static void main(String[] args){
BTNode node1 = new BTNode(8);
BTNode node2 = new BTNode(6);
BTNode node3 = new BTNode(10);
BTNode node4 = new BTNode(5);
BTNode node5 = new BTNode(7);
BTNode node6 = new BTNode(9);
BTNode node7 = new BTNode(11);
node1.setLChild(node2);
node1.setRChild(node3);
node2.setLChild(node4);
node2.setRChild(node5);
node3.setLChild(node6);
node3.setRChild(node7);
mirror(node1);
print(node1);
}
public static void mirror(BTNode root){
if(root == null)
return;
if(root.getLChild() == null && root.getRChild() == null)
return;
BTNode temp = root.getLChild();
root.setLChild(root.getRChild());
root.setRChild(temp);
mirror(root.getLChild());
mirror(root.getRChild());
}
private static void print(BTNode root){
if(root != null){
System.out.println(root.getData());
print(root.getLChild());
print(root.getRChild());
}
}
}
class BTNode{
private int data;
private BTNode LChild;
private BTNode RChild;
public BTNode(int data) {
super();
this.data = data;
}
public BTNode getLChild() {
return LChild;
}
public void setLChild(BTNode lChild) {
LChild = lChild;
}
public BTNode getRChild() {
return RChild;
}
public void setRChild(BTNode rChild) {
RChild = rChild;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
## 第20题:顺时针打印矩##
/**
* 题目描述:顺时针打印矩阵
* 输入一个矩阵,按照从外向里以顺时针的顺序打印出每一个数字
* 例如,输入矩阵:
* 1 2 3 4
* 5 6 7 8
* 9 10 11 12
* 13 14 15 16
* 打印结果:1、2、3、4、8、12、16、15、14、13、9、5、6、7、11、10
*
* 解题思路:可以矩阵思考成若干的圈,一层嵌套一层。这个问题就变成了两个问题,
* 一个矩阵应该打印多少圈和每一圈该怎么去打印。先来解决第一个问题,该打
* 印多少圈?不难发现,每一圈的起点的横纵坐标都是相同的,假设这个矩阵有
* rows行,有columns列,当圈数继续进行下去的条件是rows > startX*2 &&
* columns > startY*2;再来解决如何打一圈的问题?总共分为四步,第一步
* 从左到右,第二步从上向下,第三步从右向左,第四步从下到上。注意最后
* 一圈会退化,可能只会有三步,两步甚至一步。第一步总是需要的,因为打印
* 一圈至少有一步。需要第二步的前提条件是终止行号大于起始行号,需要第三步
* 的条件至少有两行两列,也就是除了要求终止行号大于起始行号之外,还需要终
* 止列号大于起始列号。需要第四步的前提条件是至少三行两列,因此要求终止行
* 号比起始行号至少大2,同时终止行号大于起始行号。
*
* @author 焦含寒
*
*/
public class NO20 {
public static void main(String[] args){
int[][] arr = {{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}};
printArray(arr);
printMatixClockwisely(arr);
}
private static void printArray(int[][] arr) {
// TODO Auto-generated method stub
for(int i =0;i<arr.length;i++){
for(int j = 0;j<arr[0].length;j++){
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
public static void printMatixClockwisely(int[][] arr){
if(arr == null)
return;
int start = 0;
while(arr[0].length > start*2 && arr.length > start *2){
printOneCircle(arr,start);
start++;
}
}
private static void printOneCircle(int[][] arr, int start) {
// 打印从坐向右的一行
for(int i = start;i<arr[0].length-start;i++)
System.out.print(arr[start][i] + " ");
//判断并打印从上到下的一列
if(arr.length-1-start > start){
for(int i = start+1;i<arr.length-1-start;i++)
System.out.print(arr[i][arr[0].length-1-start] + " ");
}
//判断并打印从左向右的一行
if(arr[0].length-start-1 > start && arr.length-start-1 >start){
for(int i=arr.length-1-start;i>start;i--){
System.out.print(arr[arr.length-1-start][i] + " ");
}
}
//判断并打印从下到上的一列
if(arr.length-start-1 >start && arr[0].length-start-1 > start ){
for(int i=arr.length-1-start;i>start;i--){
System.out.print(arr[i][start] + " ");
}
}
}
}
## 第21题:包含min函数的栈 ##
import java.util.Stack;
/**
* 题目描述:包含min函数的栈
* 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min
* 函数。在该栈中,调用min、push及pop的时间复杂度都是O(1).
*
* 解题思路:最直观的想法就是在栈结构中维护一个最小值,可是这个办法只能调用一次,
* 当最小值被弹出的时候,就无法确定下一个最小值了。所以更换策略,在栈结构中
* 再维护一个最小值栈。当数据压到数据栈的时候,要是最小值栈为空或者最顶层元素
* 大于要压栈元素,就将这个数据压入最小值栈中,要是这个数据大于最小值栈最顶层
* 元素的话,就将最小值栈的顶层元素的值再压栈一遍。
*
* @author 焦含寒
*
*/
public class NO21 {
public static void main(String[] args) {
MyStack mStack = new MyStack();
System.out.println(mStack.min());
mStack.push(3);
mStack.push(4);
mStack.push(4);
mStack.push(10);
mStack.push(11);
System.out.println(mStack.min());
}
}
class MyStack {
private Stack<Integer> stack1;
private Stack<Integer> stackHelp;
public MyStack() {
stack1 = new Stack<>();
stackHelp = new Stack<>();
}
public void push(int num) {
stack1.push(num);
if (stackHelp.size() == 0 || num < stackHelp.peek()) {
stackHelp.push(num);
} else {
stackHelp.push(stackHelp.peek());
}
}
public void pop() {
stack1.pop();
stackHelp.pop();
}
public Integer min() {
if (stackHelp.size() == 0)
return null;
return stackHelp.peek();
}
}
## 第22题:栈的压入、弹出序列 ##
import java.util.Stack;
/**
* 题目描述:栈的压入、弹出序列
* 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出
* 顺序。假设压入栈的所有数字均不相等。例如序列1、2、3、4、5是某粘的压栈序列,序列
* 4、5、3、2、1是该压栈序列对应的一个弹出序列,但4、3、5、1、2就不可能是该压栈序列
* 的弹出序列。
*
* 解题思路:如果下一个弹出的数字刚好是栈顶数字,那么直接弹出。如果下一个弹出的数字不在栈顶
* 就把压栈序列中还没有入栈的数字压入辅助栈,直到把下一个需要弹出的数字压入栈顶为止。
* 如果所有的数字都压入栈了仍然没有找到下一个弹出的数字,那么该序列不可能是一个弹出序列。
*
*
* @author 焦含寒
*
*/
public class NO22 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr1 = {1,2,3,4,5};
int[] arr2 = {4,3,5,2,1};
int[] arr3 = {4,3,5,1,2};
System.out.println(isPopOrder(arr1, arr2));
System.out.println(isPopOrder(arr1, arr3));
}
public static boolean isPopOrder(int[] arr1,int[] arr2){
if(arr1 == null || arr2 == null)
return false;
int point1 = 0;
Stack<Integer> stack = new Stack();
for(int i=0;i<arr2.length;i++){
if(!stack.isEmpty() && stack.peek() == arr2[i]){
stack.pop();
}else{
if(point1 == arr1.length)
return false;
else{
do{
stack.push(arr1[point1++]);
}while(stack.peek()!=arr2[i] && point1 != arr1.length);
if(stack.peek() == arr2[i])
stack.pop();
else
return false;
}
}
}
return true;
}
}
## 第23题:从上往下打印二叉树 ##
import java.util.LinkedList;
import java.util.Queue;
/**
* 题目描述:从上往下打印二叉树
* 从上往下打印出二叉树的每个结点,同一层的结点按照从左到由的顺序打印。
*
* 解题思路:就是实现层次遍历
*
* @author 焦含寒
*
*/
public class N023 {
public static void main(String[] args) {
MBtNode node1 = new MBtNode(8);
MBtNode node2 = new MBtNode(6);
MBtNode node3 = new MBtNode(10);
MBtNode node4 = new MBtNode(5);
MBtNode node5 = new MBtNode(7);
MBtNode node6 = new MBtNode(9);
MBtNode node7 = new MBtNode(11);
node1.setLChild(node2);
node1.setRChild(node3);
node2.setLChild(node4);
node2.setRChild(node5);
node3.setLChild(node6);
node3.setRChild(node7);
printFromTopToBottom(node1);
}
private static void printFromTopToBottom(MBtNode root){
if(root == null)
return;
Queue<MBtNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
MBtNode node = queue.poll();
System.out.println(node.getData());
if(node.getLChild() != null)
queue.add(node.getLChild());
if(node.getRChild() != null)
queue.add(node.getRChild());
}
}
}
class MBtNode{
private int data;
private MBtNode LChild;
private MBtNode RChild;
public MBtNode(int data) {
super();
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public MBtNode getLChild() {
return LChild;
}
public void setLChild(MBtNode lChild) {
LChild = lChild;
}
public MBtNode getRChild() {
return RChild;
}
public void setRChild(MBtNode rChild) {
RChild = rChild;
}
}
## 第24题:二叉搜索树的后序遍历 ##
/**
* 题目描述:二叉搜索树的后序遍历
* 输入一个整数数组,判断该数组是不是某个二叉搜索树的后续遍历的结果。
* 如果是则返回true,否则返回false。假设输入的数组的任意两个数字都
* 互不相同。
*
* 解题思路:后序遍历的序列中,最后一个数字是树的根结点的值。数组中前面的
* 数字可以分为两部分:第一部分是左子树结点的值,它们都比根结点的值小
* ;第二部分是右子树结点的值,它们都比根结点的值大。
*
* @author 焦含寒
*
*/
public class NO24 {
public static void main(String[] args) {
int[] arr = {5,7,6,9,11,10,8};
System.out.println(verifySequenceOfBST(arr, 0, arr.length-1));
}
private static boolean verifySequenceOfBST(int[] arr,int start,int end){
if(arr == null || arr.length == 0
|| start > end || start < 0 || end <0)
return false;
if(start == end)
return true;
int root = arr[end];
int i = start;
for(;i<=end;i++){
if(arr[i] > root)
break;
}
int j = i;
for(;j<=end;j++){
if(arr[j]<root)
return false;
}
boolean left = true;
if(i>start){
left=verifySequenceOfBST(arr, start, i-1);
}
boolean right = true;
if(i<end){
right = verifySequenceOfBST(arr, i, end-1);
}
return left&&right;
}
}
## 第25题:二叉树中和为某一值的路径 ##
import java.util.Stack;
/**
* 题目描述:二叉树中和为某一值的路径
* 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。
* 从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
*
* 解题思路:对二叉树进行前序遍历,访问到某一个结点的时候,就把该结点添加到路径上
* 并累加该结点的值。如果该结点为叶子结点并且刚好等于输入的整数,则当前路径符
* 合要求。如果当前结点不是叶子结点,则继续访问它的孩子结点,当结点访问结束之后
* 递归函数会自动回到它的父节点。因此我们在函数退出之前要在路径上删除当前结点并
* 减去当前结点的值,以确保返回父结点时路径刚好是从根结点到父节点的路径。其实也
* 就是一个栈。
*
* @author 焦含寒
*
*/
public class NO25 {
public static void main(String[] args) {
BT_Node root = new BT_Node(10);
BT_Node node1 = new BT_Node(5);
BT_Node node2 = new BT_Node(4);
BT_Node node3 = new BT_Node(7);
BT_Node node4 = new BT_Node(12);
root.setLChild(node1);
root.setRChild(node4);
node1.setLChild(node2);
node1.setRChild(node3);
findPath(root, 22);
}
private static void findPath(BT_Node root, int i) {
if (root == null)
return;
Stack<Integer> stack = new Stack<>();
int currentSum = 0;
findPath(root, i, stack, currentSum);
}
private static void findPath(BT_Node root, int i, Stack<Integer> stack, int currentSum) {
currentSum += root.getData();
stack.push(root.getData());
if (root.getLChild() == null && root.getRChild() == null) {
if (currentSum == i) {
System.out.print("找到路径: ");
for (int path : stack) {
System.out.print(path + " ");
}
System.out.println();
}
}
if (root.getLChild() != null) {
findPath(root.getLChild(), i, stack, currentSum);
}
if (root.getRChild() != null) {
findPath(root.getRChild(), i, stack, currentSum);
}
stack.pop();
}
}
class BT_Node {
private int data;
private BT_Node LChild;
private BT_Node RChild;
public BT_Node(int data) {
super();
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public BT_Node getLChild() {
return LChild;
}
public void setLChild(BT_Node lChild) {
LChild = lChild;
}
public BT_Node getRChild() {
return RChild;
}
public void setRChild(BT_Node rChild) {
RChild = rChild;
}
}
## 第26题:复杂链表的复制 ##
/**
* 题目描述:复杂链表的复制
* 请实现函数,复制一个复杂链表,在复杂链表中,每个结点除了有一个m_pNext指针
* 指向下一个结点外,还有一个m_pSibling指向链表中的任意结点或者NULL
*
* 解题思路:先建立链表再去一个一个挂sibling结点,时间复杂度O(n^2);哈希表又牺牲了
* 空间,下面是一个巧妙的办法
*
* @author 焦含寒
*
*/
public class N026 {
public static void main(String[] args) {
// TODO Auto-generated method stub
ComplexListNode node1 = new ComplexListNode(1);
ComplexListNode node2 = new ComplexListNode(2);
ComplexListNode node3 = new ComplexListNode(3);
ComplexListNode node4 = new ComplexListNode(4);
ComplexListNode node5 = new ComplexListNode(5);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node1.sibling = node3;
node2.sibling = node5;
node4.sibling = node2;
ComplexListNode result = clone(node1);
while (result != null) {
System.out.println(result.data);
result = result.next;
}
}
private static ComplexListNode clone(ComplexListNode head) {
colneNodes(head);
copySiblingNodes(head);
return sparateNodes(head);
}
private static ComplexListNode sparateNodes(ComplexListNode head) {
ComplexListNode node = head;
ComplexListNode cloneHead = null;
ComplexListNode cloneNode = null;
if (node != null) {
cloneNode = node.next;
cloneHead = cloneNode;
node.next = cloneNode.next;
node = node.next;
}
while (node != null) {
cloneNode.next = node.next;
cloneNode = cloneNode.next;
node.next = cloneNode.next;
node = node.next;
}
return cloneHead;
}
private static void copySiblingNodes(ComplexListNode head) {
// TODO Auto-generated method stub
ComplexListNode node = head;
while (node != null) {
ComplexListNode cloneNode = node.next;
if (node.sibling != null)
cloneNode.sibling = node.sibling.next;
node = cloneNode.next;
}
}
private static void colneNodes(ComplexListNode head) {
// TODO Auto-generated method stub
ComplexListNode node = head;
while (node != null) {
ComplexListNode cloneNode = new ComplexListNode(node.data);
cloneNode.next = node.next;
node.next = cloneNode;
node = cloneNode.next;
}
}
}
class ComplexListNode {
int data;
ComplexListNode next;
ComplexListNode sibling;
public ComplexListNode(int data) {
super();
this.data = data;
}
}