Problem2:实现Singleton模式
题目描述:设计一个类,我们只能生成该类的一个实例
1 packageProblem2;2
3 public classSingletonClass {4
5 /*
6 * 题目描述:设计一个类,我们只能生成该类的一个实例7 */
8 //volatile:防止指令重排序
9 private static volatileSingletonClass instance;10
11 privateSingletonClass() {12 }13
14 public staticSingletonClass getInstace() {15 if (instance == null) {16 synchronized (SingletonClass.class) {17 if (instance == null) {18 instance = newSingletonClass();19 }20 }21 }22
23 returninstance;24
25 }26
27 }
Problem3:二维数组中的查找
题目描述:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下的顺序排序。 完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否包含该整数;
1 packageProblem3;2
3 public classFind {4
5 /*
6 * 题目描述:二维数组中的查找7 * 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下的顺序排序。8 * 完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否包含该整数9 *10 */
11 public static boolean find(int arr[][],intkeyNumber){12 //从二维数组的右上角开始选取与keyNumber比较的整数13 //column的变化:arr[0].length-1-->0;14 //row的变化:0-->arr.length;
15 int column=arr[0].length-1;16 int row=0;17 while(column>=0&&rowkeyNumber){22 column--;23 }24 else{25 row++;26 }27 }28 return false;29
30 }31 //测试find函数
32 public static voidmain(String[] args) {33 /*
34 * 1 2 8 935 * 2 4 9 1236 * 4 7 10 1337 * 6 8 11 1538 */
39 int array[][]=new int[4][4];40 array[0][0]=1;41 array[0][1]=2;42 array[0][2]=8;43 array[0][3]=9;44 array[1][0]=2;45 array[1][1]=4;46 array[1][2]=9;47 array[1][3]=12;48 array[2][0]=4;49 array[2][1]=7;50 array[2][2]=10;51 array[2][3]=13;52 array[3][0]=6;53 array[3][1]=8;54 array[3][2]=11;55 array[3][3]=15;56 System.out.println(find(array, 7));57 System.out.println(find(array, 5));58 }59
60 }
同理,比较关键字也可以从二维数组的左下角开始选择,则column和row的增减方式调换一下,但是不能选择左上角和右下角的元素作为与查找元素比较的关键字,因为无论比较结果怎样,都无法进一步缩小查找的范围。
Problem4:替换空格
题目描述:请实现一个函数,将字符串的每个空格替换为"%20"。例如输入"We are happy",则输出"We%20are%20happy."。
1 packageProblem4;2
3 public classReplaceBank {4
5 /*
6 * 题目描述: 请实现一个函数,将字符串的每个空格替换为"%20"。7 * 例如输入"We are happy",则输出"We%20are%20happy."。8 */
9 /**
10 *@paramargs11 */
12
13 publicString replace(String input) {14 StringBuilder builder = newStringBuilder();15 if (input == null || input.length() == 0) {16 return null;17 }18 for (int i = 0; i < input.length(); i++) {19 if (input.charAt(i) == ' ') {20 builder.append("%");21 builder.append("2");22 builder.append("0");23 } else{24 builder.append(input.charAt(i));25 }26 }27 returnbuilder.toString();28 }29
30 //测试用例
31 public static voidmain(String[] args) {32 ReplaceBank test = newReplaceBank();33 //输入的字符串包含空格:最后面,最前面,中间,连续空格
34 String str1 = "We are happy.";35 String str2 = " Wearehappy.";36 String str3 = "Wearehappy. ";37 String str4 = "We are happy .";38 //输入的字符串没有空格
39 String str5="Wearehappy.";40 //特殊输入测试:字符串只有连续空格、只有一个空格、字符串是一个null指针、字符串是一个空字符串;
41 String str6=" ";42 String str7=" ";43 String str8=null;44 String str9="";45 System.out.println(test.replace(str1));46 System.out.println(test.replace(str2));47 System.out.println(test.replace(str3));48 System.out.println(test.replace(str4));49 System.out.println(test.replace(str5));50 System.out.println(test.replace(str6));51 System.out.println(test.replace(str7));52 System.out.println(test.replace(str8));53 System.out.println(test.replace(str9));54 }55
56 }
Problem5:从尾到头打印链表
题目描述:输入一个链表的头结点,从尾到头反过来打印出每个结点的值.
1 packageProblem5;2
3 importjava.util.Stack;4
5 //首先定义链表结构
6 classLinkNode{7 LinkNode next;8 intnode_value;9 }10
11 public classPrintListReverse {12 public voidreverse(LinkNode headNode){13 //用栈的思想来实现链表的倒序输出
14 Stack stack=new Stack();15 while(headNode!=null){16 stack.push(headNode);17 headNode=headNode.next;18 }19 while(!stack.isEmpty()){20 System.out.print(stack.pop().node_value+" ");21 }22 System.out.println();23 }24
25 /**
26 *@paramargs27 */
28 public static voidmain(String[] args) {29 //输入的链表有多个结点
30 PrintListReverse plr=newPrintListReverse();31 LinkNode node1=newLinkNode();32 LinkNode node2=newLinkNode();33 LinkNode node3=newLinkNode();34 node1.node_value=1;35 node2.node_value=2;36 node3.node_value=3;37 node1.next=node2;38 node2.next=node3;39 plr.reverse(node1);40 }41
42 }
Problem5:重建二叉树
题目描述:输入某二叉树的前序遍历和中序遍历结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不包含重复的数字。例如输入前序遍历序列:{1,2,4,7,3,5,6,8}和中序遍历{4,7,2,1,5,3,8,6},则重建出图中所示二叉树并且输出它的头结点。
重建的二叉树:
1 packageProblem6;2
3 /*重建二叉树4 * 问题描述:输入某二叉树的前序遍历和中序遍历结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中5 * 都不包含重复的数字。例如输入前序遍历序列:{1,2,4,7,3,5,6,8}和中序遍历{4,7,2,1,5,3,8,6},6 * 则重建出图中所示二叉树并且输出它的头结点。7 */
8 //定义二叉树节点
9 classBinaryTreeNode {10 public intvalue;11 publicBinaryTreeNode leftNode;12 publicBinaryTreeNode rightNode;13
14 //无参构造函数
15 publicBinaryTreeNode() {16
17 }18
19 //有参构造函数
20 public BinaryTreeNode(intvalue) {21 this.value =value;22 this.leftNode = null;23 this.rightNode = null;24 }25 }26
27 public classConstructBinaryTree {28
29 public static BinaryTreeNode construct(int preOrder[], intinOrder[],30 int length) throwsException {31 if (preOrder == null || inOrder == null || length < 0) {32 return null;33 }34 return constructCore(preOrder, 0, preOrder.length - 1, inOrder, 0,35 inOrder.length - 1);36 }37
38 public static BinaryTreeNode constructCore(intpreOrder[],39 int startPreIndex, int endPreIndex, intinOrder[],40 int startInIndex, int endInIndex) throwsInvalidPutException {41 //头结点的值
42 int rootValue =preOrder[startInIndex];43
44 //构建一个只有一个根节点的二叉树
45 BinaryTreeNode root = newBinaryTreeNode(rootValue);46 //只有一个元素的情况下:
47 if (startPreIndex ==endPreIndex) {48 if (startInIndex ==endInIndex49 && preOrder[startInIndex] ==inOrder[endInIndex]) {50 System.out.println("只有一个元素");51 returnroot;52 } else{53 throw newInvalidPutException();54 }55
56 }57 //最重要的一步:在中序遍历中找到根结点的索引
58 int rootInIndex =startInIndex;59 while (rootInIndex <= endInIndex && inOrder[rootInIndex] !=rootValue) {60 rootInIndex++;61 }62 if (rootInIndex == endInIndex && inOrder[rootInIndex] !=rootInIndex) {63 throw newInvalidPutException();64 }65 //根节点的左子树的长度
66 int leftLength = rootInIndex -startInIndex;67 //根节点的左子树的最右端的索引值
68 int leftPreEndIndex = startPreIndex +leftLength;69 //构建左子树
70 if (leftLength > 0) {71 root.leftNode = constructCore(preOrder, startPreIndex + 1,72 leftPreEndIndex, inOrder, startInIndex, rootInIndex - 1);73 }74 //说明根节点存在右子树
75 if (leftLength < endPreIndex -startPreIndex) {76 root.rightNode = constructCore(preOrder, leftPreEndIndex + 1,77 endPreIndex, inOrder, rootInIndex + 1, endInIndex);78 }79 returnroot;80 }81
82 //按照前序遍历打印二叉树的节点
83 public static voidprintPreBinaryTree(BinaryTreeNode root) {84 if (root == null) {85 return;86 } else{87 System.out.println(root.value + " ");88 }89 if (root.leftNode != null) {90 printPreBinaryTree(root.leftNode);91 }92 if (root.rightNode != null) {93 printPreBinaryTree(root.rightNode);94 }95 }96
97 public static class InvalidPutException extendsException {98
99 private static final long serialVersionUID = 1L;100 }101
102 /**
103 *@paramargs104 *@throwsException105 */
106 public static void main(String[] args) throwsException {107 int preOrder[] = { 1, 2, 4, 7, 3, 5, 6, 8};108 int inOrder[] = { 4, 7, 2, 1, 5, 3, 8, 6};109 ConstructBinaryTree test = newConstructBinaryTree();110 printPreBinaryTree(test.construct(preOrder, inOrder, preOrder.length));111 }112
113 }
Problem7:用两个栈实现队列
题目描述:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能
1 packageProblem7;2
3 importjava.util.Stack;4
5 public classConStructQueue {6 /*
7 * 问题描述:用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,8 * 分别完成在队列尾部插入结点和在队列头部删除结点的功能9 */
10
11 /**
12 *@paramargs13 */
14 Stack stack1 = new Stack();15 Stack stack2 = new Stack();16
17 //实现appendTail函数
18 public voidappendTail(String s) {19 stack1.push(s);20 }21
22 //实现deleteHead函数
23 public String deleteHead() throwsException {24 if(stack2.isEmpty()) {25 while (!stack1.isEmpty()) {26 stack2.push(stack1.pop());27 }28 }29 if(stack2.isEmpty()) {30 throw new Exception("队列为空,不能进行删除操作");31 }32 returnstack2.pop();33 }34
35 public static void main(String[] args) throwsException {36 ConStructQueue test = newConStructQueue();37 //向空的队列中添加元素、删除元素
38 test.appendTail("1");39 System.out.println(test.deleteHead());40 //向非空的队列添加删除元素
41 test.appendTail("2");42 test.appendTail("3");43 System.out.println(test.deleteHead());44
45 }46
47 }
Problem8:旋转数组的最小数字
题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1;
1 packageProblem8;2
3 public classMinInReversingList {4 /*
5 * 题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。6 * 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1;7 */
8
9 /**
10 *@paramargs11 *@throwsException12 */
13 public static int minElement(int array[]) throwsException {14 //条件判断
15 if (array == null || array.length <= 0) {16 throw new Exception("Invalid parameters");17 }18 int left = 0;19 int right = array.length - 1;20 int mid =left;21 while (array[left] >=array[right]) {22 //跳出循环的条件
23 if (right - left == 1) {24 mid =right;25 break;26 }27 mid = (left + right) / 2;28 if (array[left] == array[mid] && array[mid] ==array[right]) {29 returnminFromSortSearch(array);30 //算法的核心思想
31 } else{32 if (array[mid] >=array[left]) {33 left =mid;34 }35 if (array[mid] <=array[right]) {36 right =mid;37 }38 }39 }40 returnarray[right];41 }42
43 public static int minFromSortSearch(int[] array) {44 int minEle = array[0];45 for (int i = 1; i < array.length; i++) {46 if (array[i]
53 //测试
54 public static void main(String[] args) throwsException {55 //功能测试:输入的数组是升序排序数组的一个旋转,数组中有重复数字或者没有重复数字
56 int array1[] = { 3, 4, 5, 1, 2};57 System.out.println(minElement(array1));58 int array2[] = { 3, 4, 5, 3, 3};59 System.out.println(minElement(array2));60 //边界测试:输入的数组是一个升序排序数组、只包含一个数字的数组
61 int array3[] = { 3};62 System.out.println(minElement(array3));63 //特殊输入测试:输入null指针
64 int array4[] = null;65 System.out.println(minElement(array4));66 }67
68 }
Problem9:斐波那契数列
题目描述:写一个函数,输入n,求斐波那契数列的第n项,斐波那契数列的定义如下: n=0,f(n)=0 ;n=1,f(n)=1 n>1;f(n)=f(n-1)+f(n-2).
1 packageProblem9;2
3 public classFibonacci {4 /*
5 * 题目描述: 写一个函数,输入n,求斐波那契数列的第n项,斐波那契数列的定义如下: n=0,f(n)=0 n=1,f(n)=16 * n>1;f(n)=f(n-1)+f(n-2)7 */
8
9 /**
10 *@paramargs11 */
12 //解法1:用递归解决,但是存在很严重的效率问题,做了很多次的重复计算
13 public static int Fib1(intn) {14 if (n == 0) {15 return 0;16 } else if (n == 1) {17 return 1;18 } else{19 return Fib1(n - 1) + Fib1(n - 2);20 }21
22 }23
24 //解法2:时间复杂度为O(n),从下向上计算,保存已经计算过的数值,避免重复计算
25 public static long Fib2(intn) {26 long FibOne = 0;27 long FibTwo = 1;28 long FibN = 0;29 int result[] = { 1, 2};30 if (n < 2) {31 returnresult[n];32 } else{33 for (int i = 2; i <= n; i++) {34 FibN = FibTwo +FibOne;35 FibOne =FibTwo;36 FibTwo =FibN;37 }38 }39 returnFibN;40 }41
42 public static voidmain(String[] args) {43 //用解法1求序列的第100项,直接不动了44 //System.out.println(Fib1(100));
45 System.out.println(Fib2(100));46 }47 }
相关题目:一只青蛙一次可以跳上一级台阶,也可以跳上2级。求该青蛙跳上一个n级台阶共有多少种跳法;
Problem10:二进制中1的个数
问题描述: 请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1 因此如果输入9,该函数输出2;
1 packageProblem10;2
3 public classNumberOf1 {4 /*
5 * 问题描述: 请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1 因此如果输入9,该函数输出26 */
7
8 /**
9 *@paramargs10 */
11 //可能引起死循环的解法1
12 public static int numberof1_1(intn) {13 int count = 0;14 while (n != 0) {15 if ((n & 1) != 0) {16 count++;17 }18 n = n >> 1;19 }20 returncount;21 }22
23 //常规解法2
24 public static int numberof1_2(intn) {25 int count = 0;26 int flag = 1;27 while (flag != 0) {28 if ((n & flag) != 0) {29 count++;30 }31 flag = flag << 1;32 }33 returncount;34 }35
36 //解法3:把一个吧整数减去1,再和原整数做位与运算,会把该整数最右边一个1变成037 //一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作
38 public static int numberof1_3(intn) {39 int count = 0;40 while (n != 0) {41 count++;42 n = n & (n - 1);43 }44 returncount;45 }46
47 public static voidmain(String[] args) {48 NumberOf1 test = newNumberOf1();49 //测试一下解法1
50 System.out.println("解法1:" + test.numberof1_1(9));51 //测试一下解法2
52 System.out.println("解法2:" + test.numberof1_2(100254));53 //测试一下解法3:正数(边界值)、负数、0
54 System.out.println("解法3:" + test.numberof1_3(0x7FFFFFFF));55 System.out.println("解法3:" + test.numberof1_3(1));56 System.out.println("解法3:" + test.numberof1_3(0x80000000));57 System.out.println("解法3:" + test.numberof1_3(0xFFFFFFFF));58 System.out.println("解法3:" + test.numberof1_3(0));59 }60
61 }
Problem11:数值的整数次方
问题描述:实现函数double power(double base,int exponent),求base的exponent次方。不能使用库函数,同时不需要考虑大数问题。
1 packageProblem11;2
3 public classPower {4 /*
5 * 问题描述: 实现函数double power(double base,int exponent),求base的exponent6 * 次方。不能使用库函数,同时不需要考虑大数问题。7 */
8
9 /**
10 *@paramargs11 */
12 public double power(double base, int exponet) throwsException {13 double result = 0.0;14 if (equals(base, 0) && (exponet < 0)) {15 throw new Exception("0的负数次幂无意义");16 }17 if (exponet == 0) {18 return 1.0;19 }20 if (exponet < 0) {21 result = powerWithUnsignedExponent(base, -exponet);22 } else{23 result =powerWithUnsignedExponent(base, exponet);24 }25 returnresult;26 }27
28 private double powerWithUnsignedExponent(double base, intexponet) {29 double result = 1.0;30 for (int i = 1; i <= exponet; i++) {31 result = result *base;32 }33 returnresult;34 }35
36 //由于计算机中表示小数都有误差,不能用等号判断两个小数是否相等。如果两个小数的差的绝对值很小37 //我们就可以认为它们是相等的
38 private boolean equals(double number1, intnumber2) {39 if ((number1 - number2 > -0.00000001)40 && (number1 - number2) < 0.00000001) {41 return true;42 }43 return false;44 }45
46 //写测试:把底数和指数分别设置成正数、负数、0;
47 public static void main(String[] args) throwsException {48 Power test = newPower();49 System.out.println(test.power(2, 3));50 System.out.println(test.power(2, 0));51 System.out.println(test.power(2, -2));52 System.out.println(test.power(0, 3));53 System.out.println(test.power(0, 0));54 System.out.println(test.power(0, -2));55
56 }57
58 }
Problem13:O(1)时间删除链表结点
问题描述:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
1 packageProblem13;2
3 /*
4 * 问题描述:给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。5 *6 */
7 //定义结点的结构
8 classListNode {9 ListNode nextNode;10 intnodeValue;11 }12
13 public classDeleteNode {14 public static voiddeleteNode(ListNode head, ListNode deListNode) {15 //空链表
16 if (head == null || deListNode == null) {17 return;18 }19 //要删除的链表中只有一个结点
20 if (head ==deListNode) {21 head = null;22 } else{23 //要删除的结点不在链表的中间,不在尾部
24 if (deListNode.nextNode != null) {25 deListNode.nodeValue =deListNode.nextNode.nodeValue;26 deListNode.nextNode =deListNode.nextNode.nextNode;27 } else{28 ListNode pointNode =head;29 while (pointNode.nextNode !=deListNode) {30 pointNode =pointNode.nextNode;31 }32 pointNode.nextNode = null;33 }34 }35 }36
37 /**
38 *@paramargs39 */
40 //测试代码
41 public static voidmain(String[] args) {42 DeleteNode test = newDeleteNode();43 ListNode firListNode = newListNode();44 ListNode secListNode = newListNode();45 ListNode thiListNode = newListNode();46 firListNode.nextNode =secListNode;47 secListNode.nextNode =thiListNode;48 firListNode.nodeValue = 1;49 secListNode.nodeValue = 2;50 thiListNode.nodeValue = 3;51 test.deleteNode(firListNode, thiListNode);52 System.out.println(firListNode.nextNode.nodeValue);53 }54
55 }
Problem14:调整数组顺序使奇数位与偶数的后面
问题描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位与数组的前半部分,所有偶数位与数组的后半部分;
1 packageProblem14;2
3 /*
4 * 问题描述:5 * 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位与数组的前半部分,所有偶数位与数组的6 * 后半部分7 */
8 public classReorderOddEven {9 public static void reOrder(intarray[]) {10 int firstIndex = 0;11 int lastIndex = array.length - 1;12 if (array == null || (0 ==array.length)) {13 return;14 }15 while (firstIndex
30 //进行解耦操作:odd(奇数)、even(偶数)
31 private static boolean isEven(intn) {32
33 return (n & 1) == 0;34 }35
36 public static void printArr(intarray[]) {37 for (int i = 0; i < array.length; i++) {38 System.out.print(array[i] + "");39 }40 }41
42 /**
43 *@paramargs44 *@throwsException45 */
46 public static voidmain(String[] args) {47 ReorderOddEven test = newReorderOddEven();48 //功能测试49 //奇偶交替出现
50 int array1[] = { 1, 2, 3, 4, 5, 6};51 test.reOrder(array1);52 printArr(array1);53 System.out.println("------1------");54 //所有偶数都位于奇数的前面
55 int array2[] = { 8, 2, 4, 5, 3, 6};56 test.reOrder(array2);57 printArr(array2);58 System.out.println("------2------");59 //所有奇数都位于偶数的前面
60 int array3[] = { 5, 3, 1, 7, 2, 4, 6, 8};61 test.reOrder(array3);62 printArr(array3);63 System.out.println("------3------");64 //输入的数组只有一个元素
65 int array4[] = { 2};66 test.reOrder(array4);67 printArr(array4);68 System.out.println("------4------");69 //特殊输入测试:输入null指针
70 int array5[] = null;71 test.reOrder(array5);72 printArr(array5);73 System.out.println("------5------");74
75 }76
77 }
对应OJ在线编程题目:
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
解法一:时间复杂度为O(n^2);
1 public classSolution {2 public void reOrderArray(int[] array) {3 for(int i=0;i
16 }17 }
解法二:时间复杂度O(n),空间复杂度O(n)
1 public classSolution {2 public void reOrderArray(int[] array) {3
4 reOrderCore(array,array.length);5 }6 private void reOrderCore(int array[],intlen){7
8 if(array==null||array.length==0){9 return;10 }11
12 //用空间换时间
13 int newArray[]=new int[len];14 int index=0;15 for(int i=0;i
Problem15:链表中倒数第K个结点
问题描述:输入一个链表,输出该链表中倒数第K个结点。为了符合大多数人的习惯,从1开始计数,即链表的尾结点是倒数第一个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、5、6.这个链表的倒数第三个结点是值为4的结点。
1 packageProblem15;2
3 /*
4 * 问题描述:5 * 输入一个链表,输出该链表中倒数第K个结点。为了符合大多数人的习惯,从1开始计数,即链表的6 * 尾结点是倒数第一个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、5、6.7 * 这个链表的倒数第三个结点是值为4的结点。8 */
9
10 //定义链表的结点结构
11 classListNode {12 ListNode next;13 intdata;14
15 public ListNode(intdata) {16 this.data =data;17 }18 }19
20 public classFindKthFromTail {21
22 /*
23 * 需要考虑三种情况: 1.链表为空; 2.链表的长度不足k; 3.k=0;24 */
25
26 public static int find(ListNode head, intk) {27 if (head == null || (0 ==k)) {28 return 0;29 }30 ListNode first =head;31 ListNode second = null;32 //第一个指针先走k-1
33 for (int i = 1; i < k; i++) {34 if (first.next != null) {35 first =first.next;36 } else{37 return 0;38 }39 }40 second =head;41 while (first.next != null) {42 first =first.next;43 second =second.next;44 }45 returnsecond.data;46 }47
48 /**
49 *@paramargs50 */
51 //进行测试
52 public static voidmain(String[] args) {53 FindKthFromTail test = newFindKthFromTail();54 //功能测试:第K个结点位与链表的中间、头部、尾部
55 ListNode node1 = new ListNode(1);56 ListNode node2 = new ListNode(2);57 ListNode node3 = new ListNode(3);58 ListNode node4 = new ListNode(4);59 node1.next =node2;60 node2.next =node3;61 node3.next =node4;62 node4.next = null;63 System.out.println(test.find(node1, 3));64 System.out.println(test.find(node1, 1));65 System.out.println(test.find(node1, 4));66 //特殊输入测试:k=0
67 System.out.println(test.find(node1, 0));68 //k>4
69 System.out.println(test.find(node1, 5));70 //链表为空
71 node1 = null;72 System.out.println(test.find(node1, 3));73 }74
75 }
Problem16:反转链表
问题描述:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。
解法一:非递归实现
1 packageProblem16;2
3 /*
4 * 问题描述:5 * 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。6 */
7 //定义链表的结点结构
8 classListNode {9 ListNode next;10 intdata;11
12 public ListNode(intdata) {13 this.data =data;14 }15 }16
17 public classReversList {18
19 public static intgetReverseListHead(ListNode head) {20 //定义一个结点,用来保存找到的反转链表的表头结点21 //当前正在遍历的结点p
22 ListNode pNode =head;23 //结点p的前一个结点
24 ListNode preNode = null;25 //结点p的后一个结点
26 ListNode reversHeadNode = null;27 if (head == null) {28 return 0;29 }30 if (head.next == null) {31 returnhead.data;32 } else{33 while (pNode != null) {34 ListNode nextNode = null;35 nextNode =pNode.next;36 if (nextNode == null) {37 reversHeadNode =pNode;38 }39 pNode.next =preNode;40 preNode =pNode;41 pNode =nextNode;42 }43 }44 returnreversHeadNode.data;45
46 }47
48 /**
49 *@paramargs50 */
51 //测试
52 public static voidmain(String[] args) {53 ReversList test = newReversList();54 ListNode node1 = new ListNode(1);55 ListNode node2 = new ListNode(2);56 ListNode node3 = new ListNode(3);57 ListNode node4 = new ListNode(4);58 node1.next =node2;59 node2.next =node3;60 node3.next =node4;61 node4.next = null;62 //功能测试:链表中有多个结点、有一个结点63 //特殊输入测试:链表头结点为null指针
64 System.out.println(test.getReverseListHead(node1));65 }66
67 }
解法二:递归实现
1 /*
2 public class ListNode {3 int val;4 ListNode next = null;5
6 ListNode(int val) {7 this.val = val;8 }9 }*/
10 public classSolution {11 publicListNode ReverseList(ListNode head) {12 //链表只有一个节点或者到达了链表的尾部
13 if(head==null||head.next==null){14 returnhead;15 }16 ListNode newList=ReverseList(head.next);17
18 head.next.next=head;19 head.next=null;20 returnnewList;21 }22 }
Problem17:合并两个排序的链表
问题描述: 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。
1 packageProblem17;2
3 /*
4 * 问题描述:5 * 输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。6 */
7
8 //定义链表结点的结构
9 classListNode {10 ListNode next;11 intdata;12
13 publicListNode() {14
15 }16
17 public ListNode(intdata) {18 this.data =data;19 }20 }21
22 public classMergeList {23
24 public staticListNode Merge(ListNode head1, ListNode head2) {25 if (head1 == null) {26 returnhead2;27 }28 if (head2 == null) {29 returnhead1;30 }31 ListNode mergeNode = null;32 ;33 if (head1.data
43 public static voidprintList(ListNode merge) {44 ListNode head =merge;45 while (head != null) {46 System.out.print(head.data);47 head =head.next;48 }49 System.out.println();50 }51
52 /**
53 *@paramargs54 */
55
56 //测试
57 public static voidmain(String[] args) {58 //功能测试:输入的两个链表有多个结点,结点的值互不相同或者存在相等的多个结点59 //特殊输入测试:两个链表中的一个或者两个头结点为null指针、两个链表中只有一个结点
60 MergeList test = newMergeList();61 ListNode head1 = new ListNode(2);62 ListNode head2 = new ListNode(4);63 ListNode head3 = new ListNode(8);64 head1.next =head2;65 head2.next =head3;66 head3.next = null;67 ListNode sec1 = new ListNode(1);68 ListNode sec2 = new ListNode(3);69 ListNode sec3 = new ListNode(9);70 sec1.next =sec2;71 sec2.next =sec3;72 sec3.next = null;73 ListNode merge = newListNode();74 merge =test.Merge(head1, sec1);75 test.printList(merge);76 }77
78 }
Problem18:树的子结构
题目描述:输入两棵二叉树A和B,判断B是不是A的子结构;
1 /**
2 public class TreeNode {3 int val = 0;4 TreeNode left = null;5 TreeNode right = null;6
7 public TreeNode(int val) {8 this.val = val;9
10 }11
12 }13 */
14 public classSolution {15 //空树不是任何一个树的子结构
16 public booleanHasSubtree(TreeNode root1,TreeNode root2) {17 if(root1==null||root2==null){18 return false;19 }20 boolean result=false;21
22 //第一步;在树A中找到和树B根结点值相同的节点,因此需要对二叉树进行遍历
23 if(root1!=null&&root2!=null){24 if(root1.val==root2.val){25 result=DoTheJudge(root1,root2);26 }27 if(!result){28 result=HasSubtree(root1.left,root2);29 }30 if(!result){31 result=HasSubtree(root1.right,root2);32 }33 }34 returnresult;35 }36 private booleanDoTheJudge(TreeNode root1,TreeNode root2){37 //遍历完树A都没有,其中都没有完全匹配树B的子结构
38 if(root1==null&&root2!=null){39 return false;40 }41 //root2的所有节点与root1中进行了匹配
42 if(root2==null){43 return true;44 }45 if(root1.val!=root2.val){46 return false;47 }else{48 return DoTheJudge(root1.left,root2.left)&&DoTheJudge(root1.right,root2.right);49 }50 }51 }52
Problem19:二叉树的镜像
题目描述:请完成一个函数,输入一个二叉树,该函数输出它的镜像;
1 packageProblem19;2
3 /*
4 * 问题描述:5 * 请完成一个函数,输入一个二叉树,该函数输出它的镜像;6 */
7
8 //定义二叉树的结构
9 classBinaryTreeNode {10 BinaryTreeNode leftNode;11 BinaryTreeNode rightNode;12 intvalue;13 }14
15 public classMirrorOfBinaryTree {16
17 public static voidmirroOfBinTree(BinaryTreeNode root) {18 if (root == null) {19 return;20 }21 if (root.leftNode == null || root.rightNode == null) {22 return;23 }24 //交换一个结点的左右子节点
25 inttempValue;26 tempValue =root.leftNode.value;27 root.leftNode.value =root.rightNode.value;28 root.rightNode.value =tempValue;29 //递归操作左右子节点
30 if (root.leftNode != null) {31 mirroOfBinTree(root.leftNode);32 }33 if (root.rightNode != null) {34 mirroOfBinTree(root.rightNode);35 }36 }37
38 /**
39 *@paramargs40 */
41 //功能测试:普通的二叉树,二叉树的所有结点都没有左子树或者右子树,只有一个结点的二叉树42 //特殊输入测试:二叉树的根节点为null指针
43 public static voidmain(String[] args) {44 BinaryTreeNode root1 = newBinaryTreeNode();45 BinaryTreeNode node1 = newBinaryTreeNode();46 BinaryTreeNode node2 = newBinaryTreeNode();47 BinaryTreeNode node3 = newBinaryTreeNode();48 BinaryTreeNode node4 = newBinaryTreeNode();49 BinaryTreeNode node5 = newBinaryTreeNode();50 BinaryTreeNode node6 = newBinaryTreeNode();51 root1.leftNode =node1;52 root1.rightNode =node2;53 node1.leftNode =node3;54 node1.rightNode =node4;55 node4.leftNode =node5;56 node4.rightNode =node6;57 root1.value = 8;58 node1.value = 8;59 node2.value = 7;60 node3.value = 9;61 node4.value = 2;62 node5.value = 4;63 node6.value = 7;64
65 MirrorOfBinaryTree.mirroOfBinTree(root1);66 System.out.println(root1.rightNode.value);67 }68
69 }
Problem20:顺时针打印矩阵
题目描述:输入一个矩阵,按照从外向里以顺时针的顺组依次打印出每一个数字。
解法一:
1 importjava.util.ArrayList;2 public classSolution {3 public ArrayList printMatrix(int[][] matrix) {4
5 ArrayList result=new ArrayList<>();6 if(matrix==null||matrix.length<0|matrix[0].length<0){7 returnresult;8 }9 int rows=matrix.length;10 int columns=matrix[0].length;11 int start=0;12 //打印的起始位置13 //循环中打印每一圈
14 while(rows>2*start&&columns>2*start){15 result=printMatrixCicle(matrix,rows,columns,start,result);16 start++;17 }18 returnresult;19
20 }21 //22 private ArrayList printMatrixCicle(int matrix[][],int rows,int columns,int start,ArrayListresult){23 int endX=rows-1-start;24 int endY=columns-1-start;25 //从左到右打印一行
26 for(int i=start;i<=endY;i++){27 result.add(matrix[start][i]);28 }29 //从上到下打印一列:至少需要两行,即终止行号需要大于起始行号
30 if(start
36 if(start=start;i--){38 result.add(matrix[endX][i]);39 }40 }41 //从下到上打印一列,至少需要三行两列
42 if(endX>start+1&&endY>start){43 for(int i=endX-1;i>=start+1;i--){44 result.add(matrix[i][start]);45 }46 }47 returnresult;48 }49 }
解法二:
1 importjava.util.ArrayList;2 public classSolution {3 public ArrayList printMatrix(int[][] matrix) {4 ArrayList result=new ArrayList();5 if(matrix==null||matrix.length<=0||matrix[0].length<=0){6 returnresult;7 }8 int up=0;9 int down=matrix.length-1;10 int left=0;11 int right=matrix[0].length-1;12 while(left<=right&&up<=down){13 //从左到右打印一行
14 for(int i=left;i<=right;i++){15 result.add(matrix[up][i]);16 }17 up++;18 //从上到下打印一列
19 for(int i=up;i<=down;i++){20 result.add(matrix[i][right]);21 }22 right--;23 //从右到左打印一行,if判断是否有下一行需要打印
24 if(up-1!=down){25 for(int i=right;i>=left;i--){26 result.add(matrix[down][i]);27 }28 }29 down--;30 //从下到上打印一列 ,if判断是否还有下一列需要打印
31 if(left!=right+1){32 for(int i=down;i>=up;i--){33 result.add(matrix[i][left]);34 }35 }36 left++;37
38 }39 returnresult;40
41 }42 }
Problem21:包含min函数的栈
题目描述:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min、push以及pop的时间复杂度为O(1)
1 importjava.util.Stack;2
3
4 public classSolution {5
6 //数据栈
7 private StackstackData;8 //辅助栈
9 private StackstackMin;10
11 publicSolution(){12 stackData=new Stack();13 stackMin=new Stack();14 }15
16 //入栈操作
17 public void push(intnode) {18 stackData.push(node);19 if(stackMin.empty()){20 stackMin.push(node);21 }else{22 if(node<=stackMin.peek()){23 stackMin.push(node);24 }25 }26 }27 //出栈操作
28 public voidpop() {29 int data=stackData.pop();30 if(data==stackMin.peek()){31 stackMin.pop();32 }33
34 }35 //返回栈顶的元素
36 public inttop() {37 returnstackData.peek();38 }39 //得到栈的最小元素
40 public intmin() {41 returnstackMin.peek();42 }43 }
Problem22:栈的压入、弹出序列
题目描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出序列。假设压入栈的所有数字均不相等。例如序列1/2/3/4/5是某栈的压栈序列,序列4/5/3/2/1是该压栈序列对应的一个弹出序列,但4/3/5/1/2就不可能是该压栈序列的弹出序列;
1 packageProblem22;2
3 importjava.util.Stack;4
5 /*
6 * 问题描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出序列。假设压入栈的所有数字均不相等。7 * 例如序列1/2/3/4/5是某栈的压栈序列,序列4/5/3/2/1是该压栈序列对应的一个弹出序列,但4/3/5/1/2就不可能是该压栈序列的弹出序列8 */
9
10 public classIsPopOrder {11 /*
12 * 输入两个整数序列,第一个序列表示压入顺序,判断第二个序列是否为弹出顺序.假设入栈所有数字均不相等13 */
14 public boolean isPopOrder(int[] line1, int[] line2) {15 if (line1 == null || line2 == null)16 return false;17 int point1 = 0;18 Stack stack = new Stack();19 for (int i = 0; i < line2.length; i++) {20 if (!stack.isEmpty() && stack.peek() ==line2[i]) {21 stack.pop();22 } else{23 if (point1 ==line1.length)24 return false;25 else{26 do
27 stack.push(line1[point1++]);28 while (stack.peek() != line2[i] && point1 !=line1.length);29 if (stack.peek() ==line2[i])30 stack.pop();31 else
32 return false;33 }34 }35 }36 return true;37 }38
39 public static voidmain(String args[]) {40 int[] array1 = { 1, 2, 3, 4, 5};41 int[] array2 = { 4, 3, 5, 1, 2};42 IsPopOrder test = newIsPopOrder();43 System.out.println(test.isPopOrder(array1, array2));44 }45 }
Problem23:从上往下打印二叉树
题目描述:
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
1 importjava.util.ArrayList;2 importjava.util.LinkedList;3 /**
4 public class TreeNode {5 int val = 0;6 TreeNode left = null;7 TreeNode right = null;8
9 public TreeNode(int val) {10 this.val = val;11
12 }13
14 }15 */
16 public classSolution {17 public ArrayListPrintFromTopToBottom(TreeNode root) {18 //定义一个辅助队列
19 LinkedList queue=new LinkedList<>();20 //存储一层的打印结果
21 ArrayList resultCur=new ArrayList();22 //存储所有的打印结果23 //ArrayList> result=new ArrayList<>();
24 if(root==null){25 returnresultCur;26 }27 //定义两个变量last和nlast,分别记录当前行的最右节点和下一行的最右节点
28 TreeNode last=root;29 TreeNode nlast=root;30 TreeNode cur=root;31 queue.add(root);32 while(queue.size()!=0){33 cur=queue.poll();34 resultCur.add(cur.val);35 if(cur.left!=null){36 queue.add(cur.left);37 nlast=cur.left;38 }39 if(cur.right!=null){40 queue.add(cur.right);41 nlast=cur.right;42 }43 if(cur==last){44 //result.add(resultCur);45 //resultCur=new ArrayList<>();
46 last=nlast;47 }48 }49 returnresultCur;50 }51 }
Problem24 二叉搜索树的后序遍历序列
题目描述:
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
Problem29 数组中出现次数超过一半的数字
1 public classSolution {2 public boolean VerifySquenceOfBST(int[] sequence) {3 if(sequence.length == 0) return false;4 return IsTreeBST(sequence, 0, sequence.length-1);5 }6 public boolean IsTreeBST(int [] sequence,int start,intend ){7 //if(end <= start) return true;
8 int i =start;9 for (; i < end; i++) {10 if(sequence[i] > sequence[end]) break;11 }12 intj;13 for (j = i; j < end; j++) {14 if(sequence[j] < sequence[end]) return false;15 }16 boolean left=true;17 //根结点左子树不为空
18 if(i>0){19 left=IsTreeBST(sequence, start, i-1);20 }21 boolean right=true;22 //根结点右子树不为空
23 if(j
Problem24 二叉树中和为某一值的路径
题目描述:
输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
1 importjava.util.ArrayList;2 //import java.util.Stack;
3 /**
4 public class TreeNode {5 int val = 0;6 TreeNode left = null;7 TreeNode right = null;8
9 public TreeNode(int val) {10 this.val = val;11
12 }13
14 }15 */
16 //需要注意的是递归函数的参数传递,如果是在FindPathCore函数中定义curResult和curSum时,不传入该函数的话,它的下一级递归函数是无法看到这两个值的
17 public classSolution {18 public ArrayList> FindPath(TreeNode root,inttarget) {19 //定义result用于存储找到的所有符合条件的路径
20 ArrayList> result=new ArrayList<>();21 ArrayList curResult=new ArrayList<>();22 if(root==null){23 returnresult;24 }25 int curSum=0;26 FindPathCore(root,target,curResult,result,curSum);27 returnresult;28 }29
30 private void FindPathCore(TreeNode root,int target,ArrayList curResult,ArrayList> result,intcurSum){31 if(root==null){32 return;33 }34 boolean isLeaf=(root.left==null&&root.right==null);35
36 curSum+=root.val;37 //如果让前节点是叶子节点
38 if(isLeaf){39 if(curSum==target){40 curResult.add(root.val);41 result.add(new ArrayList(curResult));42 //路径中取出该叶子节点
43 curResult.remove(curResult.size()-1);44 }45 //返回上层节点,并从当前路径和中减去该叶子节点
46 curSum-=root.val;47 return;48 }49 curResult.add(root.val);50 FindPathCore(root.left,target,curResult,result,curSum);51 FindPathCore(root.right,target,curResult,result,curSum);52 curResult.remove(curResult.size()-1);53
54 }55 }
Problem28 字符串的排列
题目描述:
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
1 import java.util.*;2 public classSolution {3 public ArrayListPermutation(String str) {4 ArrayList re = new ArrayList();5 if (str == null || str.length() == 0) {6 returnre;7 }8 HashSet set = new HashSet();9 fun(set, str.toCharArray(), 0);10 re.addAll(set);11 Collections.sort(re);12 returnre;13 }14 void fun(HashSet re, char[] str, intbeginIndex) {15 if (beginIndex ==str.length) {16 //找到了一个字符串
17 re.add(newString(str));18 return;19 }20 for (int i = beginIndex; i < str.length; i++) {21 swap(str, i, beginIndex);22 fun(re, str, beginIndex + 1);23 swap(str, i, beginIndex);24 }25 }26 void swap(char[] str, int i, intj) {27 if (i !=j) {28 char t =str[i];29 str[i] =str[j];30 str[j] =t;31 }32 }33 }
Problem29 数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
解法一:其中对于错误输入的判断值得借鉴
1 public classSolution {2 boolean isInvalid=false;3
4 public int MoreThanHalfNum_Solution(int[] array) {5
6 if(CheckInvalidArray(array,array.length)){7 return -1;8 }9 int result=array[0];10 int count=1;11 for(int i=1;i
27 private boolean CheckInvalidArray(int[] arr,intlength){28
29 isInvalid=false;30 //输入无效的情况
31 if(arr==null||length==0){32 isInvalid=true;33 }34 returnisInvalid;35 }36 //判断一个数字的出现次数是否超过数组元素的一半
37 private boolean CheckMoreThanHalf(int[] arr,int length,intnumber){38 int count=0;39 for(int i=0;i
解法二:使用哈希表,时间复杂度和空间复杂度都为O(n)
1 public classSolution {2
3 public int MoreThanHalfNum_Solution(int[] array) {4 if(array==null||array.length==0){5 return -1;6 }7 //使用哈希表
8 int mapArr[]=new int[256];9 for(int i=0;i(array.length)/2){17 returni;18 }19 }20 //没有找到这样的数字
21 return 0;22 }23 }
Problem31连续子数组的最大和
题目描述:
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?(子向量的长度至少是1)
1 public classSolution {2 public int FindGreatestSumOfSubArray(int[] array)throwsException{3 if(array==null||array.length==0){4 throw new Exception("重新考虑输入");5 }6 //用于保存已经找到的连续子数组的最大和
7 int maxSum=array[0];8 //当前最大和
9 int curSum=array[0];10 for(int i=1;i
13 if(curSum<=0){14 curSum=array[i];15 }else{16 curSum+=array[i];17 }18 //判断此时经过一次循环我们找到的最大值与之前已经有的最大值的大小
19 if(curSum>maxSum){20 maxSum=curSum;21 }22 }23 returnmaxSum;24 }25 }
Problem32 整数中1出现的次数
题目描述:
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
解法一:时间复杂度N*(logN)
1 public classSolution {2 public int NumberOf1Between1AndN_Solution(intn) {3 int count=0;4 for(int i=1;i<=n;i++){5
6 count+=core(i);7 }8
9 returncount;10 }11 private int core(intn){12 int num=0;13 while(n!=0){14 if(n%10==1){15 num++;16 }17 n/=10;18 }19 returnnum;20 }21 }
Problem33 把数组排成最小的数
题目描述:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
1 import java.util.*;2
3 /*
4 * 解题思路:5 * 先将整型数组转换成String数组,然后将String数组排序,最后将排好序的字符串数组拼接出来。关键就是制定排序规则。6 * 排序规则如下:7 * 若ab > ba 则 a > b,8 * 若ab < ba 则 a < b,9 * 若ab = ba 则 a = b;10 * 解释说明:11 * 比如 "3" < "31"但是 "331" > "313",所以要将二者拼接起来进行比较12 */
13 public classSolution {14 public String PrintMinNumber(int[] numbers) {15 if(numbers==null||numbers.length<1){16 return "";17 }18 int len=numbers.length;19 //将数组元素转换为字符串数组中的元素,即用字符串表示数字,应对大数溢出问题
20 String[] str=newString[len];21 for(int i=0;i(){25 @Override26 public intcompare(String c1,String c2){27 return (c1+c2).compareTo(c2+c1);28 }29 });30 StringBuilder builder=newStringBuilder();31 for(int i=0;i
Problem34 丑数
题目描述:
把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
解法1:
1 public classSolution {2 public int GetUglyNumber_Solution(intindex) {3
4 if(index<=0){5 return 0;6 }7 int uglyCount=0;8 int num=0;9 while(uglyCount
19 while(num%2==0){20 num=num/2;21 }22 while(num%3==0){23 num/=3;24 }25 while(num%5==0){26 num/=5;27 }28 return (num==1)?true:false;29 }30 }
解法二:
1 public classSolution {2 //用空间换时间的方法
3 public int GetUglyNumber_Solution(intindex) {4 if(index<=0){5 return 0;6 }7 //辅助数组,大小为index
8 int uglyArr[]=new int[index];9 //题目中描述的第一个丑数为1
10 uglyArr[0]=1;11 //下一个丑数的位置
12 int nextUgly=1;13
14 int index2=0;15 int index3=0;16 int index5=0;17
18 int ugly2=uglyArr[index2];19 int ugly3=uglyArr[index3];20 int ugly5=uglyArr[index5];21
22 //找到的丑数的数目还不满足要求
23 while(nextUgly
27
28 while(uglyArr[index2]*2<=uglyArr[nextUgly]){29
30 ugly2=uglyArr[++index2];31 }32
33 while(uglyArr[index3]*3<=uglyArr[nextUgly]){34
35 ugly3=uglyArr[++index3];36 }37
38 while(uglyArr[index5]*5<=uglyArr[nextUgly]){39
40 ugly5=uglyArr[++index5];41 }42 ++nextUgly;43 }44 return uglyArr[nextUgly-1];45 }46 //求三个数的最小值的Min函数
47 private int Min(int num1,int num2,intnum3){48 int min=num1
Problem35 第一个只出现一次的字符
题目描述:
在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置
1 public classSolution {2 public intFirstNotRepeatingChar(String str) {3 //哈希表的使用
4 int mapArr[]=new int[256];5 for(int i=0;i
14 for(int i=0;i
Problem36数组中的逆序对
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1
输入
1,2,3,4,5,6,7,0
输出
7
1 /*
2 *归并排序的思想,最后求得的逆序数进行取摸 % 10000000073 */
4 public classSolution {5 public int InversePairs(int[] array) {6 if(array==null || array.length<=0){7 return 0;8 }9 int pairsNum=mergeSort(array,0,array.length-1);10 returnpairsNum;11 }12 13 public int mergeSort(int[] array,int left,intright){14 if(left==right){15 return 0;16 }17 int mid=(left+right)/2;18 int leftNum=mergeSort(array,left,mid);19 int rightNum=mergeSort(array,mid+1,right);20 return (Sort(array,left,mid,right)+leftNum+rightNum)%1000000007;21 }22 23 public int Sort(int[] array,int left,int middle,intright){24 int current1=middle;25 int current2=right;26 int current3=right-left;27 int temp[]=new int[right-left+1];28 int pairsnum=0;29 while(current1>=left && current2>=middle+1){30 if(array[current1]>array[current2]){31 temp[current3--]=array[current1--];32 pairsnum+=(current2-middle); //这个地方是current2-middle!!!!
33 if(pairsnum>1000000007)//数值过大求余
34 {35 pairsnum%=1000000007;36 }37 }else{38 temp[current3--]=array[current2--];39 }40 }41 while(current1>=left){42 temp[current3--]=array[current1--];43 }44 while(current2>=middle+1){45 temp[current3--]=array[current2--];46 }47 //将临时数组赋值给原数组
48 int i=0;49 while(left<=right){50 array[left++]=temp[i++];51 }52 returnpairsnum;53 }54 }
Problem37 两个链表的第一个公共节点
题目描述:输入两个链表,找出它们的第一个公共结点。
解法一:蛮力法
碰到这道题,很多人的第一反应就是蛮力法:在第一链表上顺序遍历每个结点,每遍历到一个结点的时候,在第二个链表上顺序遍历每个结点。如果在第二个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合,于是就找到了它们的公共结点。如果第一个链表的长度为m,第二个链表的长度为n,显然该方法的时间复杂度是O(mn)。
解法二:借助外部空间法
首先,经过分析我们发现两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可能像X,如下图所示,两个链表在值为6的结点处交汇:
如果两个链表有公共结点,那么公共结点出现在两个链表的尾部。如果我们从两个链表的尾部开始往前比较,最后一个相同的结点就是我们要找的结点。But,在单链表中只能从头结点开始按顺序遍历,最后才能到达尾结点。最后到达的尾结点却要最先被比较,这是“后进先出”的特性。于是,我们可以使用栈的特点来解决这个问题:分别把两个链表的结点放入两个栈里,这样两个链表的尾结点就位于两个栈的栈顶,接下来比较两个栈顶的结点是否相同。如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的结点。
1 import java.util.*;2 /*
3 public class ListNode {4 int val;5 ListNode next = null;6
7 ListNode(int val) {8 this.val = val;9 }10 }*/
11 public classSolution {12 //时间复杂度为O(mn),空间复杂度为O(m+n)的方法
13 publicListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {14 if(pHead1==null||pHead2==null){15 return null;16 }17
18 Stack stack1=new Stack<>();19 Stack stack2=new Stack<>();20 while(pHead1!=null){21 stack1.push(pHead1);22 pHead1=pHead1.next;23 }24 while(pHead2!=null){25 stack2.push(pHead2);26 pHead2=pHead2.next;27 }28 if(stack1.peek().val!=stack2.peek().val){29 return null;30 }31 ListNode node1=null;32 ListNode node2=null;33 ListNode common=null;34 while(!stack1.empty()&&!stack2.empty()){35 node1=stack1.peek();36 node2=stack2.peek();37 if(node1.val==node2.val){38 stack1.pop();39 stack2.pop();40 common=node1;41 }else{42 break;43 }44 }45
46 returncommon;47 }48 }
解法三:不借助外部空间法
那么,可不可以不借助栈来实现了呢?答案是可以的,我们可以首先遍历两个链表得到它们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个结点。在第二次遍历的时候,在较长的链表上先走若干步,接着再同时在两个链表上遍历,找到的第一个相同的结点就是它们的第一个公共结点。
比如在上图的两个链表中,我们可以先遍历一次得到它们的长度分别为5和4,也就是较长的链表与较短的链表相比多一个结点。第二次先在长的链表上走1步,到达结点2。接下来分别从结点2和结点4出发同时遍历两个结点,直到找到它们第一个相同的结点6,这就是我们想要的结果。
1 /*
2 public class ListNode {3 int val;4 ListNode next = null;5
6 ListNode(int val) {7 this.val = val;8 }9 }*/
10 public classSolution {11 //时间复杂度为O(mn),空间复杂度为O(1)的方法
12 publicListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {13 int len1=getLengthOfList(pHead1);14 int len2=getLengthOfList(pHead2);15 ListNode longList=null;16 ListNode shortList=null;17 //两个链表的长度差
18 int diff=0;19 if(len1
29 while(diff>0){30 longList=longList.next;31 diff--;32 }33 while(longList!=null&&shortList!=null&&longList!=shortList){34
35 longList=longList.next;36 shortList=shortList.next;37 }38 returnlongList;39 }40 private intgetLengthOfList(ListNode head){41 int len=0;42 while(head!=null){43 len++;44 head=head.next;45 }46 returnlen;47 }48 }
\Problem39 二叉树的深度&&平衡二叉树判断
题目一:
二叉树的深度:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
1 /**
2 public class TreeNode {3 int val = 0;4 TreeNode left = null;5 TreeNode right = null;6
7 public TreeNode(int val) {8 this.val = val;9
10 }11
12 }13 */
14 public classSolution {15 public intTreeDepth(TreeNode root) {16 if(root==null){17 return 0;18 }19 int lh=TreeDepth(root.left);20 int rh=TreeDepth(root.right);21 return lh>rh?(lh+1):(rh+1);22 }23 }
题目二:
平衡二叉树判断:输入一棵二叉树,判断该二叉树是否是平衡二叉树。
解法一:递归实现(需要重复遍历节点多次)
1 import java.util.*;2
3 /*
4 public class TreeNode {5 int val = 0;6 TreeNode left = null;7 TreeNode right = null;8 public TreeNode(int val) {9 this.val = val;10 }11 }*/
12 public classCheckBalance {13 public booleancheck(TreeNode root) {14 //write code here
15 if(root==null){16 return true;17 }18 int lh=getDepth(root.left);19 int rh=getDepth(root.right);20 int diff=lh-rh;21 if(diff>1||diff
27 private intgetDepth(TreeNode root){28 if(root==null){29 return 0;30 }31 int lh=getDepth(root.left);32 int rh=getDepth(root.right);33
34 return lh>rh?(lh+1):rh+1;35 }36 }
解法二:
1 import java.util.*;2
3 /*
4 public class TreeNode {5 int val = 0;6 TreeNode left = null;7 TreeNode right = null;8 public TreeNode(int val) {9 this.val = val;10 }11 }*/
12 public classCheckBalance {13 public booleancheck(TreeNode root) {14 //定义一个引用类型的数据作为平衡标记,通过传引用的方式在递归左右子树时修改平衡标记
15 boolean[] res=new boolean[1];16 //从根节点开始遍历树,遍历过程中修改平衡标记
17 res[0]=true;18 postCheck(root,1,res);19
20 return res[0];21 }22 public int postCheck(TreeNode root,int depth,boolean[] res){23 if(root==null){24 returndepth;25 }26 //遍历一次左子树,获取深度(深度已经在参数改变了,目的是为了检查左子树是否平衡)27 //若遍历左子树过程中修改了平衡标记为false,则子树非平衡,所以当前结点为根的子树非平衡,不再递归,直接返回
28
29 int left_depth=postCheck(root.left,depth+1,res);30 if(res[0]==false){31 returndepth;32 }33 //若左子树是平衡的,则遍历右子树并获取深度34 //若遍历右子树过程中修改了平衡标记为false,则子树非平衡,所以当前结点为根的子树非平衡,不再递归,直接返回
35 int right_depth=postCheck(root.right,depth+1,res);36 if(res[0]==false){37 returndepth;38 }39
40 //若左右子树都是平衡的,则对左右子树深度进行比较,判断当前结点为根的子树是否平衡
41 if(Math.abs(left_depth-right_depth)>1){//高度差大于1,当前子树不平衡,修改平衡标记
42 res[0]=false;43 }44 //用左右子树深度最大者作为自己的高度
45 returnMath.max(left_depth,right_depth);46 }47 }
Problem38 数字在排序数组中出现的次数
题目描述
统计一个数字在排序数组中出现的次数。
1 public classSolution {2 //需要充分利用排序数组这个特点
3 public int GetNumberOfK(int [] array , intk) {4
5 if(array==null||array.length==0){6 return 0;7 }8 int firstIndexK=getTheIndexOfFirst(array,array.length,k,0,array.length-1);9 int lastIndexK=getTheIndexOfLast(array,array.length,k,0,array.length-1);10 if(firstIndexK>-1||lastIndexK>-1){11 return(lastIndexK-firstIndexK+1);12 }13 //数组中不存在数字k
14 return 0;15 }16 //找到第一次出现k的位置
17 private int getTheIndexOfFirst(int[] arr,int len,int k,int start,intend){18 if(start>end){19 return -1;20 }21 int mid=(start+end)/2;22 int dataMid=arr[mid];23 if(dataMid>k){24 end=mid-1;25 }else if(dataMid
41 private int getTheIndexOfLast(int[] arr,int len,int k,int start,intend){42 if(start>end){43 return -1;44 }45 int mid=(start+end)/2;46 int dataMid=arr[mid];47 if(arr[mid]k){50 end=mid-1;51 }else{52 if(mid!=len-1){53 if(arr[mid+1]!=k){54 returnmid;55 }else{56 start=mid+1;57 }58 }else{59 returnmid;60 }61 }62 returngetTheIndexOfLast(arr,len,k,start,end);63 }64
65 }
Problem40数组中只出现一次的数字
题目描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
1 //num1,num2分别为长度为1的数组。传出参数2 //将num1[0],num2[0]设置为返回结果
3 public classSolution {4 public void FindNumsAppearOnce(int [] array,int num1[] , intnum2[]) {5 //输入不符合要求
6 if(array==null||array.length==0){7 return;8 }9 //int xor存放异或结果
10 int xor=0;11 //flag用于寻找和标记第N位为1的位置
12 int flag=1;13 //先对整个数组的元素进行异或运算
14 for(int i=0;i
Problem41 和为S的两个数字VS和为S的连续正数序列
题目一描述:
输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
1 import java.util.ArrayList;2 public classSolution {3 public ArrayList FindNumbersWithSum(int [] array,intsum) {4 ArrayList list=new ArrayList();5 if(array==null||array.length<1){6 returnlist;7 }8 int small=0;9 int big=array.length-1;10 while(small
12 if(array[small]+array[big]>sum)13 big--;14 else if(array[small]+array[big]
17 {18 list.add(array[small]);19 list.add(array[big]);20 returnlist;21 }22 }23 returnlist;24 }25 }
题目二描述:和为S的连续正数序列
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
1 importjava.util.ArrayList;2 public classSolution {3 public ArrayList > FindContinuousSequence(intsum) {4
5 ArrayList> result = new ArrayList>();6
7 int small = 1;8 int big = 2;9 int curSum = small+big;10 while(small < big && small < (sum+1)/2){11 if(curSum ==sum){12 ArrayList list = new ArrayList();13
14 for(int i=small;i<=big;i++){15 list.add(i);16 }17 result.add(list);18
19 //更新
20 curSum -=small;21 //区间右移
22 small ++;23 big ++;24 curSum +=big;25 }else if(curSum < sum){ //tmp_sum小,右侧扩展26 //区间右侧 右移,包括更大的数字
27 big ++;28 curSum += big; //更新
29 }else{ //tmp_sum大,左侧紧缩
30 curSum -=small;31 small ++; //左侧紧缩
32 }33 }34 returnresult;35 }36 }
Problem42 翻转单词的顺序
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?
1 import java.util.*;2 public classSolution {3 publicString ReverseSentence(String str) {4 if(str==null||str.length()==0){5 //反复错在这个位置,之前返回的是null值
6 returnstr;7 }8 char chas[]=str.toCharArray();9 rolateWord(chas);10 returnString.valueOf(chas);11 }12 private void rolateWord(charchas[]){13 if(chas==null||chas.length==0){14 return;15 }16 reverse(chas,0,chas.length-1);17 //下面对每一个局部的单词进行逆序18 //标记一个单词的开始
19 int start=0;20 //标记一个单词的结束
21 int end=0;22 //遍历字符数组
23 int i=0;24 while(i
36
37 }38 private void reverse(char chas[],int left,intright){39 while(left
Problem44 扑克牌的顺子
题目描述:
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何。为了方便起见,你可以认为大小王是0。
1 import java.util.*;2
3 public classSolution {4
5 public boolean isContinuous(int[] numbers) {6 if(numbers==null||numbers.length<1){7 return false;8 }9 int numberOfZero=0;10 int gapsOfNum=0;11 for(int i=0;i
21 if(numbers[small]==numbers[big]){22 return false;23 }24 gapsOfNum+=numbers[big]-numbers[small]-1;;25 small=big;26 big++;27 }28 return (gapsOfNum>numberOfZero)?false:true;29 }30 }
Problem45 y圆圈中最后剩下的数字(约瑟夫环问题)
题目描述:
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)
1 import java.util.*;2
3 public classSolution {4
5 public int LastRemaining_Solution(int n, intm) {6 //输入不合法
7 if(n<1||m<1){8 return -1;9 }10 ArrayList list=new ArrayList();11 for(int i=0;i it=list.iterator();16 while(list.size()>1){17 for(int i=1;i<=m;i++){18 if(it.hasNext()){19 it.next();20 }else{21 //当迭代器扫描到链表尾部时,需要把迭代器移动到链表的头部
22 it=list.iterator();23 it.next();24 }25 }26 it.remove();27 listSize--;28 }29 it=list.iterator();30 returnit.next();31 }32 }
Problem46 计算1+2+3+。。。n
题目描述:
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
1 public classSolution {2 //常用方法是使用循环或者递归实现3 //循环只是让相同代码重复执行遍而已
4 public int Sum_Solution(intn) {5 int sum=n;6 boolean flag=(n>0)&&((sum+=Sum_Solution(n-1))>0);7 returnsum;8 }9 }
Problem47 不用加减乘除做加法
题目描述:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
1 public classSolution {2 //使用位运算3 //1.不考虑进位各位相加 2.考虑进位3.两步结果相加
4 public int Add(int num1,intnum2) {5 intsum,carry;6 if(num1==0){7 returnnum2;8 }9 if(num2==0){10 returnnum1;11 }12 while(num2!=0){13 sum=num1^num2;14 carry=(num1&num2)<<1;15 num1=sum;16 num2=carry;17 }18
19 returnnum1;20 }21 }
Problem49 把字符串转换为整数
题目描述:
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0
示例1
输入
+2147483647
1a33
输出
2147483647
0
1 public classSolution {2 public intStrToInt(String str) {3 int sum =0;4 //判断非法输入
5 if(str == "0" || str == "" ||str.length() == 0){6
7 return 0;8 }9 //将字符串转换为对应的字符数组
10 char chs[]=str.toCharArray();11 for(int i = 0; i < chs.length;i++){12 //是正负号的话,跳出当前if循环,开始下一趟for循环
13 if(chs[i]== '+' || chs[i] == '-'){14 continue;15 }16 if(chs[i] >'9' || chs[i]
Problem51 数组中重复的数字
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
1 public classSolution {2 //Parameters:3 //numbers: an array of integers4 //length: the length of array numbers5 //duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;6 //Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++7 //这里要特别注意~返回任意重复的一个,赋值duplication[0]8 //Return value: true if the input is valid, and there are some duplications in the array number9 //otherwise false
10 public boolean duplicate(int numbers[],int length,int[] duplication) {11
12 if(numbers==null||length==0){13 return false;14 }15 //条件判断,保证数组中的元素值在0-n-1的范围内
16 for(int i=0;ilength-1){18 return false;19 }20 }21 for(int i=0;i
Proble52 构建乘积数组
题目描述:给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
1 importjava.util.ArrayList;
2 public classSolution {
3 public int[] multiply(int[] A) {
4 //将B[i]的计算拆分成A[0]*A[1]...A[i-1]和A[i+1]*...A[n-1]两部分,用一个矩阵来创建数组B
5 int len=A.length;
6 int B[]=new int[len];
7 B[0]=1;
8 //先求矩阵上三角部分
9 for(int i=1;i
10 B[i]=B[i-1]*A[i-1];
11 }
12 //再求下三角部分
13 int temp=1;
14 for(int i=len-2;i>=0;i--){
15 //temp随着i的减小不断变化
16 temp*=A[i+1];
17 B[i]*=temp;
18 }
19 returnB;
20 }
21 }
Problem53 正则表达式匹配
题目描述:
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
1 public classSolution {2 public boolean match(char[] str, char[] pattern)3 {4 //条件判断
5 if(str==null||pattern==null){6 return false;7 }8 return matchCore(str,0,pattern,0);9 }10 private boolean matchCore(char[] str,int strIndex,char[] pattern,intpIndex){11 //有效性检验12 //str和pattern同时到达尾部,完成匹配,返回true
13 if(strIndex==str.length&&pIndex==pattern.length){14 return true;15 }16 //str不到尾,pattern到尾部,返回false
17 if(strIndex!=str.length&&pIndex==pattern.length){18 return false;19 }20
21 //模式第2个是*,且字符串第1个跟模式第1个匹配,分3种匹配模式;如不匹配,模式后移2位
22 if (pIndex + 1 < pattern.length && pattern[pIndex + 1] == '*') {23 if(strIndex!=str.length&&str[strIndex]==pattern[pIndex]||strIndex!=str.length&&pattern[pIndex]=='.'){24 //1.模式串后后移两位,相当于第一个匹配的字符被忽略掉,从字符串的下一个字符继续开始匹配25 //2.字符串后移一位,模式串后移两位,相当于模式匹配一个字符26 //3.字符串后移一位,模式串不动,因为模式串的第二个字符'*‘,可以匹配前面出现的多个字符
27 return matchCore(str,strIndex,pattern,pIndex+2)||matchCore(str,strIndex+1,pattern,pIndex+2)||
28 matchCore(str,strIndex+1,pattern,pIndex);29 }else{30 return matchCore(str,strIndex,pattern,pIndex+2);31 }32 }33 //模式串第二个字符不是'*',并且两个串的第一个字符是匹配的
34 if(strIndex!=str.length&&str[strIndex]==pattern[pIndex]||strIndex!=str.length&&pattern[pIndex]=='.'){35 return matchCore(str,strIndex+1,pattern,pIndex+1);36
37 //否则,直接返回false
38 }else{39 return false;40 }41 }42 }
Problem54 表示数值的字符串
题目描述:
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
思路:使用正则表达式来解决
1 public classSolution {2 public boolean isNumeric(char[] str) {3 String string =String.valueOf(str);4 return string.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?");5 }6 }
Problem55 字符流中第一个不重复的字符
题目描述:
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。
思路:定义一个数据容器来保存字符在字符流中的位置,当一个字符第一次从字符流中读出来时,把它在字符流中的位置保存在数据容器中,当这个字符再次出现时,那么就吧它在数据容器中保存的值更新为一个特殊的值(比如负数值)
1 public classSolution {2 //Insert one char from stringstream3 //定义一个数组模拟哈希表
4
5 int mapArr[]=new int[256];6 int index=0;7
8 publicSolution(){9 //最开始,哈希表中所有元素都初始化为-1
10 for(int i=0;i<256;i++){11 mapArr[i]=-1;12 }13 }14 public void Insert(charch)15 {16 if(mapArr[ch]==-1){17 mapArr[ch]=index++;18 }else{19 mapArr[ch]=-2;20 }21 }22 //return the first appearence once char in current stringstream
23 public charFirstAppearingOnce()24 {25 int minIndex=256;26 char ch='#';27 for(int i=0;i<256;i++){28 if(mapArr[i]>=0&&mapArr[i]
Problem56 链表中环的入口结点
题目描述:
一个链表中包含环,请找出该链表的环的入口结点。
1 /*
2 public class ListNode {3 int val;4 ListNode next = null;5
6 ListNode(int val) {7 this.val = val;8 }9 }10 */
11 public classSolution {12
13 //分成两步:1.判断是否存在环,并找到快慢两个指针相遇的位置14 //2.根据找到的这个相遇位置,统计环中节点的数目n,先让快指针走n步,然后15 //快慢两个指针一起运动,快慢指针相遇时的节点就是环的入口节点
16 publicListNode EntryNodeOfLoop(ListNode pHead)17 {18 //getMeetingNode函数返回null或者环中的一个节点(快慢指针相遇的节点)
19 ListNode meetNode=getMeetingNode(pHead);20 if(meetNode==null){21 return null;22 }23 //根据找到的这个节点统计环中节点的数目
24 int loopNodes=1;25 ListNode cur=meetNode.next;26 while(cur!=meetNode){27 loopNodes++;28 cur=cur.next;29 }30 //快指针先走loopNodes步
31 ListNode fast=pHead;32 for(int i=1;i<=loopNodes;i++){33 fast=fast.next;34 }35 //慢指针开始跟快指针一起移动
36 ListNode slow=pHead;37 while(slow!=fast){38 slow=slow.next;39 fast=fast.next;40 }41 returnfast;42 }43 //先找两个指针相遇的位置
44 privateListNode getMeetingNode(ListNode pHead){45 if(pHead==null){46 return null;47 }48 ListNode slow=pHead.next;49 //只有一个结点 ,直接返回null
50 if(slow==null){51 return null;52 }53 ListNode fast=slow.next;54 while(slow!=null&&fast!=null){55 if(slow==fast){56 returnfast;57 }58 //slow指针在链表上一次移动一步
59 slow=slow.next;60 //fast指针一次在链表上移动两步
61 fast=fast.next;62 if(fast!=null){63 fast=fast.next;64 }65 }66 //链表中不存在环,则直接返回null;
67 return null;68 }69
70 }
Problem57删除链表中重复的节点
题目描述:
在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
1 /*
2 public class ListNode {3 int val;4 ListNode next = null;5
6 ListNode(int val) {7 this.val = val;8 }9 }10 */
11 public classSolution {12 publicListNode deleteDuplication(ListNode pHead)13 {14 //使用虚拟头结点,方便在链表头部进行的一些操作
15 ListNode visualHead = new ListNode(-1);16 visualHead.next =pHead;17 //当前节点的前一个节点
18 ListNode pre =visualHead;19 while(pHead != null && pHead.next != null){20 if(pHead.val ==pHead.next.val){21 int value =pHead.val;22 while(pHead != null && pHead.val ==value)23 pHead =pHead.next;24 pre.next =pHead;25 }else{26 pre =pHead;27 pHead =pHead.next;28 }29 }30 returnvisualHead.next;31 }32 }
Problem58二叉树的下一个节点
题目描述:
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
1 /*
2 public class TreeLinkNode {3 int val;4 TreeLinkNode left = null;5 TreeLinkNode right = null;6 TreeLinkNode next = null;7
8 TreeLinkNode(int val) {9 this.val = val;10 }11 }12 */
13 public classSolution {14 publicTreeLinkNode GetNext(TreeLinkNode pNode)15 {16 if(pNode==null){17 return null;18 }19 TreeLinkNode pNext=null;20 if(pNode.right!=null){21 TreeLinkNode pRight=pNode.right;22 while(pRight.left!=null){23 pRight=pRight.left;24 }25 pNext=pRight;26 }else if(pNode.next!=null){27 TreeLinkNode pCur=pNode;28 TreeLinkNode parent=pNode.next;29 while(parent!=null&&pCur!=parent.left){30 pCur=parent;31 parent=pCur.next;32 }33 pNext=parent;34 }35 returnpNext;36 }37 }
Problem59二叉树的镜像(对称的二叉树)
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:源二叉树
8
/ \
6 10
/ \ / \
5 7 9 11
镜像二叉树
8
/ \
10 6
/ \ / \
11 9 7 5
1 /**
2 public class TreeNode {3 int val = 0;4 TreeNode left = null;5 TreeNode right = null;6
7 public TreeNode(int val) {8 this.val = val;9
10 }11
12 }13 */
14 public classSolution {15 public voidMirror(TreeNode root) {16 if(root==null){17 return;18 }19 TreeNode tempNode;20 tempNode=root.left;21
22 root.left=root.right;23 root.right=tempNode;24
25 Mirror(root.left);26 Mirror(root.right);27 }28 }
剑指offer书上面对应的题目是判断两个二叉树是否为彼此的镜像二叉树,可以通过二叉树的前序遍历和对称前序遍历来验证;(根->左->右和根->右->左);两个遍历序列相同则说明是对称二叉树,反之则不是;
OJ在线:
题目描述
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
1 /*
2 public class TreeNode {3 int val = 0;4 TreeNode left = null;5 TreeNode right = null;6
7 public TreeNode(int val) {8 this.val = val;9
10 }11
12 }13 */
14 public classSolution {15 booleanisSymmetrical(TreeNode pRoot)16 {17 returnisSymmetricalCore(pRoot,pRoot);18 }19 private booleanisSymmetricalCore(TreeNode pRoot1,TreeNode pRoot2){20 if(pRoot1==null&&pRoot2==null){21 return true;22 }23 if(pRoot1==null||pRoot2==null){24 return false;25 }26 if(pRoot1.val!=pRoot2.val){27 return false;28 }29 return isSymmetricalCore(pRoot1.left,pRoot2.right)&&isSymmetricalCore(pRoot1.right,pRoot2.left);30 }31 }
Problem60 把二叉树打印成多行
题目描述:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
1 importjava.util.ArrayList;2 importjava.util.LinkedList;3
4 classTreeNode {5 int val = 0;6 TreeNode left = null;7 TreeNode right = null;8
9 public TreeNode(intval) {10 this.val =val;11
12 }13
14 }15
16 public classSolution {17 //层次遍历二叉树
18 ArrayList >Print(TreeNode pRoot) {19 //定义一个辅助队列
20 LinkedList queue=new LinkedList();21 //last表示打印当前行时的最右节点
22 TreeNode last=pRoot;23 //nlast表示要打印的下一行的最右节点
24 TreeNode nlast=pRoot;25 //当前正在打印的节点
26 TreeNode cur=pRoot;27
28 queue.add(cur);29 //result存放一层的打印结果
30 ArrayList result=new ArrayList();31
32 //存储所有的打印结果
33 ArrayList> resultAll=new ArrayList<>();34 if(cur==null){35 returnresultAll;36 }37 while(queue.size()!=0){38 //弹出队列中的一个节点
39 cur=queue.poll();40 result.add(cur.val);41 if(cur.left!=null){42 queue.add(cur.left);43 nlast=cur.left;44 }45 if(cur.right!=null){46 queue.add(cur.right);47 nlast=cur.right;48 }49 //一层打印结束
50 if(cur==last){51 resultAll.add(result);52 last=nlast;53 result=new ArrayList();54 }55 }56 returnresultAll;57 }58
59 }
Problem61 按之字形顺序打印二叉树
题目描述:
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
Problem62 序列化二叉树
1 import java.util.*;2
3 /*
4 public class TreeNode {5 int val = 0;6 TreeNode left = null;7 TreeNode right = null;8
9 public TreeNode(int val) {10 this.val = val;11
12 }13
14 }15 */
16 public classSolution {17 public ArrayList >Print(TreeNode pRoot) {18
19 ArrayList> result=new ArrayList<>();20 if(pRoot==null){21 returnresult;22 }23
24 //需要使用两个辅助栈
25 Stack stack1=new Stack<>();26 Stack stack2=new Stack<>();27 //先使用辅助栈1
28 stack1.push(pRoot);29 while(!stack1.empty()||!stack2.empty()){30 if(!stack1.empty()){31 ArrayList curResult=new ArrayList<>();32 while(!stack1.empty()){33 TreeNode dataPop=stack1.pop();34 curResult.add(dataPop.val);35 if(dataPop.left!=null){36 stack2.push(dataPop.left);37 }38 if(dataPop.right!=null){39 stack2.push(dataPop.right);40 }41 }42 result.add(curResult);43 }else{44 ArrayList curResult=new ArrayList<>();45
46 while(!stack2.empty()){47 TreeNode dataPop=stack2.pop();48 curResult.add(dataPop.val);49 if(dataPop.right!=null){50 stack1.push(dataPop.right);51 }52 if(dataPop.left!=null){53 stack1.push(dataPop.left);54 }55 }56 result.add(curResult);57 }58 }59 returnresult;60
61 }62
63 }
Problem62 序列化二叉树
题目描述:
请实现两个函数,分别用来序列化和反序列化二叉树
1 /*
2 public class TreeNode {3 int val = 0;4 TreeNode left = null;5 TreeNode right = null;6
7 public TreeNode(int val) {8 this.val = val;9
10 }11
12 }13 */
14 public classSolution {15
16 String Serialize(TreeNode root) {17 if(root == null)18 return "";19 StringBuilder builder = newStringBuilder();20 serializeCore(root, builder);21 returnbuilder.toString();22 }23
24 voidserializeCore(TreeNode root, StringBuilder builder) {25 if(root == null) {26 builder.append("#,");27 return;28 }29 builder.append(root.val).append(",");30 serializeCore(root.left, builder);31 serializeCore(root.right, builder);32 }33
34
35 TreeNode Deserialize(String str) {36 if(str.length() == 0)37 return null;38 String[] strs = str.split(",");39 returnDeserialize2(strs);40 }41 int index = 0;42
43 TreeNode Deserialize2(String[] strs) {44 if(!strs[index].equals("#")) {45 TreeNode root = new TreeNode(0);46 root.val = Integer.parseInt(strs[index++]);47 root.left =Deserialize2(strs);48 root.right =Deserialize2(strs);49 returnroot;50 }else{51 index++;52 return null;53 }54 }55 }
Problem63 二叉搜索树的第k个结点
题目描述:给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
1 /*
2 public class TreeNode {3 int val = 0;4 TreeNode left = null;5 TreeNode right = null;6
7 public TreeNode(int val) {8 this.val = val;9
10 }11
12 }13 */
14 public classSolution {15 //对二叉搜索树进行一次中序遍历就可以找到第K大的数
16 TreeNode KthNode(TreeNode pRoot, intk)17 {18 if(pRoot==null||k==0){19 return null;20 }21 int result[]=new int[1];22 result[0]=k;23 returnKthNodeCore(pRoot,result);24 }25 private TreeNode KthNodeCore(TreeNode pRoot,int[] result){26 TreeNode target=null;27 if(target==null&&pRoot.left!=null){28 target=KthNodeCore(pRoot.left,result);29 }30 if(target==null&&result[0]==1){31 target=pRoot;32 }else{33 result[0]--;34 }35 if(target==null&&pRoot.right!=null){36 target=KthNodeCore(pRoot.right,result);37 }38 returntarget;39 }40 }
Problem65滑动窗口的最大值
题目描述:
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
1 import java.util.*;2 public classSolution {3 public ArrayList maxInWindows(int [] num, intsize)4 {5 ArrayList result=new ArrayList<>(0);6 if(num==null||num.length<1||num.length
10 ArrayDeque queue=new ArrayDeque<>();11 for(int i=0;i
13 while(!queue.isEmpty()&&num[queue.peekLast()]<=num[i]){14 queue.pollLast();15 }16 queue.addLast(i);17 //删除队头失效的最大值
18 if(i-size>=queue.peekFirst()){19 queue.pollFirst();20 }21 if(i>=size-1){22 result.add(num[queue.peekFirst()]);23 }24 }25 returnresult;26
27 }28 }