├── src └── main │ └── java │ ├── common │ ├── TreeNodeUtil.java │ ├── ListNode.java │ ├── Node.java │ ├── ListNodeUtil.java │ └── BinaryTree.java │ ├── 第四章_解决面试的思路 │ ├── 复杂链表的复制.java │ ├── 二叉树的镜像.java │ ├── 二叉搜索树与双向链表.java │ ├── 面试题_45度打印矩阵.java │ ├── 字符串的排列.java │ ├── 栈的压入及弹出序列.java │ ├── 从上往下打印二叉树.java │ ├── 二叉搜索树的后序遍历序列.java │ ├── 字符串的全排列_去除重复.java │ ├── 从上往下打印二叉树_按行打印.java │ ├── 字符串的组合.java │ ├── 顺时针打印矩阵.java │ ├── 包含min函数的栈.java │ ├── 二叉树中和为某一值的路径.java │ ├── 之字打印二叉树.java │ └── 思考题_8个数字在正方体上三组相对的面上的4个顶点的和都相等.java │ ├── 扩展_动态规划 │ ├── 最大的利益 │ │ ├── 题目.png │ │ └── Main.java │ ├── 不能相邻的两个数的最大和 │ │ ├── 递归式.png │ │ ├── 解题公式.png │ │ ├── 题目_不相邻的两个数的最大和.png │ │ └── Main.java │ ├── 求数组中的数之和为指定的数 │ │ ├── 题目.png │ │ ├── 递归的出口.png │ │ └── Main.java │ └── 连续子数组的最大和 │ │ └── Main.java │ ├── 第三章_高质量的代码 │ ├── 打印1至最大的n位数.java │ ├── 数值的整数次方.java │ ├── 链表中倒数第k个结点.java │ ├── 树的子结构.java │ ├── 调整数组顺序使奇数位于偶数前面.java │ ├── 反转链表.java │ ├── 在O1时间删除链表结点.java │ ├── 奇数位于前面偶数位于后面并且不改原在原数组中的顺序.java │ ├── 面试题_调整0位于数组的最后面.java │ └── 合并两个排序的链表.java │ ├── 第五章_优化时间和空间效率 │ ├── 数组中的逆序对.java │ ├── test.java │ ├── 第一个只出现一次的字符.java │ ├── 连续子数组的最大和.java │ ├── 两个链表的第一个公共结点.java │ ├── 最小的k个数.java │ └── 数组中出现次数超过一半的数字.java │ ├── 第六章_面试中的各项能力 │ ├── 二叉树的深度.java │ ├── 和为s的连续正数序列.java │ ├── 字符反转.java │ ├── 和为s的两个数.java │ ├── 翻转单词顺序.java │ ├── 判断二叉树是否为平衡二叉树.java │ ├── 数组中只出现一次的数字.java │ └── 数字在排序数组中出现的次数.java │ ├── 第8章_英文版新增面试题 │ ├── 对称的二叉树.java │ ├── 数组中重复的数字.java │ ├── 把二叉树打印成多行.java │ ├── 链表中环的入口结点.java │ ├── 删除链表中重复的结点.java │ └── 二叉树的下一个结点.java │ └── 第二章_面试需要的基础知识 │ ├── 跳台阶与变态跳台阶.java │ ├── 二进制中1的个数.java │ ├── 二维数组中的查找.java │ ├── 旋转数组的最小数.java │ ├── 从尾到头打印链表.java │ ├── 用两个栈实现队列.java │ ├── 斐波那契数列.java │ ├── 快速排序.java │ ├── 替换空格.java │ ├── 用两个队列实现一个栈.java │ ├── Singleton模式.java │ └── 重建二叉树.java ├── .gitignore ├── pom.xml └── README.md /src/main/java/common/TreeNodeUtil.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | public class TreeNodeUtil { 4 | 5 | } 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/复杂链表的复制.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | 4 | public class 复杂链表的复制 { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/最大的利益/题目.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvCmx/jzoffer/HEAD/src/main/java/扩展_动态规划/最大的利益/题目.png -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/不能相邻的两个数的最大和/递归式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvCmx/jzoffer/HEAD/src/main/java/扩展_动态规划/不能相邻的两个数的最大和/递归式.png -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/求数组中的数之和为指定的数/题目.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvCmx/jzoffer/HEAD/src/main/java/扩展_动态规划/求数组中的数之和为指定的数/题目.png -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/不能相邻的两个数的最大和/解题公式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvCmx/jzoffer/HEAD/src/main/java/扩展_动态规划/不能相邻的两个数的最大和/解题公式.png -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/求数组中的数之和为指定的数/递归的出口.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvCmx/jzoffer/HEAD/src/main/java/扩展_动态规划/求数组中的数之和为指定的数/递归的出口.png -------------------------------------------------------------------------------- /src/main/java/第三章_高质量的代码/打印1至最大的n位数.java: -------------------------------------------------------------------------------- 1 | package 第三章_高质量的代码; 2 | 3 | /** 4 | * 注意这个n的大小 5 | */ 6 | public class 打印1至最大的n位数 { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/不能相邻的两个数的最大和/题目_不相邻的两个数的最大和.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvCmx/jzoffer/HEAD/src/main/java/扩展_动态规划/不能相邻的两个数的最大和/题目_不相邻的两个数的最大和.png -------------------------------------------------------------------------------- /src/main/java/第五章_优化时间和空间效率/数组中的逆序对.java: -------------------------------------------------------------------------------- 1 | package 第五章_优化时间和空间效率; 2 | 3 | /** 4 | * 题目: 5 | * 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。 6 | * 方法一: 7 | * 双循环遍历,时间复杂度O(n) 8 | * 方法二: 9 | * 10 | */ 11 | public class 数组中的逆序对 { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/common/ListNode.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | public class ListNode{ 4 | public int value; 5 | public ListNode next; 6 | public ListNode(){ 7 | } 8 | public ListNode(int value,ListNode next){ 9 | this.value=value; 10 | this.next=next; 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/java/第六章_面试中的各项能力/二叉树的深度.java: -------------------------------------------------------------------------------- 1 | package 第六章_面试中的各项能力; 2 | 3 | 4 | import common.Node; 5 | 6 | public class 二叉树的深度 { 7 | int treeDepth(Node tree) { 8 | if (tree == null) { 9 | return 0; 10 | } 11 | int left = treeDepth(tree.lnode); 12 | int right = treeDepth(tree.rnode); 13 | return (left > right) ? (left + 1) : (right + 1); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/common/Node.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | public class Node { 4 | public Node lnode; 5 | public Node rnode; 6 | public Node parent; 7 | public int data; 8 | 9 | public Node(int data) { 10 | this.data=data; 11 | } 12 | //构造一个新结点,该结点以lNode结点为其左孩子,rNode结点为其右孩子 13 | public Node(Node lNode,Node rNode,int data) { 14 | this.lnode=lNode; 15 | this.rnode=rNode; 16 | this.data=data; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.jar 3 | !.mvn/wrapper/* 4 | *.war 5 | *.zip 6 | *.tar 7 | *.tar.gz 8 | 9 | # eclipse ignore 10 | .settings/ 11 | .project 12 | .classpath 13 | 14 | 15 | # temp ignore 16 | *.log 17 | *.cache 18 | *.diff 19 | *.patch 20 | *.tmp 21 | 22 | # system ignore 23 | .DS_Store 24 | Thumbs.db 25 | *.orig 26 | 27 | # idea ignore 28 | .idea/ 29 | *.ipr 30 | *.iws 31 | .mymetadata 32 | .checkstyle 33 | .classpath 34 | .project 35 | .class 36 | .war 37 | .zip 38 | .rar 39 | *.iml 40 | .settings/* 41 | /indexes/* 42 | /target/* 43 | /src/main/webapp/WEB-INF/classes/* 44 | /src/main/webapp/userfiles/* 45 | /target/ -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/二叉树的镜像.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | import common.BinaryTree; 4 | import common.Node; 5 | 6 | public class 二叉树的镜像 { 7 | 8 | public static void reverse(Node node){ 9 | if(node==null){ 10 | return ; 11 | } 12 | if(node.lnode==null && node.rnode==null){ 13 | return ; 14 | } 15 | Node temp=node.lnode; 16 | node.lnode=node.rnode; 17 | node.rnode=temp; 18 | if(node.lnode!=null){ 19 | reverse(node.lnode); 20 | } 21 | if(node.rnode!=null){ 22 | reverse(node.rnode); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/二叉搜索树与双向链表.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | import common.Node; 4 | 5 | /** 6 | * 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。 7 | * 要求:1.不能创建新节点 8 | * 2.只能调整树中结点的指针的指向。 9 | */ 10 | public class 二叉搜索树与双向链表 { 11 | public static void main(String[] args) { 12 | Node root = new Node( null, null,4); 13 | Node left1 = new Node( null, null,3); 14 | Node right1 = new Node( null, null,5); 15 | root.lnode=left1; 16 | root.rnode=right1; 17 | left1.lnode = new Node( null, null,1); 18 | left1.rnode = new Node( null, null,2); 19 | right1.rnode= new Node( null, null,7); 20 | 21 | 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/第8章_英文版新增面试题/对称的二叉树.java: -------------------------------------------------------------------------------- 1 | package 第8章_英文版新增面试题; 2 | 3 | import common.Node; 4 | 5 | public class 对称的二叉树 { 6 | public static boolean isSymmetrical(Node node){ 7 | return isSymmetrical(node,node); 8 | } 9 | 10 | private static boolean isSymmetrical(Node node, Node node1) { 11 | if(node==null && node1==null){ 12 | return true; 13 | } 14 | if(node==null || node1==null){ 15 | return false; 16 | } 17 | if(node.data!=node1.data){ 18 | return false; 19 | } 20 | return isSymmetrical(node.rnode,node.lnode) && isSymmetrical(node.lnode,node1.rnode); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.sxl 8 | jzoffer 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | junit 14 | junit 15 | 4.11 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/跳台阶与变态跳台阶.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | import org.junit.Test; 4 | 5 | public class 跳台阶与变态跳台阶 { 6 | 7 | @Test 8 | public void test1(){ 9 | System.out.println(fib1(4)); 10 | System.out.println(fib2(4)); 11 | } 12 | 13 | //跳台阶 14 | public int fib1(int n){ 15 | if(n<=0){ 16 | return 0; 17 | }else if(n==1){ 18 | return 1; 19 | }else if(n==2){ 20 | return 2; 21 | } 22 | return fib1(n-1)+fib1(n-2); 23 | } 24 | 25 | //变态跳 26 | public int fib2(int n){ 27 | if(n<=0){ 28 | return 0; 29 | }else if(n==1){ 30 | return 1; 31 | } 32 | return 2*fib2(n-1); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/二进制中1的个数.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | import org.junit.Test; 4 | 5 | public class 二进制中1的个数 { 6 | // 时间复杂度是O(n) 7 | @Test 8 | public void test(){ 9 | int key=-1; 10 | int flag=1; 11 | int num=0; 12 | while(flag>0){ 13 | if((key & flag)>0){ 14 | num++; 15 | } 16 | flag=flag << 1; 17 | } 18 | System.out.println(num); 19 | } 20 | 21 | /** 22 | * 23 | * 上面的代码可以解决正数和负数的问题,如果key是32位的数,它要循环32次。 24 | * 下面给出最优代码(有多少个1,就执行多少次循环) 25 | */ 26 | @Test 27 | public void test2(){ 28 | int count=0; 29 | int n=-1; 30 | while(n!=0){ 31 | count++; 32 | n=(n-1) & n; 33 | } 34 | System.out.println(count); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/二维数组中的查找.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | /** 4 | * 参考答案 5 | */ 6 | public class 二维数组中的查找 { 7 | public static void main(String[] args) { 8 | int[][] arr={{1,2,8,9},{2,4,9,12},{4,7,10,13},{6,8,11,15}}; 9 | System.out.println(findNum(arr,3)); 10 | } 11 | public static boolean findNum(int[][] arr,int num){ 12 | if(null==arr || arr.length==0){ 13 | return false; 14 | } 15 | int row=0; 16 | int column=arr[0].length-1; 17 | while(row=0){ 18 | if(num==arr[row][column]){ 19 | return true; 20 | }else if(num>arr[row][column]){ 21 | row++; 22 | }else{ 23 | column--; 24 | } 25 | } 26 | return false; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/第8章_英文版新增面试题/数组中重复的数字.java: -------------------------------------------------------------------------------- 1 | package 第8章_英文版新增面试题; 2 | 3 | /** 4 | * 思路1:排序,再遍历 5 | * 思路2:数组元素对应下标 6 | */ 7 | public class 数组中重复的数字 { 8 | public static void main(String[] args) { 9 | int[] arr={2,3,1,0,2,5,3}; 10 | int result=duplicate(arr); 11 | System.out.println(result); 12 | } 13 | 14 | private static int duplicate(int[] arr) { 15 | if(arr==null || arr.length==0){ 16 | return -1; 17 | } 18 | for(int i=0;i>1 24 | double result= power(base,exponent>>1); 25 | result*=result; 26 | //说明是奇数 27 | if((exponent & 0x1) ==1){ 28 | //奇数就再重一个base 29 | result*=base; 30 | } 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/第六章_面试中的各项能力/和为s的连续正数序列.java: -------------------------------------------------------------------------------- 1 | package 第六章_面试中的各项能力; 2 | 3 | /** 4 | * 输入一个正整数s,打印出所有和为s的连续正整数序列。 5 | */ 6 | public class 和为s的连续正数序列 { 7 | void findContinuousSequence(int sum) { 8 | if (sum < 3) { 9 | return; 10 | } 11 | int small = 1; 12 | int big = 2; 13 | int mid = (1 + sum) / 2; 14 | int curSum = small + big; 15 | while (small < mid) { 16 | if (sum == curSum) { 17 | System.out.println(small + "->" + big); 18 | } 19 | while (curSum > sum && small < mid) { 20 | curSum -= small; 21 | small++; 22 | if (sum == curSum) { 23 | System.out.println(small + "->" + big); 24 | } 25 | } 26 | big++; 27 | curSum += big; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/最大的利益/Main.java: -------------------------------------------------------------------------------- 1 | package 扩展_动态规划.最大的利益; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 题目说明,每个恢色的条代表着每个工作的时候,里面的数字代表着完成它的利益,求如何去做才能得到最大的解 7 | */ 8 | public class Main { 9 | 10 | public static void main(String[] args) { 11 | int prev[] ={0,0,0,0,1,0,2,3,5}; 12 | int value[]={0,5,1,8,4,6,3,2,4}; 13 | 14 | int opt[]=new int[prev.length]; 15 | opt[0]=0; 16 | for(int i=1;inum2){ 28 | return num1; 29 | }else{ 30 | return num2; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/连续子数组的最大和/Main.java: -------------------------------------------------------------------------------- 1 | package 扩展_动态规划.连续子数组的最大和; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | int[] arr={-101,3,-4,5,7,-8,4,-3,6,-8}; 6 | int sum = findGreatestSumOfSubArray(arr,arr.length-1); 7 | System.out.println(sum); 8 | } 9 | 10 | /** 11 | * @param arr 12 | * @return 13 | */ 14 | private static int findGreatestSumOfSubArray(int[] arr,int i) { 15 | if(arr==null || arr.length<=0){ 16 | return 0; 17 | } 18 | int sum=arr[0]; 19 | int max=arr[0]; 20 | for(int j=1;jmax){ 23 | max=sum; 24 | } 25 | } 26 | return max; 27 | } 28 | 29 | public static int getMax(int a,int b){ 30 | return a > b ? a: b; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/旋转数组的最小数.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | public class 旋转数组的最小数 { 4 | public static void main(String[] args) { 5 | int arr[]={6,1,2,3,4,5}; 6 | int val=reverseArr(arr); 7 | System.out.println(val); 8 | } 9 | 10 | private static int reverseArr(int[] arr) { 11 | if(null==arr || arr.length<=0){ 12 | return -1; 13 | } 14 | 15 | int left=0; 16 | int right=arr.length-1; 17 | int mid=left; 18 | while(arr[left]>=arr[right]){ 19 | mid=(left+right)/2; 20 | if(right-left==1){ 21 | mid=right; 22 | break; 23 | } 24 | if(arr[mid]>=arr[left]){ 25 | left=mid; 26 | }else if(arr[mid]<=arr[right]){ 27 | right=mid; 28 | } 29 | } 30 | return arr[mid]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/第三章_高质量的代码/链表中倒数第k个结点.java: -------------------------------------------------------------------------------- 1 | package 第三章_高质量的代码; 2 | 3 | import common.ListNode; 4 | import common.ListNodeUtil; 5 | 6 | /** 7 | * 输入一个链表,输出该链表的倒数第k个结点。 8 | * 这题利用两个指针 9 | */ 10 | public class 链表中倒数第k个结点 { 11 | 12 | public static void main(String[] args) { 13 | ListNode head = ListNodeUtil.createListNode(new int[]{1, 2, 4, 5, 6, 7, 8}); 14 | int kthToTail = findKthToTail(head, 2); 15 | System.out.println(kthToTail); 16 | } 17 | 18 | public static int findKthToTail(ListNode head,int k){ 19 | if(null==head || k<0){ 20 | return -1; 21 | } 22 | int tail=0; 23 | ListNode temp=head; 24 | ListNode slow=head; 25 | while(null!=temp){ 26 | tail++; 27 | if(tail>k){ 28 | slow=slow.next; 29 | } 30 | temp=temp.next; 31 | } 32 | return slow.value; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/从尾到头打印链表.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | public class 从尾到头打印链表 { 4 | public static void main(String[] args) { 5 | //初始化一个链表 6 | ListNode root=new ListNode(0); 7 | ListNode temp=root; 8 | ListNode node=null; 9 | for(int i=1;i<10;i++){ 10 | node=new ListNode(i); 11 | temp.next=node; 12 | temp=node; 13 | } 14 | //从尾到头打印链表 15 | reverseListNode(root); 16 | } 17 | 18 | public static void reverseListNode(ListNode node){ 19 | if(null==node){ 20 | return; 21 | } 22 | if(null!=node.next){ 23 | reverseListNode(node.next); 24 | } 25 | System.out.println(node.key); 26 | } 27 | } 28 | 29 | /* 30 | 定义链表结构 31 | */ 32 | class ListNode{ 33 | ListNode next; 34 | Integer key; 35 | public ListNode(Integer key){ 36 | this.key=key; 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/第五章_优化时间和空间效率/test.java: -------------------------------------------------------------------------------- 1 | package 第五章_优化时间和空间效率; 2 | 3 | import java.util.*; 4 | 5 | public class test { 6 | 7 | public static void main(String[] args){ 8 | Scanner scan = new Scanner(System.in); 9 | while(scan.hasNext()){ 10 | int n=scan.nextInt(); 11 | long[] dp=new long[n+1]; 12 | if(n==1) 13 | System.out.println(0); 14 | else if(n==2) 15 | System.out.println(1); 16 | else if(n==3) 17 | System.out.println(2); 18 | else{ 19 | dp[1]=0; 20 | dp[2]=2; 21 | dp[3]=3; 22 | for(int i=4;i<=n;i++){ 23 | for(int j=1;j stack1=new Stack(); 7 | static Stack stack2=new Stack(); 8 | 9 | public static void main(String[] args) { 10 | push(1); 11 | push(2); 12 | push(3); 13 | push(4); 14 | 15 | System.out.println(pop()); 16 | } 17 | 18 | //放入元素 19 | public static void push(Integer value){ 20 | stack1.push(value); 21 | } 22 | 23 | //取出元素 24 | public static Integer pop(){ 25 | if(stack2.isEmpty()){ 26 | //将stack1中的元素放入到stack2中 27 | if(stack1.isEmpty()){ 28 | return -1; 29 | }else{ 30 | while(!stack1.isEmpty()){ 31 | stack2.push(stack1.pop()); 32 | } 33 | } 34 | } 35 | return stack2.pop(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/求数组中的数之和为指定的数/Main.java: -------------------------------------------------------------------------------- 1 | package 扩展_动态规划.求数组中的数之和为指定的数; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | int[] arr={1,3,6,8,3,5,4,2}; 6 | int num=15; 7 | boolean max=getMax(arr,arr.length-1,num); 8 | System.out.println(max); 9 | } 10 | 11 | /** 12 | * 使用递归式 13 | * @param arr 14 | * @param i 15 | * @param num 16 | * @return 17 | */ 18 | private static boolean getMax(int[] arr,int i, int num) { 19 | if(arr==null || arr.length<=0){ 20 | return false; 21 | } 22 | if(num==0){ 23 | return true; 24 | }else if(i==0){ 25 | return arr[i]==num; 26 | }else if(arr[i]>num){ 27 | return getMax(arr,i-1, num); 28 | }else { 29 | boolean resultA=getMax(arr,i-1, num-arr[i]); 30 | boolean resultB=getMax(arr,i-1, num); 31 | return resultA || resultB; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/斐波那契数列.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | import org.junit.Test; 4 | 5 | public class 斐波那契数列 { 6 | 7 | @Test 8 | public void test(){ 9 | int fibonacci = fibonacci(10); 10 | System.out.println(fibonacci); 11 | 12 | int fibonacci2 = fibonacci2(10); 13 | System.out.println(fibonacci2); 14 | 15 | 16 | 17 | } 18 | 19 | //递归解法 20 | public int fibonacci(int n){ 21 | if(n<=0){ 22 | return 0; 23 | } 24 | if(n==1 || n==2){ 25 | return 1; 26 | } 27 | return fibonacci(n-1)+fibonacci(n-2); 28 | } 29 | 30 | //循环解法 31 | public int fibonacci2(int i){ 32 | int f1=1; 33 | int f2=1; 34 | int f3=f1+f2; 35 | if(i==1 || i==2){ 36 | return 1; 37 | }else if(i==3){ 38 | return f2; 39 | }else{ 40 | for(int t=3;t=key){ 25 | right--; 26 | } 27 | arr[left]=arr[right]; 28 | while(left queue = new ArrayBlockingQueue(100); 14 | queue.add(node); 15 | int nextLevel=0; 16 | int toBePrinted=1; 17 | while(!queue.isEmpty()){ 18 | Node poll = queue.poll(); 19 | System.out.print(poll.data); 20 | if(poll.lnode!=null){ 21 | queue.add(poll.lnode); 22 | ++nextLevel; 23 | } 24 | if(poll.rnode!=null){ 25 | queue.add(poll.rnode); 26 | ++nextLevel; 27 | } 28 | --toBePrinted; 29 | if(toBePrinted==0){ 30 | System.out.println(); 31 | toBePrinted=nextLevel; 32 | nextLevel=0; 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/第六章_面试中的各项能力/字符反转.java: -------------------------------------------------------------------------------- 1 | package 第六章_面试中的各项能力; 2 | 3 | /** 4 | * 例如:student 5 | * udentst 6 | */ 7 | public class 字符反转 { 8 | public static void main(String[] args) { 9 | String str="student"; 10 | int num=3; 11 | String result=reverseChar(str,num); 12 | System.out.println(result); 13 | } 14 | 15 | private static String reverseChar(String str, int num) { 16 | if(str==null || str.length()<2){ 17 | return str; 18 | } 19 | String sLeft=swap(str.substring(0,num),0,num-1); 20 | String sRight=swap(str.substring(num),0,str.length()-num-1); 21 | 22 | String result=swap(sLeft+sRight,0,str.length()-1); 23 | return result; 24 | } 25 | 26 | private static String swap(String str, int left, int right) { 27 | char[] chars = str.toCharArray(); 28 | while(left map=new LinkedHashMap(); 26 | for (char c:arrs) { 27 | if(map.containsKey(c)){ 28 | map.put(c,map.get(c)+1); 29 | }else{ 30 | map.put(c,1); 31 | } 32 | } 33 | for (Map.Entry entry:map.entrySet()) { 34 | if(entry.getValue()==1){ 35 | System.out.println(entry.getKey()); 36 | break; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/面试题_45度打印矩阵.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | public class 面试题_45度打印矩阵 { 4 | public static void main(String[] args) { 5 | int[][] arrs={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; 6 | printRightTop(arrs); 7 | 8 | printLeftTop(arrs); 9 | } 10 | 11 | // 打印左下角的三角型 12 | public static void printLeftTop(int[][] arrs) { 13 | if(null==arrs || arrs.length<=0){ 14 | return ; 15 | } 16 | int endY=arrs.length-1; 17 | for(int i=1;i<=endY;i++){ 18 | int temp=i; 19 | for(int j=0;j<=endY-i;j++){ 20 | System.out.print(arrs[temp++][j]+" "); 21 | } 22 | System.out.println(); 23 | } 24 | } 25 | 26 | // 打印右上角的三角型 27 | public static void printRightTop(int[][] arrs){ 28 | if(null==arrs || arrs.length<=0){ 29 | return; 30 | } 31 | int end=arrs[0].length-1; 32 | for(int i=end;i>=0;i--){ 33 | int temp=i; 34 | for(int j=0;j<=end-i;j++){ 35 | System.out.print(arrs[j][temp++]+" "); 36 | } 37 | System.out.println(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/第六章_面试中的各项能力/和为s的两个数.java: -------------------------------------------------------------------------------- 1 | package 第六章_面试中的各项能力; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 方法1:利用map 8 | * 方法2:先排序,然后利用left与right指针 9 | * 题目:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s 10 | */ 11 | public class 和为s的两个数 { 12 | public static void main(String[] args) { 13 | int[] arr = {1, 2, 4, 9, 11, 15}; 14 | int s = 13; 15 | List result = findNumbersWithSum(arr, s); 16 | System.out.println(result); 17 | } 18 | 19 | private static List findNumbersWithSum(int[] arr, int s) { 20 | if (arr == null || arr.length < 2) { 21 | return null; 22 | } 23 | List result = new ArrayList(); 24 | int left = 0; 25 | int right = arr.length - 1; 26 | while (left < right) { 27 | int temp = arr[left] + arr[right]; 28 | if (temp == s) { 29 | result.add(arr[left] + "," + arr[right]); 30 | left++; 31 | right--; 32 | } else if (temp > s) { 33 | right--; 34 | } else { 35 | left++; 36 | } 37 | } 38 | return result; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/字符串的排列.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | /** 4 | * 输入一个字符串,打印出该字符串所能排列出来的所有字符串 5 | */ 6 | public class 字符串的排列 { 7 | public static void main(String[] args) { 8 | String str="abc"; 9 | permutation(str.toCharArray(),0,str.length()-1); 10 | 11 | } 12 | 13 | /* 14 | * 参数arrayA:给定字符串的字符数组 15 | * 参数start:开始遍历字符与其后面各个字符将要进行交换的位置 16 | * 参数end:字符串数组的最后一位 17 | */ 18 | public static void permutation(char[] arr,int start,int end){ 19 | if(end<=1){ 20 | return; 21 | } 22 | if(start==end){ 23 | //说明已经交换到了最后,可以输出这个字符串了 24 | for(int i=0;i stackData = new Stack(); 26 | 27 | int lastIndex=0; 28 | for(int i=0;i= 0; i--) { 30 | if (arr[i] != ' ') { 31 | newArr[--newLen]=arr[i]; 32 | }else{ 33 | newArr[--newLen]='0'; 34 | newArr[--newLen]='2'; 35 | newArr[--newLen]='%'; 36 | } 37 | } 38 | return new String(newArr); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/从上往下打印二叉树.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | import common.Node; 4 | 5 | import java.util.Stack; 6 | import java.util.concurrent.ArrayBlockingQueue; 7 | import java.util.concurrent.LinkedBlockingQueue; 8 | 9 | /** 10 | * 层次遍历,利用辅助栈来实现 11 | */ 12 | public class 从上往下打印二叉树 { 13 | public static void main(String[] args) { 14 | Node root = new Node( null, null,1); 15 | Node left1 = new Node( null, null,2); 16 | Node right1 = new Node( null, null,3); 17 | root.lnode=left1; 18 | root.rnode=right1; 19 | 20 | printTree(root); 21 | 22 | } 23 | 24 | /** 25 | * 按层次顺序输出二叉树中的节点 26 | * @param node 27 | */ 28 | public static void printTree(Node node){ 29 | if(node==null){ 30 | return ; 31 | } 32 | // 基于链表的队列 33 | LinkedBlockingQueue queue = new LinkedBlockingQueue(); 34 | queue.add(node); 35 | while(!queue.isEmpty()){ 36 | Node temp = queue.poll(); 37 | System.out.println(temp.data); 38 | if(temp.lnode!=null){ 39 | queue.add(temp.lnode); 40 | } 41 | if(temp.rnode!=null){ 42 | queue.add(temp.rnode); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/二叉搜索树的后序遍历序列.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | import common.Node; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 已存在一棵二叉树 9 | * 和一个二叉树的后序序列 10 | */ 11 | public class 二叉搜索树的后序遍历序列 { 12 | 13 | public static void main(String[] args) { 14 | int[] arr={7,4,6,5}; 15 | int[] arr2={5,7,6,9,11,10,8}; 16 | boolean result=verifySqeuenceOfBST(arr2,arr2.length); 17 | System.out.println(result); 18 | } 19 | 20 | public static boolean verifySqeuenceOfBST(int[] arr,int length) { 21 | if(arr==null || length<=0){ 22 | return false; 23 | } 24 | // 即然是后序遍历,那么它最后一个元素就是根 25 | int last=arr[arr.length-1]; 26 | int i=0; // 搜索所有小于根节点的,因为是二叉搜索树,左小于根,右大于根 27 | for(;ilast){ 29 | break; 30 | } 31 | } 32 | int j=i; 33 | // 判断后面的数是否都大于根节点 34 | for(;j0){ 41 | left=verifySqeuenceOfBST(arr,i); 42 | } 43 | boolean right=true; 44 | if(i right ? left : right); 22 | } 23 | return -1; 24 | } 25 | 26 | 27 | /** 28 | * 这种方式存在重复递归的过程 29 | * 30 | * @param root 31 | * @return 32 | */ 33 | boolean isBalanced(Node root) { 34 | if (root == null) { 35 | return true; 36 | } 37 | int left = treeDepth(root.lnode); 38 | int right = treeDepth(root.rnode); 39 | if (Math.abs(left - right) != 1) { 40 | return false; 41 | } 42 | return isBalanced(root.lnode) && isBalanced(root.rnode); 43 | } 44 | 45 | int treeDepth(Node tree) { 46 | if (tree == null) { 47 | return 0; 48 | } 49 | int left = treeDepth(tree.lnode); 50 | int right = treeDepth(tree.rnode); 51 | return (left > right) ? (left + 1) : (right + 1); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/第三章_高质量的代码/奇数位于前面偶数位于后面并且不改原在原数组中的顺序.java: -------------------------------------------------------------------------------- 1 | package 第三章_高质量的代码; 2 | 3 | import java.util.Arrays; 4 | import java.util.Queue; 5 | import java.util.concurrent.ArrayBlockingQueue; 6 | 7 | /** 8 | * 这题是上题的进化版 9 | * 在交换的时候,还需要保持在原数组中的次序不能改变 10 | * 11 | * 这题参考网上的答案: * https://blog.csdn.net/wangshihui512/article/details/51242868 12 | * 1、奇数往前移 13 | * 2、统计偶数的个数 14 | * 3、将偶数放入队列 15 | */ 16 | public class 奇数位于前面偶数位于后面并且不改原在原数组中的顺序 { 17 | 18 | public static void main(String[] args) { 19 | int[] arr={1,2,5,-53,6,7,4,3,13}; 20 | 21 | reOrderArray(arr); 22 | System.out.println(Arrays.toString(arr)); 23 | } 24 | 25 | // 网上某个大佬的思路 26 | public static void reOrderArray(int[] arr){ 27 | Queue odd=new ArrayBlockingQueue(arr.length); 28 | if(null==arr || arr.length<=0){ 29 | return; 30 | } 31 | int oddNumber=0; 32 | for(int i=0;i>= indexOf1; 38 | return (i & 1) != 0; 39 | } 40 | 41 | private static int findFirstBitIs1(int exqResult) { 42 | int index = 0; 43 | while ((exqResult & 1) == 0) { 44 | exqResult >>= 1; 45 | index++; 46 | } 47 | return index; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/第三章_高质量的代码/面试题_调整0位于数组的最后面.java: -------------------------------------------------------------------------------- 1 | package 第三章_高质量的代码; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | 给定一个由正数,负数和0组成的整数数组,将所有为0的元素,挪到数组末尾。要求时间复杂度O(n) 7 | 请设计一个函数,完成此功能。(语言不限) 8 | 实现思路: 9 | 利用两个变量分别指向数组首部与数组的尾部,然后判断首部是否为0,不为0则首部+1 10 | 如果首部为0,则交换首尾元素,首尾各+1 11 | 如果首部为0,尾部也为0,则尾部+1再交换 12 | 这种实现方式中需要遍历一遍数组,所以时间复杂度为O(1),空间复杂度O(1) 13 | */ 14 | public class 面试题_调整0位于数组的最后面 { 15 | public static void main(String[] args) { 16 | int[] arr= {1,6,4,-3,0,5,0,9}; 17 | int[] arr1= {0,0,0}; 18 | swapZero(arr1); 19 | System.out.println("最终结果:"+Arrays.toString(arr1)); 20 | } 21 | 22 | public static void swapZero(int[] arr){ 23 | if(null==arr || arr.length<=1){ 24 | return; 25 | } 26 | int begin=0; 27 | int end=arr.length-1; 28 | while(begin queue = new LinkedList(); 34 | queue.add(root); 35 | while (!queue.isEmpty()) { 36 | Node temp = queue.poll(); 37 | System.out.print(temp.data + ","); 38 | if (temp.lnode != null) { 39 | queue.add(temp.lnode); 40 | nlast = temp.lnode; 41 | } 42 | if (temp.rnode != null) { 43 | queue.add(temp.rnode); 44 | nlast = temp.rnode; 45 | } 46 | if (last == temp) { 47 | System.out.println(); 48 | last = nlast; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/第8章_英文版新增面试题/删除链表中重复的结点.java: -------------------------------------------------------------------------------- 1 | package 第8章_英文版新增面试题; 2 | 3 | import common.ListNode; 4 | import common.ListNodeUtil; 5 | 6 | public class 删除链表中重复的结点 { 7 | public static void main(String[] args) { 8 | int[] arr=new int[]{-1,1,1,2,3,4,4,5,5}; 9 | ListNode head = ListNodeUtil.createListNode(arr); 10 | ListNode result=delDuplication(head); 11 | ListNodeUtil.print(result); 12 | } 13 | 14 | private static ListNode delDuplication(ListNode head) { 15 | if(head==null){ 16 | return null; 17 | } 18 | ListNode pHead=head; 19 | ListNode temp=pHead; 20 | ListNode pre=pHead; 21 | boolean flag=false; 22 | while(pHead.next!=null){ 23 | if(pHead.value==pHead.next.value){ 24 | flag=true; 25 | if(pHead.next.next!=null){ 26 | pHead.next=pHead.next.next; 27 | continue; 28 | }else { 29 | pHead.next=null; 30 | } 31 | } 32 | if(flag){ 33 | if(pre.next!=null && pre.next.next!=null){ 34 | pre.next=pre.next.next; 35 | }else{ 36 | pre.next=null; 37 | } 38 | flag=false; 39 | }else{ 40 | pre=pHead; 41 | } 42 | if(pHead.next!=null) 43 | pHead=pHead.next; 44 | } 45 | return temp; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/字符串的组合.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 字符串的排列与组合是考试常见到的题目 8 | * 原文 https://www.jb51.net/article/134398.htm 9 | * 要么选择长度为n的字符串中的第一个字符,那么要在其余的长度n-1的字符串中选择m-1个字符 10 | * 要么不选择长度为n的字符串中的第一个字符,那么要在其余的长度n-1的字符串中选择m个字符。 11 | */ 12 | public class 字符串的组合 { 13 | 14 | public static void main(String[] args) { 15 | String str = "abc"; 16 | perm(str); 17 | } 18 | 19 | public static void perm(String str){ 20 | // 将结果保存到这里面 21 | List result = new ArrayList(); 22 | // 从单个字母开始 23 | for(int i=1;i<=str.length();i++){ 24 | combination(str,i,result); 25 | } 26 | } 27 | 28 | // 从字符串str中选择m个字符 29 | public static void combination(String str, int m, List result){ 30 | // 如果m==0,则递归结束,输出当前结果 31 | if(m == 0){ 32 | for (int i = 0; i < result.size(); i++){ 33 | System.out.print(result.get(i)); 34 | } 35 | System.out.print("、"); 36 | return; 37 | } 38 | if(str.length()!=0){ 39 | // 选择当前元素 40 | result.add(str.charAt(0)+""); 41 | // substring用法,截取出从1开始到n结束的字符串 42 | combination(str.substring(1, str.length()), m - 1, result); 43 | result.remove(result.size() - 1); 44 | // 不选当前元素 45 | combination(str.substring(1, str.length()), m, result); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/common/ListNodeUtil.java: -------------------------------------------------------------------------------- 1 | package common; 2 | 3 | /** 4 | * 说明:一些公用的东西就写到这里面了 5 | */ 6 | public class ListNodeUtil { 7 | //循环输出链表 8 | public static void print(ListNode node){ 9 | while(null!=node){ 10 | System.out.println(node.value); 11 | node=node.next; 12 | } 13 | } 14 | 15 | // 生成一个链表,用于测试 16 | public static ListNode createListNode(int [] arr){ 17 | if(null!=arr && arr.length>0){ 18 | ListNode result=new ListNode(-1,null); 19 | ListNode root=result; 20 | for(int i=0;i0){ 31 | ListNode result=new ListNode(-1,null); 32 | ListNode root=result; 33 | for(int i=0;ipnode2.value){ 29 | temp.next=pnode2; 30 | pnode2=pnode2.next; 31 | temp=temp.next; 32 | }else{ 33 | temp.next=pnode1; 34 | pnode1=pnode1.next; 35 | temp=temp.next; 36 | } 37 | } 38 | while(pnode1!=null){ 39 | temp.next=pnode1; 40 | pnode1=pnode1.next; 41 | temp=temp.next; 42 | } 43 | while(pnode2!=null){ 44 | temp.next=pnode2; 45 | pnode2=pnode2.next; 46 | temp=temp.next; 47 | } 48 | return newHead.next; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/用两个队列实现一个栈.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | import java.util.Queue; 4 | import java.util.concurrent.ArrayBlockingQueue; 5 | 6 | public class 用两个队列实现一个栈 { 7 | private static Queue queue1 = new ArrayBlockingQueue(10); 8 | private static Queue queue2 = new ArrayBlockingQueue(10); 9 | 10 | public static void main(String[] args) { 11 | push(1); 12 | push(2); 13 | push(3); 14 | 15 | System.out.println(poll()); 16 | System.out.println(poll()); 17 | } 18 | 19 | //栈放入元素 20 | public static void push(Integer value){ 21 | if(queue1.isEmpty() && queue1.isEmpty()){ 22 | queue1.add(value); 23 | }else{ 24 | if(!queue1.isEmpty()){ 25 | queue1.add(value); 26 | }else{ 27 | queue2.add(value); 28 | } 29 | } 30 | } 31 | //栈取出元素 32 | public static Integer poll(){ 33 | Integer v=-1; 34 | if(!queue1.isEmpty()){ 35 | while(!queue1.isEmpty()){ 36 | if(queue1.size()>1){ 37 | queue2.add(queue1.poll()); 38 | }else{ 39 | v=queue1.poll(); 40 | queue1.clear(); 41 | } 42 | } 43 | }else{ 44 | while(!queue2.isEmpty()){ 45 | if(queue2.size()>1){ 46 | queue1.add(queue2.poll()); 47 | }else{ 48 | v=queue2.poll(); 49 | queue2.clear(); 50 | } 51 | } 52 | } 53 | return v; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/Singleton模式.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | /** 4 | * 说明:目前我所知道的单例模式主要有4种实现方式: 5 | * 懒汉式、饿汉式、内部类、枚举 6 | */ 7 | public class Singleton模式 { 8 | public static void main(String[] args) { 9 | SingletonTest4.INSTANCE.test(); 10 | } 11 | } 12 | /** 13 | * 懒汉式 14 | */ 15 | class SingletonTest1{ 16 | private static SingletonTest1 instance=null; 17 | 18 | public static SingletonTest1 getInstance(){ 19 | // 双重锁检查 20 | if(null==instance){ 21 | // 多线程问题 22 | synchronized (instance) { 23 | if(instance==null){ 24 | instance = new SingletonTest1(); 25 | } 26 | } 27 | } 28 | return instance; 29 | } 30 | } 31 | 32 | /** 33 | * 饿汉式 34 | */ 35 | class SingletonTest2{ 36 | private static SingletonTest2 instance=new SingletonTest2(); 37 | 38 | public static SingletonTest2 getInstance(){ 39 | return instance; 40 | } 41 | } 42 | 43 | /** 44 | * 内部类实现方式,由于类在加载的时候,内部类不会被加载,只有当调用它的时候才会被加载 45 | * 加载一个类时,其内部类不会同时被加载。一个类被加载,当且仅当其某个静态成员(静态域、构造器、静态方法等)被调用时发生。 46 | * 实现了懒汉式与线程安全问题 47 | */ 48 | class SingletonTest3{ 49 | 50 | public static SingletonTest3 getInstance(){ 51 | return Inner.instance; 52 | } 53 | 54 | public static class Inner{ 55 | public static final SingletonTest3 instance=new SingletonTest3(); 56 | } 57 | } 58 | 59 | /** 60 | * 枚举类实现单例 61 | * 饿汉式+线程安全 62 | * 主要是用到了枚举中的变量都会被转换成public static final的,之后,会在静态代码中对枚举量进行初始化。 63 | */ 64 | enum SingletonTest4{ 65 | INSTANCE; 66 | public void test(){ 67 | System.out.println("test enum singleton..."); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/顺时针打印矩阵.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | public class 顺时针打印矩阵 { 4 | public static void main(String[] args) { 5 | int[][] arrs={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; 6 | printCircel(arrs); 7 | } 8 | 9 | public static void printCircel(int[][] arrs){ 10 | if(arrs==null || arrs.length<=0){ 11 | return; 12 | } 13 | int columns=arrs.length-1; 14 | int rows=arrs[0].length-1; 15 | int start=0; 16 | while(columns>start*2 && rows>start*2){ 17 | printMatrixInCircle(arrs,columns,rows,start); 18 | start++; 19 | } 20 | } 21 | 22 | private static void printMatrixInCircle(int[][] arrs, int columns, int rows, int start) { 23 | int endX=columns-start; 24 | int endY=rows-start; 25 | 26 | //从左到右打印一行 27 | for(int i=start;i<=endX;i++){ 28 | System.out.print(arrs[start][i]+" "); 29 | } 30 | System.out.println(); 31 | // 从上到下打印一列 32 | if(start=start;--i){ 41 | System.out.print(arrs[endY][i]+" "); 42 | } 43 | } 44 | System.out.println(); 45 | if(start=start+1;i--){ 47 | System.out.print(arrs[i][start]+" "); 48 | } 49 | } 50 | System.out.println(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/包含min函数的栈.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 这题是通过两个栈来实现的 7 | * 正常一个栈是用来存数据,另外一个辅助栈是用来存放当前最小的值 8 | */ 9 | public class 包含min函数的栈 { 10 | 11 | private static Stack stackData = new Stack(); 12 | private static Stack stackMin = new Stack(); 13 | 14 | public static void main(String[] args) { 15 | push(4); 16 | push(3); 17 | push(2); 18 | 19 | Integer min = getMin(); 20 | System.out.println(min); 21 | } 22 | 23 | /** 24 | * 存放元素的时候,我们往stackData中存放,存放的时候,判断该数与stackMin顶的最小值进行比较 25 | * 如果比最小值小,则也同样进入到stackMin中 26 | * 如果比最小值大,则最小值再一次进入到栈中 27 | * @param val 28 | * @return 29 | */ 30 | public static Integer push(Integer val){ 31 | if(stackMin.isEmpty()){ 32 | stackMin.push(val); 33 | }else{ 34 | Integer peek = stackMin.peek(); 35 | if(val>peek){ 36 | stackMin.push(peek); 37 | }else{ 38 | stackMin.push(val); 39 | } 40 | } 41 | stackData.push(val); 42 | return val; 43 | } 44 | 45 | /** 46 | * 出栈的时候 47 | * @return 48 | */ 49 | public static Integer poll(){ 50 | if(stackData.isEmpty()){ 51 | return -1; 52 | } 53 | Integer pop = stackData.pop(); 54 | Integer peek = stackMin.pop(); 55 | return pop; 56 | } 57 | 58 | /** 59 | * 获取最小值的时候 60 | */ 61 | public static Integer getMin(){ 62 | if(stackMin.isEmpty()){ 63 | return -1; 64 | } 65 | Integer peek = stackMin.peek(); 66 | return peek; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/第五章_优化时间和空间效率/连续子数组的最大和.java: -------------------------------------------------------------------------------- 1 | package 第五章_优化时间和空间效率; 2 | 3 | /** 4 | * 如果累加的数比本身还小,则不重新统计 5 | */ 6 | public class 连续子数组的最大和 { 7 | public static void main(String[] args) { 8 | int[] arr = {1, 2, -4, 5, 7, -8, 4, -3, 6, -8}; 9 | int greatestSumOfSubArray = findGreatestSumOfSubArray(arr); 10 | System.out.println(greatestSumOfSubArray); 11 | 12 | int greatestSumOfSubArray1 = findSumOfSubArray(arr); 13 | System.out.println(greatestSumOfSubArray1); 14 | 15 | } 16 | 17 | public static int findGreatestSumOfSubArray(int[] arr) { 18 | if (null == arr || arr.length <= 0) { 19 | return 0; 20 | } 21 | int sum = 0; 22 | int greatestSum = 0; 23 | for (int i = 0; i < arr.length; i++) { 24 | if (sum <= 0) { 25 | sum = arr[i]; 26 | } else { 27 | sum += arr[i]; 28 | } 29 | if (sum > greatestSum) { 30 | greatestSum = sum; 31 | } 32 | } 33 | return greatestSum; 34 | } 35 | 36 | /** 37 | * 动态规划 38 | * 动态规划思路:对于第i项来说,要么选择第i项+之前的和,要么只选择第i项抛弃之前的和 39 | * 也就是 40 | * DP[i] = max(dp[i-1]+num[i] , num[i]) 41 | * 42 | * @param array 43 | * @return 44 | */ 45 | public static int findSumOfSubArray(int[] array) { 46 | if (array == null || array.length <= 0) { 47 | return -1; 48 | } 49 | int sum = array[0]; 50 | int max = array[0]; 51 | for (int i = 1; i < array.length; i++) { 52 | sum = Math.max(sum + array[i], array[i]); 53 | if (sum > max) { 54 | max = sum; 55 | } 56 | } 57 | return max; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/第8章_英文版新增面试题/二叉树的下一个结点.java: -------------------------------------------------------------------------------- 1 | package 第8章_英文版新增面试题; 2 | 3 | import common.Node; 4 | 5 | public class 二叉树的下一个结点 { 6 | public static void main(String[] args) { 7 | Node a = new Node(null,null,1); 8 | Node b= new Node(null,null,1); 9 | Node c = new Node(null,null,1); 10 | Node d = new Node(null,null,1); 11 | Node e = new Node(null,null,1); 12 | Node f = new Node(null,null,1); 13 | Node g = new Node(null,null,1); 14 | Node h = new Node(null,null,1); 15 | Node i = new Node(null,null,1); 16 | a.lnode=b; 17 | a.rnode=c; 18 | b.lnode=d; 19 | b.rnode=e; 20 | c.lnode=f; 21 | c.rnode=g; 22 | e.lnode=h; 23 | e.rnode=i; 24 | 25 | h.parent=e; 26 | i.parent=e; 27 | d.parent=b; 28 | e.parent=b; 29 | f.parent=c; 30 | g.parent=c; 31 | c.parent=a; 32 | b.parent=a; 33 | 34 | Node node=getNextNode(i); 35 | System.out.println(node.data); 36 | } 37 | 38 | private static Node getNextNode(Node root) { 39 | if(root==null){ 40 | return null; 41 | } 42 | Node pNext=null; 43 | if(root.rnode!=null){ 44 | Node rnode = root.rnode; 45 | while(rnode.lnode!=null){ 46 | rnode=rnode.lnode; 47 | } 48 | pNext=rnode; 49 | }else if(root.parent!=null){ 50 | Node current=root; 51 | Node parent = root.parent; 52 | while(parent!=null && current==parent.rnode){ 53 | current=parent; 54 | parent= parent.parent; 55 | } 56 | pNext=parent; 57 | } 58 | return pNext; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/扩展_动态规划/不能相邻的两个数的最大和/Main.java: -------------------------------------------------------------------------------- 1 | package 扩展_动态规划.不能相邻的两个数的最大和; 2 | 3 | import java.sql.SQLOutput; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * 例如:给定一个数组,求它们不相信的两个数的最大和 8 | * [1,2,4,1,7,8,3] 9 | */ 10 | public class Main { 11 | 12 | public static void main(String[] args){ 13 | int[] arr={1,2,4,1,7,8,3}; 14 | // int max=getMax(arr,arr.length-1); 15 | // System.out.println(max); 16 | System.out.println("方式二"); 17 | int max1 = getMax(arr); 18 | System.out.println(max1); 19 | } 20 | 21 | /** 22 | * 方法一:采用递归的方式来解决 23 | * 这种方式会存在重复计算的过程 24 | */ 25 | public static int getMax(int[] arr,int i){ 26 | if(i==0){ 27 | return arr[0]; 28 | }else if(i==1){ 29 | return Math.max(arr[0],arr[1]); 30 | }else{ 31 | // 当选择当前节点的时候 32 | int resultA=getMax(arr,i-2)+arr[i]; 33 | // 当不选择当前节点的时候 34 | int resultB=getMax(arr,i-1); 35 | return Math.max(resultA,resultB); 36 | } 37 | } 38 | 39 | /** 40 | * 采用非递归的方式,就是需要记录每次已经计算的结果,这样无需再重复的计算 41 | */ 42 | public static int getMax(int[] arr){ 43 | if(arr==null || arr.length<=0){ 44 | return -1; 45 | } 46 | int[] opt=new int[arr.length]; 47 | if(arr.length==1){ 48 | return arr[0]; 49 | }else if(arr.length==2){ 50 | return Math.max(arr[0],arr[1]); 51 | }else{ 52 | opt[0]=arr[0]; 53 | opt[1]=Math.max(arr[0],arr[1]); 54 | for(int i=2;i path=new ArrayList(); 35 | int currentSum=0; 36 | findPath(root,expectedSum,path,currentSum); 37 | 38 | } 39 | 40 | private static void findPath(Node root, int expectedSum, List path, int currentSum) { 41 | currentSum+=root.data; 42 | path.add(root.data); //将当前元素的值添加到路径中 43 | 44 | // 是不是子节点 45 | boolean isLeft=root.lnode==null && root.rnode==null; 46 | if(currentSum == expectedSum && isLeft){ 47 | System.out.println("找到一条路径..."); 48 | Iterator iterator = path.iterator(); 49 | while(iterator.hasNext()){ 50 | Integer next = iterator.next(); 51 | System.out.print(next +" "); 52 | } 53 | } 54 | 55 | //如果不是叶结点,则遍历它的子节点 56 | if(root.lnode!=null){ 57 | findPath(root.lnode, expectedSum, path, currentSum); 58 | } 59 | if(root.rnode!=null){ 60 | findPath(root.rnode, expectedSum, path, currentSum); 61 | } 62 | 63 | // 在返回到父结点之前,在路径上删除当前结点。 64 | path.remove(path.size()-1); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/第六章_面试中的各项能力/数字在排序数组中出现的次数.java: -------------------------------------------------------------------------------- 1 | package 第六章_面试中的各项能力; 2 | 3 | /** 4 | * 统计一个数字在排序数组中出现的次数 5 | * 方法1: 6 | * 循环一遍数组,取出某数字在数组中出现的次数,时间复杂度O(n) 7 | * 方法2: 8 | * 因为数组是有序的,所以可以通过二分查找,然后左右两边扫描,最坏时间复杂度O(n) 9 | * 方法3: 10 | * 通过折半找到第一个出现的k 11 | */ 12 | public class 数字在排序数组中出现的次数 { 13 | public static void main(String[] args) { 14 | int[] arr = {1, 2, 3, 3, 3, 3, 3, 4, 5}; 15 | int leftNum = getFirstK(arr, 0, arr.length - 1, 3); 16 | int rightNum = getLastK(arr, 0, arr.length - 1, 3); 17 | System.out.println(rightNum-leftNum+1); 18 | } 19 | 20 | /** 21 | * 获取第一个k 22 | * 23 | * @param arr 24 | * @param left 25 | * @param right 26 | * @param k 27 | * @return 28 | */ 29 | private static int getFirstK(int[] arr, int left, int right, int k) { 30 | if (left > right) { 31 | return -1; 32 | } 33 | int mid = (left + right) / 2; 34 | if (arr[mid] == k) { 35 | //判断是不是第一个 36 | if (mid > 0 && arr[mid - 1] != k) { 37 | return mid; 38 | } else { 39 | right = mid - 1; 40 | } 41 | } else if (arr[mid] < k) { 42 | left = mid + 1; 43 | } else { 44 | right = mid - 1; 45 | } 46 | return getFirstK(arr, left, right, k); 47 | } 48 | 49 | /** 50 | * 获取最后一个k 51 | * 52 | * @param arr 53 | * @param left 54 | * @param right 55 | * @param k 56 | * @return 57 | */ 58 | private static int getLastK(int[] arr, int left, int right, int k) { 59 | if (left > right) { 60 | return -1; 61 | } 62 | int mid = (left + right) / 2; 63 | if (arr[mid] == k) { 64 | //判断是不是第一个 65 | if (mid > 0 && arr[mid + 1] != k) { 66 | return mid; 67 | } else { 68 | left = mid + 1; 69 | } 70 | } else if (arr[mid] < k) { 71 | left = mid + 1; 72 | } else { 73 | right = mid - 1; 74 | } 75 | return getLastK(arr, left, right, k); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/第五章_优化时间和空间效率/最小的k个数.java: -------------------------------------------------------------------------------- 1 | package 第五章_优化时间和空间效率; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * 找出一个数列中最小的k个数字 7 | * 最简单的思路:排序返回前面k个数,时间复杂度为nlogn 8 | * 9 | * 10 | * 我们可以用一个k大小的容器,将k个数排序的方式进行比较,这个思路与用大顶堆来实现是一样的 11 | */ 12 | public class 最小的k个数 { 13 | public static void main(String[] args) { 14 | int[] arr={1,6,3,9,0,4,2,5,7}; 15 | //Set kNum = findKNum(arr, 3); 16 | 17 | getLeastNumbers(arr,arr.length,3); 18 | System.out.println(Arrays.toString(arr)); 19 | 20 | 21 | Scanner scanner = new Scanner(System.in); 22 | String next = scanner.next(); 23 | } 24 | 25 | // 基于partition这种方式会改变数组的顺序 26 | public static void getLeastNumbers(int[] arr,int length,int k){ 27 | if(arr==null || arr.length<=0 || k<=0 || k>arr.length){ 28 | return ; 29 | } 30 | int start=0; 31 | int end=length-1; 32 | int partition = partition(arr, start, end); 33 | while(partition!=k-1){ 34 | if(partition>k-1){ 35 | partition=partition(arr,start,partition-1); 36 | }else{ 37 | partition=partition(arr,partition+1,end); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * 这种时间复杂度为nlogk,时间复杂度为O(K) 44 | * @param arr 45 | * @param k 46 | * @return 47 | */ 48 | public static Set findKNum(int[] arr, int k){ 49 | TreeSet set = new TreeSet(); 50 | for(int i=0;i=key) { 69 | right--; 70 | } 71 | arr[left]=arr[right]; 72 | while(left leftToRight = new Stack(); 36 | leftToRight.add(root); 37 | Stack rightToLeft = new Stack(); 38 | 39 | while(!leftToRight.isEmpty() || !rightToLeft.isEmpty()){ 40 | if(flag){ 41 | //从左到右 42 | Node temp = leftToRight.pop(); 43 | System.out.print(temp.data+" "); 44 | if(temp.lnode!=null){ 45 | rightToLeft.add(temp.lnode); 46 | } 47 | if(temp.rnode!=null){ 48 | rightToLeft.add(temp.rnode); 49 | } 50 | 51 | if(leftToRight.isEmpty()){ 52 | System.out.println(); 53 | flag=false; 54 | } 55 | }else{ 56 | //从右到左 57 | Node temp = rightToLeft.pop(); 58 | System.out.print(temp.data+" "); 59 | if(temp.lnode!=null){ 60 | leftToRight.add(temp.rnode); 61 | } 62 | if(temp.rnode!=null) { 63 | leftToRight.add(temp.lnode); 64 | } 65 | 66 | if(rightToLeft.isEmpty()){ 67 | System.out.println(); 68 | flag=true; 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/第五章_优化时间和空间效率/数组中出现次数超过一半的数字.java: -------------------------------------------------------------------------------- 1 | package 第五章_优化时间和空间效率; 2 | 3 | /** 4 | * 即然这个数字超过了一半,那么排序后,它一定是在数组中间位置 排序最快时间复杂度为nlogn 5 | *

6 | * 如果要求时间复杂度为O(n)话,上面这种方式就不合适了 7 | */ 8 | public class 数组中出现次数超过一半的数字 { 9 | 10 | public static void main(String[] args) { 11 | int[] arr = {7, 6, 4, 7, 4, 3, 6, 7, 7, 7, 3, 7, 4, 7, 6, 7}; 12 | int moreNum = findNumByPartition(arr); 13 | System.out.println(moreNum); 14 | } 15 | 16 | /** 17 | * 第一种 基于partition快排函数,partition位于函数的数组, 18 | */ 19 | public static int findNumByPartition(int[] arr){ 20 | if(arr==null || arr.length<=0){ 21 | throw new RuntimeException("空的"); 22 | } 23 | int partition = partition(arr, 0, arr.length - 1); 24 | while(partition!=arr.length/2){ 25 | if(partition>arr.length/2){ 26 | partition = partition(arr, 0, partition-1); 27 | }else{ 28 | partition = partition(arr, partition+1, arr.length-1); 29 | } 30 | } 31 | if(partition==arr.length/2){ 32 | return arr[partition]; 33 | } 34 | return -1; 35 | } 36 | public static int partition(int[] arr, int left, int right) { 37 | int key = arr[left]; 38 | while (left < right) { 39 | while (left < right && arr[right] >= key) { 40 | right--; 41 | } 42 | arr[left] = arr[right]; 43 | while (left < right && arr[left] <= key) { 44 | left++; 45 | } 46 | arr[right]=arr[left]; 47 | } 48 | arr[left]=key; 49 | return left; 50 | } 51 | 52 | /** 53 | * 第二种 记录元素的次数,相同+1,不同则减1 54 | * 55 | * @param arr 56 | * @return 57 | */ 58 | public static int findMoreNum(int[] arr) { 59 | if (null == arr || arr.length <= 0) { 60 | return -1; 61 | } 62 | int result = arr[0]; 63 | int times = 1; 64 | for (int i = 0; i < arr.length; i++) { 65 | if (times == 0) { 66 | result = arr[i]; 67 | times = 1; 68 | } else if (arr[i] == result) { 69 | times++; 70 | } else { 71 | times--; 72 | } 73 | } 74 | return result; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/第四章_解决面试的思路/思考题_8个数字在正方体上三组相对的面上的4个顶点的和都相等.java: -------------------------------------------------------------------------------- 1 | package 第四章_解决面试的思路; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | /** 7 | * 与全排列相关的题目: 8 | * 输入一个含有8个数字的数组,判断有没有可能把这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。 9 | * 10 | * 其思路: 11 | * 先得到这8个数字的全排列,然后三个面的和相等即可. 12 | * a1+a2+a3+a4=a5+a6+a7+a8 13 | * a1+a3+a5+a7=a2+a4+a6+a8 14 | * a1+a2+a5+a6=a3+a4+a7_a8 15 | * 16 | */ 17 | public class 思考题_8个数字在正方体上三组相对的面上的4个顶点的和都相等 { 18 | 19 | public static void main(String[] args) { 20 | 21 | String str = "12345678"; 22 | // 得到全排列的结果 23 | ArrayList list = permutation(str); 24 | System.out.println("组合结果:"+list); 25 | // 判断是否有满足条件的 26 | isTrue(list); 27 | } 28 | 29 | private static void isTrue(ArrayList list) { 30 | if(list==null || list.size()<=0){ 31 | return ; 32 | } 33 | for (String str:list) { 34 | char[] c = str.toCharArray(); 35 | if((c[0]+c[1]+c[2]+c[3])==(c[4]+c[5]+c[6]+c[7]) && 36 | (c[0]+c[2]+c[4]+c[6])==(c[1]+c[3]+c[5]+c[7]) && 37 | (c[0]+c[1]+c[4]+c[6])==(c[2]+c[3]+c[6]+c[7])){ 38 | System.out.println(String.valueOf(str)); 39 | } 40 | } 41 | } 42 | 43 | public static ArrayList permutation(String str){ 44 | if(str==null || str.length()<=0){ 45 | return null; 46 | } 47 | ArrayList list = new ArrayList(); 48 | char[] chars = str.toCharArray(); 49 | permutation(chars,0,list); 50 | Collections.sort(list); 51 | return list; 52 | } 53 | 54 | public static void permutation(char[] str,int i,ArrayList list){ 55 | if(str==null){ 56 | return ; 57 | } 58 | if(i==str.length-1){ 59 | //判断当前排列是否已经包含在列表中 60 | if(!list.contains(String.valueOf(str))){ 61 | list.add(String.valueOf(str)); 62 | }else{ 63 | return; 64 | } 65 | }else{ 66 | for(int j=i;j preOrderTraverse(Node node){ 37 | List list = new ArrayList(); 38 | if(node.lnode!=null){ 39 | list.addAll(preOrderTraverse(node.lnode)); 40 | }if(node.rnode!=null){ 41 | list.addAll(preOrderTraverse(node.rnode)); 42 | } 43 | return list; 44 | } 45 | 46 | 47 | /** 48 | * 先序式非递归式的 49 | * 思路:对于任意节点T,访问这个节点并压入栈中,然后访问节点的左子树, 50 | * 遍历完左子树后,取出栈顶的节点T,再先序遍历T的右子树 51 | * @param node 52 | */ 53 | public void printBinaryTreePreUnrecur(Node node) { 54 | Node p=node; 55 | LinkedList nodes = new LinkedList(); 56 | while(p!=null || !nodes.isEmpty()){ 57 | if(p!=null){ 58 | nodes.add(p); 59 | System.out.println(p.data); 60 | p=p.lnode; 61 | }else{ 62 | p = nodes.poll(); 63 | p = p.rnode; 64 | } 65 | } 66 | } 67 | 68 | /** 69 | * 非递归的中序 70 | * 71 | */ 72 | public void printBinaryTreeMidUnrecur(Node node){ 73 | Node p=node; 74 | LinkedList nodes = new LinkedList(); 75 | while(p!=null || !nodes.isEmpty()){ 76 | if(p!=null){ 77 | nodes.add(p); 78 | p=p.lnode; 79 | }else{ 80 | p = nodes.poll(); 81 | System.out.println(p.lnode); 82 | p = p.rnode; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/第二章_面试需要的基础知识/重建二叉树.java: -------------------------------------------------------------------------------- 1 | package 第二章_面试需要的基础知识; 2 | 3 | import java.util.Stack; 4 | 5 | public class 重建二叉树 { 6 | // public static void main(String[] args) { 7 | // int [] preorder={1,2,4,7,3,5,6,8}; 8 | // int [] inorder={4,7,2,1,5,3,8,6}; 9 | // BinaryTreeNode root=constructCore(preorder,inorder); 10 | // print(root); 11 | // } 12 | // 13 | // private static BinaryTreeNode constructCore(int[] preorder, int[] inorder) { 14 | // if(null==preorder || null==inorder || (preorder.length!=inorder.length && preorder.length<=0)){ 15 | // return null; 16 | // } 17 | // 18 | // return constructCore2(preorder,inorder); 19 | // } 20 | // private static BinaryTreeNode constructCore2(int[] preorder,int[] inorder) { 21 | // //根 22 | // BinaryTreeNode root = new BinaryTreeNode(preorder[0],null,null); 23 | // if(preorder.length==1){ 24 | // return root; 25 | // } 26 | // //在中序遍历中找根结点 27 | // int index = getIndex(inorder, root.key); 28 | // 29 | // } 30 | // 31 | // //再先序输出该二叉树,递归的形式 32 | // private static void print(BinaryTreeNode root) { 33 | // if(root!=null){ 34 | // System.out.println(root.key); 35 | // print(root.left); 36 | // print(root.right); 37 | // } 38 | // } 39 | // //非递归的形式 40 | // private static void printWhile(BinaryTreeNode root){ 41 | // if(null==root){ 42 | // return; 43 | // } 44 | // Stack nodes=new Stack(); 45 | // nodes.add(root); 46 | // 47 | // while(nodes.isEmpty()){ 48 | // BinaryTreeNode pop = nodes.pop(); 49 | // if(null!=pop){ 50 | // System.out.println(pop.key); 51 | // if(null!=pop.left){ 52 | // nodes.push(pop.left); 53 | // } 54 | // if(null!=pop.right){ 55 | // nodes.push(pop.right); 56 | // } 57 | // } 58 | // } 59 | // 60 | // } 61 | // 62 | // public static int getIndex(int[] array,int temp){ 63 | // int index = -1; 64 | // for (int i = 0; i < array.length; i++) { 65 | // if (array[i]==temp) { 66 | // index = i; 67 | // return index; 68 | // } 69 | // } 70 | // return index; 71 | // } 72 | } 73 | 74 | /** 75 | * 树节点 76 | */ 77 | class BinaryTreeNode{ 78 | int key; 79 | BinaryTreeNode left; 80 | BinaryTreeNode right; 81 | public BinaryTreeNode(int key,BinaryTreeNode left,BinaryTreeNode right){ 82 | this.key=key; 83 | this.left=left; 84 | this.right=right; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # jzoffer 2 | java版剑指offer代码,包含剑指offer所有算法代码,统一用java语言进行了实现 3 | 对算法感兴趣的同学可以一起学习一下,或者将要找工作面试笔试的可以参考一下 4 | 5 | ## 算法口决 6 | * 难题首选动归 7 | * 受阻贪心暴力 8 | * 考虑分治思想 9 | * 配合排序哈希 10 | 11 | ## 第二章 面试需要的基础知识 12 | [面试题2.实现Singleton模式](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/Singleton%E6%A8%A1%E5%BC%8F.java) 13 | [面试题3.二维数组中的查找](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%9F%A5%E6%89%BE.java) 14 | [面试题4.替换空格](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E6%9B%BF%E6%8D%A2%E7%A9%BA%E6%A0%BC.java) 15 | [面试题5.从尾到头打印链表](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E4%BB%8E%E5%B0%BE%E5%88%B0%E5%A4%B4%E6%89%93%E5%8D%B0%E9%93%BE%E8%A1%A8.java) 16 | [面试题6.重建二叉树](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E9%87%8D%E5%BB%BA%E4%BA%8C%E5%8F%89%E6%A0%91.java) 17 | [面试题7.用两个栈实现队列](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E7%94%A8%E4%B8%A4%E4%B8%AA%E6%A0%88%E5%AE%9E%E7%8E%B0%E9%98%9F%E5%88%97.java) 18 | [面试题7.思考题-用两个队列实现栈](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E7%94%A8%E4%B8%A4%E4%B8%AA%E9%98%9F%E5%88%97%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E6%A0%88.java) 19 | [面试题8.旋转数组的最小数字](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E6%97%8B%E8%BD%AC%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%B0%8F%E6%95%B0.java) 20 | [面试题9.斐波那契数列](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97.java) 21 | [面试题9.青蛙跳台阶与变态跳台阶](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E8%B7%B3%E5%8F%B0%E9%98%B6%E4%B8%8E%E5%8F%98%E6%80%81%E8%B7%B3%E5%8F%B0%E9%98%B6.java) 22 | [面试题10.二进制中1的个数](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%8C%E7%AB%A0_%E9%9D%A2%E8%AF%95%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%B8%AD1%E7%9A%84%E4%B8%AA%E6%95%B0.java) 23 | ## 第三章 高质量的代码 24 | [面试题11.数值的整数次方](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E6%95%B0%E5%80%BC%E7%9A%84%E6%95%B4%E6%95%B0%E6%AC%A1%E6%96%B9.java) 25 | [面试题12.打印1到最大的n位数 -](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E6%89%93%E5%8D%B01%E8%87%B3%E6%9C%80%E5%A4%A7%E7%9A%84n%E4%BD%8D%E6%95%B0.java) 26 | [面试题13.在O(1)时间删除链表结点](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E5%9C%A8O1%E6%97%B6%E9%97%B4%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%BB%93%E7%82%B9.java) 27 | [面试题14.调整数组顺序使奇数位于偶数前面](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E8%B0%83%E6%95%B4%E6%95%B0%E7%BB%84%E9%A1%BA%E5%BA%8F%E4%BD%BF%E5%A5%87%E6%95%B0%E4%BD%8D%E4%BA%8E%E5%81%B6%E6%95%B0%E5%89%8D%E9%9D%A2.java) 28 | [面试题14.调整数组顺序使奇数位于偶数前面且保持顺序](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E5%A5%87%E6%95%B0%E4%BD%8D%E4%BA%8E%E5%89%8D%E9%9D%A2%E5%81%B6%E6%95%B0%E4%BD%8D%E4%BA%8E%E5%90%8E%E9%9D%A2%E5%B9%B6%E4%B8%94%E4%B8%8D%E6%94%B9%E5%8E%9F%E5%9C%A8%E5%8E%9F%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E9%A1%BA%E5%BA%8F.java) 29 | [面试题15.链表中倒数第k个结点](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E9%93%BE%E8%A1%A8%E4%B8%AD%E5%80%92%E6%95%B0%E7%AC%ACk%E4%B8%AA%E7%BB%93%E7%82%B9.java) 30 | [面试题16.反转链表](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E5%8F%8D%E8%BD%AC%E9%93%BE%E8%A1%A8.java) 31 | [面试题17.合并两个排序的链表](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%8E%92%E5%BA%8F%E7%9A%84%E9%93%BE%E8%A1%A8.java) 32 | [面试题18.树的子结构](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/%E6%A0%91%E7%9A%84%E5%AD%90%E7%BB%93%E6%9E%84.java) 33 | ## 第四章 解决面试题的思路 34 | [面试题19.二叉树的镜像](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%95%9C%E5%83%8F.java) 35 | [面试题20.顺时针打印矩阵](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E9%A1%BA%E6%97%B6%E9%92%88%E6%89%93%E5%8D%B0%E7%9F%A9%E9%98%B5.java) 36 | [面试题21.包含min函数的栈](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E5%8C%85%E5%90%ABmin%E5%87%BD%E6%95%B0%E7%9A%84%E6%A0%88.java) 37 | [面试题22.栈的压入、弹出序列](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E6%A0%88%E7%9A%84%E5%8E%8B%E5%85%A5%E5%8F%8A%E5%BC%B9%E5%87%BA%E5%BA%8F%E5%88%97.java) 38 | [面试题23.从上往下打印二叉树](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E4%BB%8E%E4%B8%8A%E5%BE%80%E4%B8%8B%E6%89%93%E5%8D%B0%E4%BA%8C%E5%8F%89%E6%A0%91.java) 39 | [面试题23.从上往下打印二叉树按行打印](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E4%BB%8E%E4%B8%8A%E5%BE%80%E4%B8%8B%E6%89%93%E5%8D%B0%E4%BA%8C%E5%8F%89%E6%A0%91_%E6%8C%89%E8%A1%8C%E6%89%93%E5%8D%B0.java) 40 | [面试题23.之字打印二叉树](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E4%B9%8B%E5%AD%97%E6%89%93%E5%8D%B0%E4%BA%8C%E5%8F%89%E6%A0%91.java) 41 | [面试题24.二叉搜索树的后序遍历序列](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97.java) 42 | [面试题25.二叉树中和为某一值的路径](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%AD%E5%92%8C%E4%B8%BA%E6%9F%90%E4%B8%80%E5%80%BC%E7%9A%84%E8%B7%AF%E5%BE%84.java) 43 | [面试题26.复杂链表的复制-](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E5%A4%8D%E6%9D%82%E9%93%BE%E8%A1%A8%E7%9A%84%E5%A4%8D%E5%88%B6.java) 44 | [面试题27.二叉搜索树与双向链表-]() 45 | [面试题28.字符串的排列](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%8E%92%E5%88%97.java) 46 | [面试题28.字符串的组合](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E7%BB%84%E5%90%88.java) 47 | [面试题28.字符串的排列去重](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%85%A8%E6%8E%92%E5%88%97_%E5%8E%BB%E9%99%A4%E9%87%8D%E5%A4%8D.java) 48 | [思考题 8个数字在正方体上三组相对的面上的4个顶点的和都相等](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E6%80%9D%E8%80%83%E9%A2%98_8%E4%B8%AA%E6%95%B0%E5%AD%97%E5%9C%A8%E6%AD%A3%E6%96%B9%E4%BD%93%E4%B8%8A%E4%B8%89%E7%BB%84%E7%9B%B8%E5%AF%B9%E7%9A%84%E9%9D%A2%E4%B8%8A%E7%9A%844%E4%B8%AA%E9%A1%B6%E7%82%B9%E7%9A%84%E5%92%8C%E9%83%BD%E7%9B%B8%E7%AD%89.java) 49 | 50 | ## 第五章 优化时间和空间效率 51 | [面试题29.数组中出现次数超过一半的数字](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%94%E7%AB%A0_%E4%BC%98%E5%8C%96%E6%97%B6%E9%97%B4%E5%92%8C%E7%A9%BA%E9%97%B4%E6%95%88%E7%8E%87/%E6%95%B0%E7%BB%84%E4%B8%AD%E5%87%BA%E7%8E%B0%E6%AC%A1%E6%95%B0%E8%B6%85%E8%BF%87%E4%B8%80%E5%8D%8A%E7%9A%84%E6%95%B0%E5%AD%97.java) 52 | [面试题30.最小的k个数](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%94%E7%AB%A0_%E4%BC%98%E5%8C%96%E6%97%B6%E9%97%B4%E5%92%8C%E7%A9%BA%E9%97%B4%E6%95%88%E7%8E%87/%E6%9C%80%E5%B0%8F%E7%9A%84k%E4%B8%AA%E6%95%B0.java) 53 | [面试题31.连续子数组的最大和](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E4%BA%94%E7%AB%A0_%E4%BC%98%E5%8C%96%E6%97%B6%E9%97%B4%E5%92%8C%E7%A9%BA%E9%97%B4%E6%95%88%E7%8E%87/%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%A4%A7%E5%92%8C.java) 54 | ## 第六章 面试中的各项能力 55 | [面试题38.数字在排序数组中出现的次数](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E6%95%B0%E5%AD%97%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0.java) 56 | [面试题39.二叉树的深度](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%B7%B1%E5%BA%A6.java) 57 | [面试题39.判断二叉树是否平衡二叉树](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E5%88%A4%E6%96%AD%E4%BA%8C%E5%8F%89%E6%A0%91%E6%98%AF%E5%90%A6%E4%B8%BA%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91.java) 58 | [面试题40.数组中只出现一次的数字](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E6%95%B0%E7%BB%84%E4%B8%AD%E5%8F%AA%E5%87%BA%E7%8E%B0%E4%B8%80%E6%AC%A1%E7%9A%84%E6%95%B0%E5%AD%97.java) 59 | [面试题41.和为s的两个数](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E5%92%8C%E4%B8%BAs%E7%9A%84%E4%B8%A4%E4%B8%AA%E6%95%B0.java) 60 | [面试题41.和为s的连续正数序列](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E5%92%8C%E4%B8%BAs%E7%9A%84%E8%BF%9E%E7%BB%AD%E6%AD%A3%E6%95%B0%E5%BA%8F%E5%88%97.java) 61 | [面试题42.翻转单词顺序](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E7%BF%BB%E8%BD%AC%E5%8D%95%E8%AF%8D%E9%A1%BA%E5%BA%8F.java) 62 | [面试题42.左旋字符串](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%85%AD%E7%AB%A0_%E9%9D%A2%E8%AF%95%E4%B8%AD%E7%9A%84%E5%90%84%E9%A1%B9%E8%83%BD%E5%8A%9B/%E5%AD%97%E7%AC%A6%E5%8F%8D%E8%BD%AC.java) 63 | ## 第八章 英文版新增面试题 64 | [面试题51.数组中重复的数字](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC8%E7%AB%A0_%E8%8B%B1%E6%96%87%E7%89%88%E6%96%B0%E5%A2%9E%E9%9D%A2%E8%AF%95%E9%A2%98/%E6%95%B0%E7%BB%84%E4%B8%AD%E9%87%8D%E5%A4%8D%E7%9A%84%E6%95%B0%E5%AD%97.java) 65 | [面试题56.链表中环的入口结点](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC8%E7%AB%A0_%E8%8B%B1%E6%96%87%E7%89%88%E6%96%B0%E5%A2%9E%E9%9D%A2%E8%AF%95%E9%A2%98/%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%8E%AF%E7%9A%84%E5%85%A5%E5%8F%A3%E7%BB%93%E7%82%B9.java) 66 | [面试题57.删除链表中重复的结点](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC8%E7%AB%A0_%E8%8B%B1%E6%96%87%E7%89%88%E6%96%B0%E5%A2%9E%E9%9D%A2%E8%AF%95%E9%A2%98/%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E4%B8%AD%E9%87%8D%E5%A4%8D%E7%9A%84%E7%BB%93%E7%82%B9.java) 67 | [面试题58.二叉树的下一个结点](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC8%E7%AB%A0_%E8%8B%B1%E6%96%87%E7%89%88%E6%96%B0%E5%A2%9E%E9%9D%A2%E8%AF%95%E9%A2%98/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E4%B8%8B%E4%B8%80%E4%B8%AA%E7%BB%93%E7%82%B9.java) 68 | [面试题59.对称的二叉树](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC8%E7%AB%A0_%E8%8B%B1%E6%96%87%E7%89%88%E6%96%B0%E5%A2%9E%E9%9D%A2%E8%AF%95%E9%A2%98/%E5%AF%B9%E7%A7%B0%E7%9A%84%E4%BA%8C%E5%8F%89%E6%A0%91.java) 69 | [面试题60.把二叉树打印成多行](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC8%E7%AB%A0_%E8%8B%B1%E6%96%87%E7%89%88%E6%96%B0%E5%A2%9E%E9%9D%A2%E8%AF%95%E9%A2%98/%E6%8A%8A%E4%BA%8C%E5%8F%89%E6%A0%91%E6%89%93%E5%8D%B0%E6%88%90%E5%A4%9A%E8%A1%8C.java) 70 | [面试题61.按之字形顺序打印二叉树](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E7%AC%AC%E5%9B%9B%E7%AB%A0_%E8%A7%A3%E5%86%B3%E9%9D%A2%E8%AF%95%E7%9A%84%E6%80%9D%E8%B7%AF/%E4%BB%8E%E4%B8%8A%E5%BE%80%E4%B8%8B%E6%89%93%E5%8D%B0%E4%BA%8C%E5%8F%89%E6%A0%91_%E6%8C%89%E8%A1%8C%E6%89%93%E5%8D%B0.java) 71 | ## 扩展——动态规划 72 | [不能相邻的两个数的最大和](https://github.com/lvCmx/jzoffer/tree/master/src/main/java/%E6%89%A9%E5%B1%95_%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/%E4%B8%8D%E8%83%BD%E7%9B%B8%E9%82%BB%E7%9A%84%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%9A%84%E6%9C%80%E5%A4%A7%E5%92%8C) 73 | [最大的利益](https://github.com/lvCmx/jzoffer/tree/master/src/main/java/%E6%89%A9%E5%B1%95_%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/%E6%9C%80%E5%A4%A7%E7%9A%84%E5%88%A9%E7%9B%8A) 74 | [求数组中的数之和为指定的数](https://github.com/lvCmx/jzoffer/tree/master/src/main/java/%E6%89%A9%E5%B1%95_%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/%E6%B1%82%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%95%B0%E4%B9%8B%E5%92%8C%E4%B8%BA%E6%8C%87%E5%AE%9A%E7%9A%84%E6%95%B0) 75 | [连续子数组的最大和](https://github.com/lvCmx/jzoffer/blob/master/src/main/java/%E6%89%A9%E5%B1%95_%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92/%E8%BF%9E%E7%BB%AD%E5%AD%90%E6%95%B0%E7%BB%84%E7%9A%84%E6%9C%80%E5%A4%A7%E5%92%8C/Main.java) 76 | --------------------------------------------------------------------------------