├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── so │ ├── Add47.java │ ├── BinaryToLinked27.java │ ├── BinaryTreeSearch6.java │ ├── Calculate46.java │ ├── CloneCLinkedList26.java │ ├── Common.java │ ├── DeleteDuplication57.java │ ├── DeleteNode13.java │ ├── DicesProbability43.java │ ├── DoesTreeHave18.java │ ├── DoubleSQueue7.java │ ├── Duplicate51.java │ ├── EnterLoop56.java │ ├── Fibonacci9.java │ ├── FinalClass48.java │ ├── FindFirstCommonNode37.java │ ├── FindGreatestSum31.java │ ├── FindKthToTail15.java │ ├── FindNumAppearOnce40.java │ ├── FindNumber3.java │ ├── FindNumbersWithSum41.java │ ├── FindPath25.java │ ├── FirstAppearingOnce55.java │ ├── FirstNotRepeating35.java │ ├── GetLeastNumbers30.java │ ├── GetMedian64.java │ ├── GetNumberOfK38.java │ ├── HasPath66.java │ ├── InversePairs36.java │ ├── IsContinuous44.java │ ├── IsNumber54.java │ ├── IsPopOrder22.java │ ├── IsSymmetrical59.java │ ├── KthNode63.java │ ├── LastRemaining45.java │ ├── LevelPrintTree61.java │ ├── MaxInWindows65.java │ ├── MergeLinked17.java │ ├── MinCParent50.java │ ├── MinNumber8.java │ ├── MirrorRecursively19.java │ ├── MoreThanHalfNum29.java │ ├── MovingCount67.java │ ├── MultiplyArray52.java │ ├── NextTreeNode58.java │ ├── NumberOf1Bw32.java │ ├── NumberOfBin10.java │ ├── OddEvenNumber14.java │ ├── Permutation28.java │ ├── Power11.java │ ├── PrintFromTopToBottom23.java │ ├── PrintListReversing5.java │ ├── PrintMatrixInCircle20.java │ ├── PrintMinNumber33.java │ ├── PrintToMaxOfNDigits12.java │ ├── RegularMatch53.java │ ├── ReplaceBlank4.java │ ├── ReverseList16.java │ ├── ReverseSentence42.java │ ├── Serializer62.java │ ├── SingletonPattern2.java │ ├── StackWithMin21.java │ ├── StrToInt49.java │ ├── TreePath39.java │ ├── UglyNumber34.java │ ├── VerifySequenceOfBST24.java │ └── ZTreePrint60.java └── test └── java └── com └── so ├── Test10.java ├── Test11.java ├── Test12.java ├── Test13.java ├── Test14.java ├── Test15.java ├── Test16.java ├── Test17.java ├── Test18.java ├── Test19.java ├── Test2.java ├── Test20.java ├── Test21.java ├── Test22.java ├── Test23.java ├── Test24.java ├── Test25.java ├── Test26.java ├── Test27.java ├── Test28.java ├── Test29.java ├── Test3.java ├── Test30.java ├── Test31.java ├── Test32.java ├── Test33.java ├── Test34.java ├── Test35.java ├── Test36.java ├── Test37.java ├── Test38.java ├── Test39.java ├── Test4.java ├── Test40.java ├── Test41.java ├── Test42.java ├── Test43.java ├── Test44.java ├── Test45.java ├── Test46.java ├── Test47.java ├── Test48.java ├── Test49.java ├── Test5.java ├── Test50.java ├── Test51.java ├── Test52.java ├── Test53.java ├── Test54.java ├── Test55.java ├── Test56.java ├── Test57.java ├── Test58.java ├── Test59.java ├── Test6.java ├── Test60.java ├── Test61.java ├── Test62.java ├── Test63.java ├── Test64.java ├── Test65.java ├── Test66.java ├── Test67.java ├── Test7.java ├── Test8.java └── Test9.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore files 2 | .idea/* 3 | target/* 4 | SwordOffer.iml 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 GaoLeiQin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 《剑指offer》Java版代码 2 | ![封面图片](https://img-blog.csdnimg.cn/201906290844352.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JhaXllX3hpbmc=,size_16,color_FFFFFF,t_70) 3 | 4 | ##### 提供多种解法以及思路,并在OJ上全都通过 5 | 6 | 7 | ### 目录 8 | 9 | |题号|题目及题解|测试用例| 10 | |:-----|:----|:----| 11 | |第二题|[单例设计模式](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/SingletonPattern2.java)|[测试2](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test2.java)| 12 | |第三题|[二维数组中查找目标值](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FindNumber3.java)|[测试3](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test3.java)| 13 | |第四题|[替换字符串中的空格](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/ReplaceBlank4.java)|[测试4](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test4.java)| 14 | |第五题|[从尾到头打印链表](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/PrintListReversing5.java)|[测试5](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test5.java)| 15 | |第六题|[由前序和中序遍历重建二叉树](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/BinaryTreeSearch6.java)|[测试6](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test6.java)| 16 | |第七题|[用两个栈实现队列](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/DoubleSQueue7.java)|[测试7](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test7.java)| 17 | |第八题|[求旋转数组的最小数字](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/MinNumber8.java)|[测试8](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test8.java)| 18 | |第九题|[斐波那契数列的第n项(青蛙跳台阶)](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/Fibonacci9.java)|[测试9](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test9.java)| 19 | |第十题|[二进制中1的个数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/NumberOfBin10.java)|[测试10](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test10.java)| 20 | |第十一题|[数值的整数次方](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/Power11.java)|[测试11](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test11.java)| 21 | |第十二题|[打印1到最大的n位数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/PrintToMaxOfNDigits12.java)|[测试12](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test12.java)| 22 | |第十三题|[O(1)时间删除链表节点](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/DeleteNode13.java)|[测试13](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test13.java)| 23 | |第十四题|[使数组中的奇数位于偶数前面](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/OddEvenNumber14.java)|[测试14](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test14.java)| 24 | |第十五题|[找链表中倒数第K个节点](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FindKthToTail15.java)|[测试15](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test15.java)| 25 | |第十六题|[反转链表](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/ReverseList16.java)|[测试16](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test16.java)| 26 | |第十七题|[合并两个有序链表](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/MergeLinked17.java)|[测试17](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test17.java)| 27 | |第十八题|[判断二叉树A中是否包含子树B](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/DoesTreeHave18.java)|[测试18](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test18.java)| 28 | |第十九题|[二叉树的镜像](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/MirrorRecursively19.java)|[测试19](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test19.java)| 29 | |第二十题|[顺时针打印矩阵](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/PrintMatrixInCircle20.java)|[测试20](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test20.java)| 30 | |第二十一题|[包含min函数的栈](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/StackWithMin21.java)|[测试21](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test21.java)| 31 | |第二十二题|[判断一个栈是否是另一个栈的弹出序列](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/IsPopOrder22.java)|[测试22](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test22.java)| 32 | |第二十三题|[层序遍历二叉树](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/PrintFromTopToBottom23.java)|[测试23](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test23.java)| 33 | |第二十四题|[后序遍历二叉搜索树](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/VerifySequerceOfBST24.java)|[测试24](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test24.java)| 34 | |第二十五题|[二叉树中和为某值的路径](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FindPath25.java)|[测试25](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test25.java)| 35 | |第二十六题|[复杂链表的复制](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/CloneCLinkedList26.java)|[测试26](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test26.java)| 36 | |第二十七题|[二叉搜索树转换为双向链表](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/BinaryToLinked27.java)|[测试27](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test27.java)| 37 | |第二十八题|[打印字符串中所有字符的排列](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/Permutation28.java)|[测试28](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test28.java)| 38 | |第二十九题|[数组中出现次数超过一半的数字](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/MoreThanHalfNum29.java)|[测试29](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test29.java)| 39 | |第三十题|[找出最小的K个数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/GetLeastNumbers30.java)|[测试30](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test30.java)| 40 | |第三十一题|[连续子数组的最大和](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FindGreatestSum31.java)|[测试31](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test31.java)| 41 | |第三十二题|[从1到整数n中1出现的次数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/NumberOf1Bw32.java)|[测试32](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test32.java)| 42 | |第三十三题|[把数组中的数排成一个最小的数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/PrintMinNumber33.java)|[测试33](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test33.java)| 43 | |第三十四题|[求第N个丑数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/UglyNumber34.java)|[测试34](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test34.java)| 44 | |第三十五题|[第一个出现一次的字符](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FirstNotRepeating35.java)|[测试35](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test35.java)| 45 | |第三十六题|[数组中逆序对的个数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/InversePairs36.java)|[测试36](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test36.java)| 46 | |第三十七题|[两个链表的第一个公共节点](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FindFirstCommonNode37.java)|[测试37](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test37.java)| 47 | |第三十八题|[数字在排序数组中出现的次数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/GetNumberOfK38.java)|[测试38](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test38.java)| 48 | |第三十九题|[二叉树的深度](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/TreePath39.java)|[测试39](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test39.java)| 49 | |第四十题|[数组中只出现一次的两个数,而其他数都出现两次](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FindNumAppearOnce40.java)|[测试40](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test40.java)| 50 | |第四十一题|[和为s的连续整数序列](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FindNumbersWithSum41.java)|[测试41](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test41.java)| 51 | |第四十二题|[翻转字符串](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/ReverseSentence42.java)|[测试42](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test42.java)| 52 | |第四十三题|[n个骰子的点数及出现的概率](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/DicesProbability43.java)|[测试43](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test43.java)| 53 | |第四十四题|[扑克牌的顺子](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/IsContinuous44.java)|[测试44](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test44.java)| 54 | |第四十五题|[圆圈中最后剩下的数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/LastRemaining45.java)|[测试45](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test45.java)| 55 | |第四十六题|[1+2+3+...+n的和](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/Calculate46.java)|[测试46](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test46.java)| 56 | |第四十七题|[不用加减乘除做加法](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/Add47.java)|[测试47](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test47.java)| 57 | |第四十八题|[不能被继承的类](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FinalClass48.java)|[测试48](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test48.java)| 58 | |第四十九题|[字符串转换为整数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/StrToInt49.java)|[测试49](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test49.java)| 59 | |第五十题|[树中两个节点的最低公共祖先](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/MinCParent50.java)|[测试50](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test50.java)| 60 | |第五十一题|[找出重复的数](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/Duplicate51.java)|[测试51](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test51.java)| 61 | |第五十二题|[构建乘积数组](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/MultiplyArray52.java)|[测试52](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test52.java)| 62 | |第五十三题|[正则表达式匹配](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/RegularMatch53.java)|[测试53](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test53.java)| 63 | |第五十四题|[表示数值的字符串](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/IsNumber54.java)|[测试54](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test54.java)| 64 | |第五十五题|[字符流中第一个不重复的字符](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/FirstAppearingOnce55.java)|[测试55](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test55.java)| 65 | |第五十六题|[链表中环的入口节点](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/EnterLoop56.java)|[测试56](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test56.java)| 66 | |第五十七题|[删除链表中重复的节点](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/DeleteDuplication57.java)|[测试57](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test57.java)| 67 | |第五十八题|[二叉树的下一个节点](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/NextTreeNode58.java)|[测试58](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test58.java)| 68 | |第五十九题|[对称的二叉树](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/IsSymmetrical59.java)|[测试59](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test59.java)| 69 | |第六十题|[按之字形顺序打印二叉树](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/ZTreePrint60.java)|[测试60](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test60.java)| 70 | |第六十一题|[把二叉树打印成多行](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/LevelPrintTree61.java)|[测试61](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test61.java)| 71 | |第六十二题|[序列化二叉树](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/Serializer62.java)|[测试62](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test62.java)| 72 | |第六十三题|[二叉搜索树的第K个节点](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/main/java/com/so/KthNode63.java)|[测试63](https://github.com/GaoLeiQin/SwordOffer/blob/master/src/test/java/com/so/Test63.java)| 73 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | com.so 8 | sword-offer 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | junit 14 | junit 15 | 4.13.1 16 | test 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | maven-clean-plugin 25 | 3.1.0 26 | 27 | 28 | maven-resources-plugin 29 | 3.0.2 30 | 31 | 32 | maven-compiler-plugin 33 | 34 | 8 35 | 8 36 | 37 | 3.8.0 38 | 39 | 40 | maven-surefire-plugin 41 | 2.22.1 42 | 43 | 44 | maven-jar-plugin 45 | 3.0.2 46 | 47 | 48 | maven-install-plugin 49 | 2.5.2 50 | 51 | 52 | maven-deploy-plugin 53 | 2.8.2 54 | 55 | 56 | maven-site-plugin 57 | 3.7.1 58 | 59 | 60 | maven-project-info-reports-plugin 61 | 3.0.0 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/main/java/com/so/Add47.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第47题 5 | * 不用加减乘除做加法 6 | * 7 | * @author qgl 8 | * @date 2017/08/16 9 | */ 10 | public class Add47 { 11 | /** 12 | * 求和 13 | * @param num1 14 | * @param num2 15 | * @return 16 | */ 17 | public static int add(int num1,int num2) { 18 | while (num2 != 0) { 19 | int temp = num1 ^ num2; 20 | num2 = (num1 & num2) << 1; 21 | num1 = temp; 22 | } 23 | return num1; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/so/BinaryToLinked27.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第27题 5 | * 将二叉搜索树转换成一个排序的双向链表 6 | * 7 | * @author qgl 8 | * @date 2017/08/14 9 | */ 10 | public class BinaryToLinked27 { 11 | /** 12 | * 二叉树 13 | */ 14 | static class BinaryTreeNode { 15 | int data; 16 | BinaryTreeNode leftNode; 17 | BinaryTreeNode rightNode; 18 | } 19 | 20 | /** 21 | * 二叉树的转换 22 | * @param root 23 | * @return 24 | */ 25 | public static BinaryTreeNode convert(BinaryTreeNode root) { 26 | //指向双向链表的尾节点 27 | BinaryTreeNode lastNode = convertNode(root, null); 28 | //找到转换后的链表的头节点 29 | BinaryTreeNode pHead = lastNode; 30 | while (pHead != null && pHead.leftNode != null) { 31 | pHead = pHead.leftNode; 32 | } 33 | //返回链表头节点 34 | return pHead; 35 | } 36 | 37 | public static BinaryTreeNode convertNode(BinaryTreeNode root, BinaryTreeNode lastNode) { 38 | if (root == null) { 39 | return null; 40 | } 41 | BinaryTreeNode current = root; 42 | //递归处理左子树 43 | if (current.leftNode != null) { 44 | lastNode = convertNode(current.leftNode, lastNode); 45 | } 46 | //将当前节点的左指针指向已经转换好的链表的最后一个位置 47 | current.leftNode = lastNode; 48 | //将已经转换好的链表的最后一个节点的右指针指向当前节点 49 | if (lastNode != null) { 50 | lastNode.rightNode = current; 51 | } 52 | //更新已经转换好的链表的最后一个节点 53 | lastNode = current; 54 | //递归处理右子树 55 | if (current.rightNode != null) { 56 | lastNode = convertNode(current.rightNode, lastNode); 57 | } 58 | 59 | return lastNode; 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/main/java/com/so/BinaryTreeSearch6.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Arrays; 4 | 5 | import com.so.Common.TreeNode; 6 | 7 | /** 8 | * 第6题 9 | * 输入二叉树的前序遍历和中序遍历结果,重建该二叉树。 10 | * 11 | * @author qgl 12 | * @date 2017/08/09 13 | */ 14 | public class BinaryTreeSearch6 { 15 | 16 | /** 17 | * 解法一:递归(传入数组的拷贝) 18 | * 时间复杂度:O(n),空间复杂度:O(n) 19 | * 20 | * @param pre 21 | * @param in 22 | * @return 23 | */ 24 | public static TreeNode reConstructBinaryTree(int[] pre, int[] in) { 25 | if (pre == null || in == null || pre.length == 0 || in.length == 0) { 26 | return null; 27 | } 28 | if (pre.length != in.length) { 29 | return null; 30 | } 31 | 32 | TreeNode root = new TreeNode(pre[0]); 33 | for (int i = 0; i < pre.length; i++) { 34 | if (pre[0] == in[i]) { 35 | root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i)); 36 | root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length), Arrays.copyOfRange(in, i + 1, in.length)); 37 | } 38 | } 39 | return root; 40 | } 41 | 42 | /** 43 | * 解法二:递归:传入子数组的边界索引 44 | * 时间复杂度:O(n),空间复杂度:O(n) 45 | * 46 | * @param preorder 47 | * @param inorder 48 | * @return 49 | */ 50 | public TreeNode reConstructBinaryTree2(int[] preorder, int[] inorder) { 51 | if (preorder == null || preorder.length == 0 || 52 | inorder == null || inorder.length == 0) return null; 53 | return helper(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); 54 | } 55 | 56 | 57 | private TreeNode helper(int[] preorder, int preL, int preR, int[] inorder, int inL, int inR) { 58 | if (preL > preR || inL > inR) { 59 | return null; 60 | } 61 | int rootVal = preorder[preL]; 62 | int index = 0; 63 | while (index <= inR && inorder[index] != rootVal) { 64 | index++; 65 | } 66 | TreeNode root = new TreeNode(rootVal); 67 | root.left = helper(preorder, preL + 1, preL - inL + index, inorder, inL, index); 68 | root.right = helper(preorder, preL - inL + index + 1, preR, inorder, index + 1, inR); 69 | return root; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/so/Calculate46.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第46题 5 | * 求1+2+...+n,不能使用乘除法,循环等 6 | * 7 | * @author qgl 8 | * @date 2017/08/16 9 | */ 10 | public class Calculate46 { 11 | 12 | /** 13 | * 解法一,利用递归求和 14 | * @param n 15 | * @return 16 | */ 17 | public static int sum(int n) { 18 | int sum = n; 19 | boolean result = (n > 0) && ((sum += sum(n-1)) > 0); 20 | return sum; 21 | } 22 | 23 | /** 24 | * 解法二:利用递归和全局变量求和 25 | */ 26 | private static int sum2 = 0; 27 | public static int sum2(int n) { 28 | sum3(n); 29 | return sum2; 30 | } 31 | 32 | private static boolean sum3(int n) { 33 | sum2 += n; 34 | return (n > 0) && sum3(n - 1); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/so/CloneCLinkedList26.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第26题 5 | * 复制一个复杂链表 6 | * 7 | * @author qgl 8 | * @date 2017/08/13 9 | */ 10 | public class CloneCLinkedList26 { 11 | /** 12 | * 复杂链表 13 | */ 14 | public static class RandomListNode { 15 | int label; 16 | RandomListNode next = null; 17 | RandomListNode random = null; 18 | 19 | RandomListNode(int label) { 20 | this.label = label; 21 | } 22 | } 23 | 24 | /** 25 | * 解法一 26 | * @param pHead 27 | * @return 28 | */ 29 | public static RandomListNode Clone1(RandomListNode pHead) { 30 | if (pHead == null) { 31 | return null; 32 | } 33 | RandomListNode pCur = pHead; 34 | //复制next 如原来是A->B->C 变成A->A'->B->B'->C->C' 35 | while (pCur != null) { 36 | RandomListNode node = new RandomListNode(pCur.label); 37 | node.next = pCur.next; 38 | pCur.next = node; 39 | pCur = node.next; 40 | } 41 | pCur = pHead; 42 | //复制random pCur是原来链表的结点 pCur.next是复制pCur的结点 43 | while (pCur != null) { 44 | if (pCur.random != null) { 45 | pCur.next.random = pCur.random.next; 46 | } 47 | pCur = pCur.next.next; 48 | } 49 | RandomListNode head = pHead.next; 50 | RandomListNode cur = head; 51 | pCur = pHead; 52 | //拆分链表 53 | while (pCur != null) { 54 | pCur.next = pCur.next.next; 55 | if (cur.next != null) { 56 | cur.next = cur.next.next; 57 | } 58 | cur = cur.next; 59 | pCur = pCur.next; 60 | } 61 | return head; 62 | } 63 | 64 | /** 65 | * 解法二 66 | * @param pHead 67 | * @return 68 | */ 69 | public static RandomListNode Clone2(RandomListNode pHead) { 70 | if (pHead == null) { 71 | return null; 72 | } 73 | RandomListNode head = new RandomListNode(pHead.label); 74 | RandomListNode temp = head; 75 | 76 | while (pHead.next != null) { 77 | temp.next = new RandomListNode(pHead.next.label); 78 | if (pHead.random != null) { 79 | temp.random = new RandomListNode(pHead.random.label); 80 | } 81 | pHead = pHead.next; 82 | temp = temp.next; 83 | } 84 | return head; 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /src/main/java/com/so/Common.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 公共类 5 | * 6 | * @author qgl 7 | * @date 2019/07/01 8 | */ 9 | public class Common { 10 | /** 11 | * 二叉树 12 | */ 13 | public static class TreeNode { 14 | int val; 15 | TreeNode left; 16 | TreeNode right; 17 | 18 | TreeNode(int x) { 19 | val = x; 20 | } 21 | } 22 | 23 | /** 24 | * 链表 25 | */ 26 | public static class ListNode { 27 | int val; 28 | ListNode next; 29 | 30 | ListNode(int val) { 31 | this.val = val; 32 | } 33 | } 34 | 35 | /** 36 | * 获取链表的所有节点 37 | * 38 | * @param head 39 | * @return 40 | */ 41 | public static String getAllListNode(ListNode head) { 42 | StringBuilder sb = new StringBuilder(); 43 | while (head != null) { 44 | sb.append(head.val).append(" → "); 45 | head = head.next; 46 | } 47 | return sb.length() < 1 ? null : sb.substring(0, sb.length() - 2); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/so/DeleteDuplication57.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第57题 5 | * 删除链表的重复节点 6 | * 7 | * @author qgl 8 | * @date 2017/08/30 9 | */ 10 | public class DeleteDuplication57 { 11 | static class ListNode { 12 | int val; 13 | ListNode next = null; 14 | 15 | ListNode(int val) { 16 | this.val = val; 17 | } 18 | } 19 | 20 | public static ListNode deleteDuplication(ListNode pHead) { 21 | if (pHead == null) { 22 | return null; 23 | } 24 | // 新建一个节点,防止头结点被删除 25 | ListNode dummy = new ListNode(-1); 26 | dummy.next = pHead; 27 | ListNode p = pHead; 28 | // 指向前一个节点 29 | ListNode preNode = dummy; 30 | 31 | while (p != null && p.next != null) { 32 | if (p.val == p.next.val) { 33 | int val = p.val; 34 | // 向后重复查找 35 | while (p != null && p.val == val) { 36 | p = p.next; 37 | } 38 | // 赋值:相当于删除 39 | preNode.next = p; 40 | }else { 41 | // 如果当前节点和下一个节点值不等,则向后移动一位 42 | preNode = p; 43 | p = p.next; 44 | } 45 | } 46 | return dummy.next; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/so/DeleteNode13.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第13题 5 | * 给定单向链表的头指针和一个节点,在O(1)时间删除该节点。 6 | * 7 | * @author qgl 8 | * @date 2017/08/09 9 | */ 10 | public class DeleteNode13 { 11 | 12 | /** 13 | * 自定义链表 14 | */ 15 | static class ListNode { 16 | int data; 17 | ListNode nextNode; 18 | } 19 | 20 | /** 21 | * 删除链表的某个节点 22 | * @param head 头指针 23 | * @param deListNode 待删除的节点 24 | */ 25 | public static void deleteNode(ListNode head, ListNode deListNode) { 26 | if (deListNode == null || head == null) 27 | return; 28 | 29 | if (head == deListNode) { 30 | head = null; 31 | } else { 32 | // 若删除节点是末尾节点,往后移一个 33 | if (deListNode.nextNode == null) { 34 | ListNode pointListNode = head; 35 | while (pointListNode.nextNode.nextNode != null) { 36 | pointListNode = pointListNode.nextNode; 37 | } 38 | pointListNode.nextNode = null; 39 | } else { 40 | deListNode.data = deListNode.nextNode.data; 41 | deListNode.nextNode = deListNode.nextNode.nextNode; 42 | } 43 | } 44 | } 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/main/java/com/so/DicesProbability43.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 第43题 8 | * 把n个骰子扔在地上,所有骰子朝上一面的点数之和为s,输入n,打印出s的所有可能出现的概率 9 | * 10 | * @author qgl 11 | * @date 2017/08/16 12 | */ 13 | public class DicesProbability43 { 14 | 15 | /** 16 | * 获取所有可能出现的情况 17 | * @param number 骰子数量 18 | */ 19 | public static Map printProbability(int number) { 20 | Map probabilityMap = new HashMap<>(); 21 | if (number < 1) { 22 | return probabilityMap; 23 | } 24 | int g_maxValue = 6; 25 | int[][] probabilities = new int[2][]; 26 | probabilities[0] = new int[g_maxValue * number + 1]; 27 | probabilities[1] = new int[g_maxValue * number + 1]; 28 | int flag = 0; 29 | 30 | // 当第一次抛掷骰子时,有6种可能,每种可能出现一次 31 | // 第一个骰子投完的结果存到了probabilities[0] 32 | for (int i = 1; i <= g_maxValue; i++) { 33 | probabilities[0][i] = 1; 34 | } 35 | 36 | //从第二次开始掷骰子,假设第一个数组中的第n个数字表示骰子和为n出现的次数, 37 | for (int k = 2; k <= number; ++k) { 38 | 39 | // 第k次掷骰子,和最小为k,小于k的情况是不可能发生的,令不可能发生的次数设置为0! 40 | for (int i = 0; i < k; ++i) { 41 | probabilities[1 - flag][i] = 0; 42 | } 43 | 44 | // 第k次掷骰子,和最小为k,最大为g_maxValue*k 45 | for (int i = k; i <= g_maxValue * k; ++i) { 46 | // 初始化,因为这个数组要重复使用,上一次的值要清0 47 | probabilities[1 - flag][i] = 0; 48 | for (int j = 1; j <= i && j <= g_maxValue; ++j) 49 | probabilities[1 - flag][i] += probabilities[flag][i - j]; 50 | } 51 | 52 | // 若flag=0,1-flag用的就是数组1,而flag=1,1-flag用的就是数组0 53 | flag = 1 - flag; 54 | } 55 | 56 | double total = Math.pow(g_maxValue, number); 57 | for (int sum = number; sum <= g_maxValue * number; sum++) { 58 | double ratio = (double) probabilities[flag][sum] / total; 59 | probabilityMap.put(sum, ratio); 60 | } 61 | 62 | return probabilityMap; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/so/DoesTreeHave18.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.TreeNode; 4 | 5 | /** 6 | * 第18题 7 | * 判断二叉树A中是否包含子树B 8 | * 9 | * @author qgl 10 | * @date 2017/08/10 11 | */ 12 | public class DoesTreeHave18 { 13 | /** 14 | * 判断是否包含子树 15 | * 16 | * @param source 17 | * @param target 18 | * @return 19 | */ 20 | public static boolean hasSubTree(TreeNode source, TreeNode target) { 21 | if (target == null) { 22 | return true; 23 | } 24 | if (source == null) { 25 | return false; 26 | } 27 | 28 | if (doesTree1HaveTree2(source, target)) { 29 | return true; 30 | } 31 | return hasSubTree(source.left, target) || hasSubTree(source.right, target); 32 | } 33 | 34 | /** 35 | * 递归遍历两棵树 36 | * 37 | * @param source 38 | * @param target 39 | * @return 40 | */ 41 | public static boolean doesTree1HaveTree2(TreeNode source, TreeNode target) { 42 | if (source == null && target == null) { 43 | return true; 44 | } 45 | if (source == null || target == null) { 46 | return false; 47 | } 48 | if (source.val != target.val) { 49 | return false; 50 | } 51 | 52 | return doesTree1HaveTree2(source.left, target.left) && doesTree1HaveTree2(source.right, target.right); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/so/DoubleSQueue7.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 第7题 7 | * 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 8 | * 9 | * @author qgl 10 | * @date 2017/08/09 11 | */ 12 | public class DoubleSQueue7 { 13 | private Stack stack1 = new Stack<>(); 14 | private Stack stack2 = new Stack<>(); 15 | 16 | /** 17 | * 入栈 18 | * 时间复杂度:O(1),空间复杂度:O(n) 19 | * 20 | * @param node 21 | */ 22 | public void push(int node) { 23 | stack1.push(node); 24 | } 25 | 26 | /** 27 | * 出栈 28 | * 时间(摊还)复杂度:O(1),空间复杂度:O(1) 29 | * 30 | * @return 31 | * @throws Exception 32 | */ 33 | public int pop() throws Exception { 34 | if (stack1.isEmpty() && stack2.isEmpty()) { 35 | throw new Exception("栈为空!"); 36 | } 37 | 38 | if (stack2.isEmpty()) { 39 | while(!stack1.isEmpty()) { 40 | stack2.push(stack1.pop()); 41 | } 42 | } 43 | return stack2.pop(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/so/Duplicate51.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.HashSet; 4 | 5 | /** 6 | * 第51题 7 | * 在一个长度为n的数组里的所有数字都在0到n-1的范围内,找出数组中任意一个重复的数字 8 | * 9 | * @author qgl 10 | * @date 2017/08/29 11 | */ 12 | public class Duplicate51 { 13 | /** 14 | * 解法一:利用题中数组的特点(数组中的元素小于数组长度) 15 | * 时间复杂度是O(n),空间复杂度是O(1) 16 | * 17 | * @param numbers 18 | * @return 19 | */ 20 | public static Integer duplicate1(int numbers[]) { 21 | if (numbers == null || numbers.length == 0) { 22 | return null; 23 | } 24 | if (numbers.length == 1) { 25 | return numbers[0]; 26 | } 27 | 28 | int length = numbers.length; 29 | for (int i = 0; i < length; i++) { 30 | int index = numbers[i]; 31 | if (index >= length) { 32 | index -= length; 33 | } 34 | if (numbers[index] >= length) { 35 | return index; 36 | } 37 | numbers[index] += length; 38 | } 39 | return null; 40 | } 41 | 42 | /** 43 | * 解法二:利用辅助空间 HashSet 44 | * 时间复杂度是O(n),空间复杂度是O(n) 45 | * 46 | * @param numbers 47 | * @return 48 | */ 49 | public static Integer duplicate2(int numbers[]) { 50 | if (numbers == null || numbers.length == 0) { 51 | return null; 52 | } 53 | if (numbers.length == 1) { 54 | return numbers[0]; 55 | } 56 | 57 | int length = numbers.length; 58 | HashSet hashSet = new HashSet<>(); 59 | for (int i = 0; i < length; i++) { 60 | if (!hashSet.add(numbers[i])) { 61 | return numbers[i]; 62 | } 63 | } 64 | return null; 65 | } 66 | 67 | /** 68 | * 解法三:快慢指针 69 | * 70 | * @param numbers 71 | * @return 72 | */ 73 | public static int duplicate3(int[] numbers) { 74 | if (numbers == null || numbers.length == 0) { 75 | return -1; 76 | } 77 | int slow = 0; 78 | int fast = 0; 79 | for (int i = 0; i < numbers.length; i++) { 80 | slow = numbers[slow]; 81 | fast = numbers[numbers[fast]]; 82 | if (fast == slow) { 83 | fast = 0; 84 | while (fast != slow) { 85 | fast = numbers[fast]; 86 | slow = numbers[slow]; 87 | } 88 | return slow; 89 | } 90 | } 91 | return -1; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/so/EnterLoop56.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第56题 5 | * 找出环链表的入口结点 6 | * 7 | * @author qgl 8 | * @date 2017/08/30 9 | */ 10 | public class EnterLoop56 { 11 | /** 12 | * 链表 13 | */ 14 | static class ListNode { 15 | int val; 16 | ListNode next = null; 17 | 18 | ListNode(int val) { 19 | this.val = val; 20 | } 21 | } 22 | 23 | /** 24 | * 获取环形链表的入口节点 25 | * 26 | * @param pHead 27 | * @return 28 | */ 29 | public static ListNode enterNodeOfLoop(ListNode pHead) { 30 | if (pHead == null || pHead.next == null) { 31 | return null; 32 | } 33 | ListNode slow = pHead; 34 | ListNode fast = pHead; 35 | 36 | while (fast != null && fast.next != null) { 37 | slow = slow.next; 38 | fast = fast.next.next; 39 | if (slow == fast) { 40 | fast = pHead; 41 | while (fast != slow) { 42 | fast = fast.next; 43 | slow = slow.next; 44 | } 45 | return slow; 46 | } 47 | } 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/so/Fibonacci9.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第9题 5 | * 输入一个整数n,求斐波那契数列的第n项。 6 | * 7 | * @author qgl 8 | * @date 2017/08/09 9 | */ 10 | public class Fibonacci9 { 11 | 12 | /** 13 | * 解法一:定义三个局部变量,作为交换 14 | * 15 | * @param n 16 | * @return 17 | */ 18 | public static int getFibonacci1(int n) { 19 | int result = 0; 20 | int preOne = 1; 21 | int preTwo = 0; 22 | if (n == 0) { 23 | return preTwo; 24 | } 25 | if (n == 1) { 26 | return preOne; 27 | } 28 | for (int i = 2; i <= n; i++) { 29 | result = preOne + preTwo; 30 | preTwo = preOne; 31 | preOne = result; 32 | } 33 | return result; 34 | } 35 | 36 | /** 37 | * 解法二 :只需要两个局部变量 38 | * 39 | * @param n 40 | * @return 41 | */ 42 | public static long getFibonacci2(int n) { 43 | long number = 1; 44 | long sum = 1; 45 | if (n <= 0) 46 | return 0; 47 | if (n == 1 || n == 2) { 48 | return 1; 49 | } 50 | 51 | while (n-- > 2) { 52 | sum += number; 53 | number = sum - number; 54 | } 55 | return sum; 56 | } 57 | 58 | /** 59 | * 解法三:递归:效率低,有大量重复计算 60 | * 61 | * @param n 62 | * @return 63 | */ 64 | public static int getFibonacci3(int n) { 65 | if (n < 0) { 66 | return -1; 67 | } 68 | if (n == 0) { 69 | return 0; 70 | } 71 | if (n == 1) { 72 | return 1; 73 | } 74 | 75 | return getFibonacci3(n - 1) + getFibonacci3(n - 2); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/so/FinalClass48.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第48题 5 | * 不能被继承的类 6 | * 7 | * @author qgl 8 | * @date 2017/08/16 9 | */ 10 | public class FinalClass48 { 11 | 12 | /** 13 | * 解法一:被final修饰的类不能被继承 14 | */ 15 | // public final class FinalClass48 { 16 | 17 | /** 18 | * 解法二:私有构造器的类不能继承 19 | */ 20 | private FinalClass48(){} 21 | 22 | public static FinalClass48 getInstance() { 23 | return new FinalClass48(); 24 | } 25 | 26 | public static void deleteInstance(FinalClass48 instance) { 27 | instance=null; 28 | } 29 | 30 | 31 | } -------------------------------------------------------------------------------- /src/main/java/com/so/FindFirstCommonNode37.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第37题 5 | * 求两个单向链表的第一个公共节点 6 | * 7 | * @author qgl 8 | * @date 2017/08/15 9 | */ 10 | public class FindFirstCommonNode37 { 11 | 12 | /** 13 | * 链表 14 | */ 15 | static class ListNode { 16 | int val; 17 | ListNode next = null; 18 | 19 | ListNode(int val) { 20 | this.val = val; 21 | } 22 | } 23 | 24 | /** 25 | * 解法一:长链表先走,需要遍历链表 26 | * @param pHead1 27 | * @param pHead2 28 | * @return 29 | */ 30 | public static ListNode findFirstCommonNode1(ListNode pHead1, ListNode pHead2) { 31 | if (pHead1 == null || pHead2 == null) { 32 | return null; 33 | } 34 | ListNode p1 = pHead1; 35 | ListNode p2 = pHead2; 36 | int length1 = getListNodeLength(p1); 37 | int length2 = getListNodeLength(p2); 38 | int diff = 0; 39 | if (length1 - length2 > 0) { 40 | diff = length1 - length2; 41 | while (diff-- > 0) { 42 | pHead1 = pHead1.next; 43 | } 44 | } else { 45 | diff = length2 - length1; 46 | while (diff-- > 0) { 47 | pHead2 = pHead2.next; 48 | } 49 | } 50 | 51 | while (pHead1 != null && pHead2 != null) { 52 | if (pHead1 == pHead2) { 53 | return pHead1; 54 | } 55 | pHead1 = pHead1.next; 56 | pHead2 = pHead2.next; 57 | } 58 | return null; 59 | } 60 | 61 | /** 62 | * 获取链表长度 63 | * @param root 64 | * @return 65 | */ 66 | private static int getListNodeLength(ListNode root) { 67 | int result = 0; 68 | if (root == null) 69 | return result; 70 | ListNode point = root; 71 | 72 | while (point != null) { 73 | point = point.next; 74 | result++; 75 | } 76 | return result; 77 | } 78 | 79 | /** 80 | * 解法二:不需要遍历链表 81 | * @param pHead1 82 | * @param pHead2 83 | * @return 84 | */ 85 | public static ListNode findFirstCommonNode2(ListNode pHead1, ListNode pHead2) { 86 | if (pHead1 == null || pHead2 == null) { 87 | return null; 88 | } 89 | 90 | ListNode p1 = pHead1; 91 | ListNode p2 = pHead2; 92 | while (p1 != p2) { 93 | p1 = (p1 != null ? p1.next : pHead2); 94 | p2 = (p2 != null ? p2.next : pHead1); 95 | } 96 | return p1; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/com/so/FindGreatestSum31.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第31题 5 | * 数组中一个或连续的多个整数组成一个子数组,求连续子数组的最大和 6 | * 7 | * @author qgl 8 | * @date 2017/08/14 9 | */ 10 | public class FindGreatestSum31 { 11 | /** 12 | * 获取连续子数组的最大和 13 | * 14 | * @param array 15 | * @return 16 | */ 17 | public static Integer findGreatestSum(int[] array) { 18 | if (array == null) { 19 | return null; 20 | } 21 | int greatest = 0; 22 | int curSum = 0; 23 | 24 | for (int i = 0; i < array.length; i++) { 25 | if (curSum + array[i] < 0) { 26 | greatest = 0; 27 | curSum = 0; 28 | } else { 29 | curSum += array[i]; 30 | greatest = Math.max(greatest, curSum); 31 | } 32 | } 33 | 34 | return greatest; 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/so/FindKthToTail15.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.ListNode; 4 | 5 | /** 6 | * 第15题 7 | * 输入一个链表,输出该链表的倒数第K个结点 8 | * 9 | * @author qgl 10 | * @date 2017/08/10 11 | */ 12 | public class FindKthToTail15 { 13 | 14 | /** 15 | * 解法一:一快一慢两个指针,快指针先走k步,然后两个指针同时走 16 | * 17 | * @param head 18 | * @param k 19 | * @return 20 | */ 21 | public static ListNode findKthToTail(ListNode head, int k) { 22 | if (head == null || k < 1) { 23 | return null; 24 | } 25 | ListNode fast = head; 26 | ListNode slow = head; 27 | while (k-- > 1) { 28 | if (fast.next == null) { 29 | return null; 30 | } 31 | fast = fast.next; 32 | } 33 | while (fast.next != null) { 34 | fast = fast.next; 35 | slow = slow.next; 36 | } 37 | return slow; 38 | } 39 | 40 | /** 41 | * 解法二:不推荐,O(n^2),先获取链表长度,在用链表长度减去k的值,求得该值处的节点 42 | * 43 | * @param head 44 | * @param k 45 | * @return 46 | */ 47 | public static ListNode findKthToTail2(ListNode head, int k) { 48 | int length = 0; 49 | ListNode p = head; 50 | while (p != null) { 51 | length++; 52 | p = p.next; 53 | } 54 | ListNode target = null; 55 | if (length == k) { 56 | target = head; 57 | } 58 | 59 | for (int i = 0; i < length - k; i++) { 60 | head = head.next; 61 | target = head; 62 | } 63 | return target; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/so/FindNumAppearOnce40.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第40题 5 | * 一个整型数组里除了两个数字之外,其他的数字都出现了两次,找出这两个只出现了一次的数字 6 | * 7 | * @author qgl 8 | * @date 2017/08/16 9 | */ 10 | public class FindNumAppearOnce40 { 11 | 12 | /** 13 | * 找出只出现了一次的数 14 | * @param array 15 | * @return 16 | */ 17 | public static int[] findNumAppearOnce(int[] array) { 18 | int[] onceNumber = new int[2]; 19 | if (array == null) { 20 | return null; 21 | } 22 | int number = 0; 23 | for (int i : array) { 24 | number ^= i; 25 | } 26 | int index = findFirstBitIs1(number); 27 | 28 | for (int i : array) { 29 | // 第index位是0的数,即第一个数 30 | if (isBit1(i, index)) { 31 | onceNumber[0] ^= i; 32 | } else { 33 | // 第index位是1的数,即第二个数 34 | onceNumber[1] ^= i; 35 | } 36 | } 37 | return onceNumber; 38 | } 39 | 40 | /** 41 | * 获取二进制中最右边是1的位置 42 | * @param number 43 | * @return 44 | */ 45 | private static int findFirstBitIs1(int number) { 46 | int indexBit = 0; 47 | 48 | while ((number & 1) == 0) { 49 | number = number >> 1; 50 | ++indexBit; 51 | } 52 | return indexBit; 53 | } 54 | 55 | /** 56 | * 判断从右边起,第index位是不是0 57 | * @param number 58 | * @param index 59 | * @return 60 | */ 61 | private static boolean isBit1(int number, int index) { 62 | number = number >> index; 63 | return (number & 1) == 0; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/so/FindNumber3.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第3题 5 | * 一个二维数组,每一行从左到右递增,每一列从上到下递增. 6 | * 输入一个二维数组和一个整数,判断数组中是否含有整数 7 | * 8 | * @author qgl 9 | * @date 2017/08/07 10 | */ 11 | public class FindNumber3 { 12 | 13 | /** 14 | * 解法一:双指针 15 | * 时间复杂度:O(mn),空间复杂度:O(1) 16 | * 17 | * @param array 18 | * @param target 19 | * @return 20 | */ 21 | public static boolean find(int[][] array, int target) { 22 | if (array == null || array.length == 0) { 23 | return false; 24 | } 25 | int row = 0; 26 | int column = array[0].length - 1; 27 | 28 | while (row < array.length && column >= 0) { 29 | if (array[row][column] == target) { 30 | return true; 31 | } 32 | if (array[row][column] > target) { 33 | column--; 34 | } else { 35 | row++; 36 | } 37 | } 38 | return false; 39 | } 40 | 41 | /** 42 | * 解法二:二分法 43 | * 时间复杂度:O(log mn),空间复杂度:O(1) 44 | * 45 | * @param array 46 | * @param target 47 | * @return 48 | */ 49 | /* 50 | public static boolean find2(int[][] array, int target) { 51 | if (array == null || array.length == 0) { 52 | return false; 53 | } 54 | 55 | int left = 0; 56 | int right = array.length * array[0].length - 1; 57 | int col = array[0].length; 58 | 59 | while (left <= right) { 60 | int mid = (left + right) / 2; 61 | int value = array[mid / col][mid % col]; 62 | 63 | if (value == target) { 64 | return true; 65 | } else if (value < target) { 66 | left = mid + 1; 67 | } else { 68 | right = mid - 1; 69 | } 70 | } 71 | 72 | return false; 73 | } 74 | */ 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/so/FindNumbersWithSum41.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 第41题 7 | * 41.1 输入一个递增排序的数组和一个数字s.在数组中查找两个数使他们的和为s,如果有多对数字的和等于s,输出两个数的乘积最小的一对 8 | * 41.2 输入一个整数s,求所有和为s的连续正数序列 9 | * @author qgl 10 | * @date 2017/08/16 11 | */ 12 | public class FindNumbersWithSum41 { 13 | 14 | /** 15 | * 获取和为s的两个数 16 | * @param sortedArray 17 | * @param s 18 | * @return 19 | */ 20 | public static ArrayList findNumbersWithSum(int[] sortedArray, int s) { 21 | ArrayList list = new ArrayList<>(); 22 | if (sortedArray == null) { 23 | return list; 24 | } 25 | int left = 0; 26 | int right = sortedArray.length - 1; 27 | 28 | while (right > left) { 29 | long curSum = sortedArray[right] + sortedArray[left]; 30 | if (curSum == s) { 31 | list.add(sortedArray[left]); 32 | list.add(sortedArray[right]); 33 | break; 34 | } else { 35 | if (curSum > s) 36 | right--; 37 | else 38 | left++; 39 | } 40 | } 41 | return list; 42 | } 43 | 44 | /** 45 | * 获取所有和为s的连续正数序列 46 | * @param s 47 | * @return 48 | */ 49 | public static ArrayList> findContinuousSequence(int s) { 50 | ArrayList> arrayList = new ArrayList<>(); 51 | if (s < 4) { 52 | return arrayList; 53 | } 54 | int small = 1; 55 | int big = 2; 56 | 57 | while (small < (s + 1) / 2) { 58 | int curSum = 0; 59 | for (int i = small; i <= big; i++) { 60 | curSum += i; 61 | } 62 | 63 | if (curSum == s) { 64 | ArrayList list = new ArrayList<>(); 65 | for (int i = small; i <= big; i++) { 66 | list.add(i); 67 | } 68 | arrayList.add(list); 69 | small++; 70 | } else if (curSum > s) { 71 | small++; 72 | } else { 73 | big++; 74 | } 75 | } 76 | return arrayList; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/so/FindPath25.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.*; 4 | 5 | import com.so.Common.TreeNode; 6 | 7 | /** 8 | * 第25题 9 | * 输入一个二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径 10 | * 11 | * @author qgl 12 | * @date 2017/08/13 13 | */ 14 | public class FindPath25 { 15 | private ArrayList> listAll = new ArrayList<>(); 16 | private ArrayList list = new ArrayList<>(); 17 | 18 | /** 19 | * 利用list寻找全路径 20 | * 21 | * @param root 22 | * @param target 23 | * @return 24 | */ 25 | public ArrayList> FindPath(TreeNode root, int target) { 26 | if (root == null) { 27 | return listAll; 28 | } 29 | list.add(root.val); 30 | target -= root.val; 31 | 32 | if (target == 0 && root.left == null && root.right == null) { 33 | listAll.add(new ArrayList<>(list)); 34 | } 35 | FindPath(root.left, target); 36 | FindPath(root.right, target); 37 | // 回退 38 | list.remove(list.size() - 1); 39 | return listAll; 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/main/java/com/so/FirstAppearingOnce55.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第55题 5 | * 请实现一个函数用来找出字符流中第一个只出现一次的字符 6 | * 7 | * @author qgl 8 | * @date 2017/08/30 9 | */ 10 | public class FirstAppearingOnce55 { 11 | static char[] chars = new char[256]; 12 | static StringBuilder sb = new StringBuilder(); 13 | 14 | /** 15 | * 输入字符流 16 | * 17 | * @param inputChars 18 | */ 19 | public static void insertChars(char[] inputChars) { 20 | for (char ch : inputChars) { 21 | sb.append(ch); 22 | chars[ch]++; 23 | } 24 | } 25 | 26 | /** 27 | * 获取字符流中第一个不重复的字符 28 | * 29 | * @return 30 | */ 31 | public static Character getFirstAppearingOnce() { 32 | char[] str = sb.toString().toCharArray(); 33 | for (char c : str) { 34 | if (chars[c] == 1) { 35 | return c; 36 | } 37 | } 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/so/FirstNotRepeating35.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Set; 5 | 6 | /** 7 | * 第35题 8 | * 在字符串中找出第一个只出现一次的字符 9 | * 10 | * @author qgl 11 | * @date 2017/08/15 12 | */ 13 | public class FirstNotRepeating35 { 14 | /** 15 | * 获取第一个只出现一次的字符的下标 16 | * 17 | * @param str 18 | * @return 19 | */ 20 | public static int getFirstNotRepeatingCharIndex(String str) { 21 | if (str == null) { 22 | return -1; 23 | } 24 | char[] strChar = str.toCharArray(); 25 | // 按照插入顺序保存key的位置 26 | LinkedHashMap hash = new LinkedHashMap(); 27 | for (char item : strChar) { 28 | if (hash.containsKey(item)) { 29 | hash.put(item, hash.get(item) + 1); 30 | } else { 31 | hash.put(item, 1); 32 | } 33 | } 34 | 35 | for (int i = 0; i < str.length(); i++) { 36 | char c = str.charAt(i); 37 | if (hash.get(c) == 1) { 38 | System.out.println("第一个只出现一次的字符是:" + c); 39 | return i; 40 | } 41 | } 42 | 43 | return -1; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/so/GetLeastNumbers30.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * 第30题 8 | * 输入N个整数,找出其中最小的k个数 9 | * 10 | * @author qgl 11 | * @date 2017/08/14 12 | */ 13 | public class GetLeastNumbers30 { 14 | 15 | /** 16 | * 获取最小的k个数 17 | * 18 | * @param array 19 | * @param k 20 | * @return 21 | */ 22 | public static ArrayList getLeastNumbers(int[] array, int k) { 23 | ArrayList list = new ArrayList<>(); 24 | if (array == null || k < 1 || k > array.length) { 25 | return list; 26 | } 27 | int[] kArray = Arrays.copyOfRange(array, 0, k); 28 | 29 | //根据输入数组前k个数建立最大堆 30 | for (int i = kArray.length / 2; i >= 0; i--) { 31 | maxHeapIfy(kArray, i, kArray.length); 32 | } 33 | 34 | //从k开始与根节点比较,若大于根节点,舍去,若小于,取代根节点,重排最大堆 35 | for (int i = k; i < array.length; i++) { 36 | if (array[i] < kArray[0]) { 37 | kArray[0] = array[i]; 38 | maxHeapIfy(kArray, 0, kArray.length); 39 | } 40 | } 41 | 42 | for (int i = kArray.length - 1; i >= 0; i--) { 43 | list.add(kArray[i]); 44 | } 45 | 46 | return list; 47 | } 48 | 49 | /** 50 | * 调整大根堆 51 | * 52 | * @param array 53 | * @param root 54 | * @param length 55 | */ 56 | private static void maxHeapIfy(int[] array, int root, int length) { 57 | int left = 2 * root + 1; 58 | 59 | if (left >= length) { 60 | return; 61 | } 62 | 63 | if (left + 1 < length && array[left] < array[left + 1]) { 64 | left++; 65 | } 66 | 67 | if (array[left] > array[root]) { 68 | swap(array, left, root); 69 | maxHeapIfy(array, left, length); 70 | } 71 | } 72 | 73 | private static void swap(int[] array, int i, int j) { 74 | int tmp = array[i]; 75 | array[i] = array[j]; 76 | array[j] = tmp; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/so/GetMedian64.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.PriorityQueue; 7 | 8 | /** 9 | * 第64题 10 | * 求数据流中的中位数 11 | * 12 | * @author qgl 13 | * @date 2017/08/31 14 | */ 15 | public class GetMedian64 { 16 | 17 | /** 18 | * 插入数据 19 | * 20 | * @param arr 21 | */ 22 | public static void insertArray(int[] arr) { 23 | for (int num : arr) { 24 | insertByMergeSort(num); 25 | insertByHeapSort(num); 26 | } 27 | } 28 | 29 | private static ArrayList list = new ArrayList<>(); 30 | 31 | /** 32 | * 对插入的数据进行(归并)排序 33 | * 34 | * @param num 35 | */ 36 | private static void insertByMergeSort(Integer num) { 37 | list.add(num); 38 | Collections.sort(list); 39 | } 40 | 41 | /** 42 | * 解法一:利用集合类的排序方法 43 | * 44 | * @return 45 | */ 46 | public static Double getMedian1() { 47 | int mid = list.size() / 2; 48 | 49 | if (list.size() % 2 == 0) { 50 | Double sum = Double.valueOf(list.get(mid)) + Double.valueOf(list.get(mid - 1)); 51 | return sum / 2; 52 | } 53 | return Double.valueOf(list.get(mid)); 54 | } 55 | 56 | private static int count = 0; 57 | private static PriorityQueue minHeap = new PriorityQueue<>(); 58 | private static PriorityQueue maxHeap = new PriorityQueue<>(16, new Comparator() { 59 | @Override 60 | public int compare(Integer o1, Integer o2) { 61 | return o2.compareTo(o1); 62 | } 63 | }); 64 | 65 | /** 66 | * 对插入的数据进行(堆)排序 67 | * 68 | * @param num 69 | */ 70 | private static void insertByHeapSort(Integer num) { 71 | count++; 72 | // 当数据的个数为奇数时,进入大根堆 73 | if ((count & 1) == 1) { 74 | minHeap.offer(num); 75 | maxHeap.offer(minHeap.poll()); 76 | } else { 77 | maxHeap.offer(num); 78 | minHeap.offer(maxHeap.poll()); 79 | } 80 | } 81 | 82 | /** 83 | * 解法二:利用优先级队列构建堆进行排序 84 | * 85 | * @return 86 | */ 87 | public static Double getMedian2() { 88 | if (count == 0) { 89 | return null; 90 | } 91 | 92 | // 当数据个数是奇数时,中位数就是大根堆的顶点 93 | if ((count & 1) == 1) { 94 | return (double) maxHeap.peek(); 95 | } else { 96 | return (double) (minHeap.peek() + maxHeap.peek()) / 2; 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/so/GetNumberOfK38.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 第38题 7 | * 统计一个数字在排序数组中出现的次数 8 | * 9 | * @author qgl 10 | * @date 2017/08/15 11 | */ 12 | public class GetNumberOfK38 { 13 | // 14 | public static int getNumberOfK(int[] arraySorted, int k) { 15 | // 若数组为空 16 | if (arraySorted == null || arraySorted.length == 0) { 17 | return 0; 18 | } 19 | // 若数组中只有一个数 20 | if (arraySorted.length == 1) { 21 | if (arraySorted[0] == k) { 22 | return 1; 23 | } 24 | return 0; 25 | } 26 | 27 | int result = 0; 28 | int mid = arraySorted.length / 2; 29 | 30 | if (k < arraySorted[mid]) { 31 | getNumberOfK(Arrays.copyOfRange(arraySorted, 0, mid), k); 32 | } else if (k > arraySorted[mid]) { 33 | getNumberOfK(Arrays.copyOfRange(arraySorted, mid, arraySorted.length), k); 34 | } else { 35 | result += getCount(arraySorted, mid); 36 | } 37 | 38 | return result; 39 | } 40 | 41 | /** 42 | * K与中间的值相等时,从中间值前后分别查找 43 | * 44 | * @param arraySorted 45 | * @param mid 46 | * @return 47 | */ 48 | private static int getCount(int[] arraySorted, int mid) { 49 | int k = arraySorted[mid]; 50 | int result = 0; 51 | 52 | for (int i = mid; i < arraySorted.length; i++) { 53 | if (arraySorted[i] == k) { 54 | result++; 55 | } else { 56 | break; 57 | } 58 | } 59 | 60 | for (int i = mid - 1; i >= 0; i--) { 61 | if (arraySorted[i] == k) { 62 | result++; 63 | } else { 64 | break; 65 | } 66 | } 67 | return result; 68 | } 69 | } -------------------------------------------------------------------------------- /src/main/java/com/so/HasPath66.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第66题 5 | * 判断在一个矩阵中是否存在一条包含某字符串所有字符的路径 6 | * 7 | * @author qgl 8 | * @date 2017/08/31 9 | */ 10 | public class HasPath66 { 11 | /** 12 | * 回溯法 13 | * @param matrix 14 | * @param rows 15 | * @param cols 16 | * @param str 17 | * @return 18 | */ 19 | public static boolean hasPath(char[] matrix, int rows, int cols, char[] str) { 20 | int flag[] = new int[matrix.length]; 21 | for (int i = 0; i < rows; i++) { 22 | for (int j = 0; j < cols; j++) { 23 | if (helper(matrix, rows, cols, i, j, str, 0, flag)) 24 | return true; 25 | } 26 | } 27 | return false; 28 | } 29 | 30 | /** 31 | * 判断是否匹配 32 | * @param matrix 33 | * @param rows 34 | * @param cols 35 | * @param i 36 | * @param j 37 | * @param str 38 | * @param k 39 | * @param flag 40 | * @return 41 | */ 42 | private static boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag) { 43 | int index = i * cols + j; 44 | if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == 1) 45 | return false; 46 | 47 | if(k == str.length - 1) 48 | return true; 49 | flag[index] = 1; 50 | 51 | if (helper(matrix, rows, cols, i - 1, j, str, k + 1, flag) 52 | || helper(matrix, rows, cols, i + 1, j, str, k + 1, flag) 53 | || helper(matrix, rows, cols, i, j - 1, str, k + 1, flag) 54 | || helper(matrix, rows, cols, i, j + 1, str, k + 1, flag)) { 55 | return true; 56 | } 57 | flag[index] = 0; 58 | return false; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/so/InversePairs36.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 第36题 7 | * 数组中的两个数字如果前面一个数字大于后面一个数字, 8 | * 则这两个数字组成一个逆序对,输入一个数组,求逆序对的总数 9 | * 10 | * @author qgl 11 | * @date 2017/08/15 12 | */ 13 | public class InversePairs36 { 14 | /** 15 | * 获取逆序对的总数 16 | * @param array 17 | * @return 18 | */ 19 | public static int inversePairs(int[] array) { 20 | if (array == null || array.length == 0) { 21 | return 0; 22 | } 23 | return getInversePairs(array, Arrays.copyOf(array, array.length), 0, array.length - 1) ; 24 | } 25 | 26 | private static int getInversePairs(int[] array, int[] copy, int low, int high) { 27 | if (low == high) { 28 | return 0; 29 | } 30 | int mid = (low + high) >> 1; 31 | int leftCount = getInversePairs(array, copy, low, mid); 32 | int rightCount = getInversePairs(array, copy, mid + 1, high); 33 | int count = 0; 34 | int i = mid; 35 | int j = high; 36 | int locCopy = high; 37 | while (i >= low && j > mid) { 38 | if (array[i] > array[j]) { 39 | count += j - mid; 40 | copy[locCopy--] = array[i--]; 41 | // 防止数值过大而求余 42 | count %= 1000000007; 43 | } else { 44 | copy[locCopy--] = array[j--]; 45 | } 46 | } 47 | 48 | for (int a = i; a >= low; a--) { 49 | copy[locCopy--] = array[a]; 50 | } 51 | for (int b = j; b > mid; b--) { 52 | copy[locCopy--] = array[b]; 53 | } 54 | for (int s = low; s <= high; s++) { 55 | array[s] = copy[s]; 56 | } 57 | return (leftCount + rightCount + count) % 1000000007; 58 | } 59 | 60 | /** 记录逆序对的数量 */ 61 | private int count = 0; 62 | 63 | /** 64 | * 解法二:获取逆序对的总数 65 | * 66 | * @param array 输入的数组长度较大时有bug 67 | * @return 68 | */ 69 | public int inversePairs2(int[] array) { 70 | if (array == null) { 71 | return 0; 72 | } 73 | mergeSort(array, 0, array.length - 1); 74 | return count; 75 | } 76 | 77 | private void mergeSort(int[] data, int start, int end) { 78 | int mid = (start + end) / 2; 79 | if (start < end) { 80 | mergeSort(data, start, mid); 81 | mergeSort(data, mid + 1, end); 82 | merge(data, start, mid, end); 83 | } 84 | } 85 | 86 | public void merge(int[] data, int start, int mid, int end) { 87 | int arr[] = new int[end - start + 1]; 88 | int c = 0; 89 | int s = start; 90 | int index = mid + 1; 91 | while (start <= mid && index <= end) { 92 | if (data[start] < data[index]) { 93 | arr[c++] = data[start++]; 94 | } else { 95 | count += index - start; 96 | // 防止数值过大而求余 97 | count %= 1000000007; 98 | arr[c++] = data[index++]; 99 | } 100 | } 101 | 102 | while (start <= mid) { 103 | arr[c++] = data[start++]; 104 | } 105 | 106 | while (index <= end) { 107 | arr[c++] = data[index++]; 108 | } 109 | 110 | for (int d : arr) { 111 | data[s++] = d; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/so/IsContinuous44.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 第44题 7 | * 判断扑克牌中的顺子,0表示大小王(可以是任意数) 8 | * 1表示A,2~10为本身,11表示J,12表示Q,13表示K 9 | * 10 | * @author qgl 11 | * @date 2017/08/16 12 | */ 13 | public class IsContinuous44 { 14 | 15 | /** 16 | * 判断是否是顺子 17 | * @param numbers 18 | * @return 19 | */ 20 | public static boolean isContinuous(int [] numbers) { 21 | if (numbers == null || numbers.length == 0) { 22 | return false; 23 | } 24 | int count = 0; 25 | int diff = 0; 26 | Arrays.sort(numbers); 27 | 28 | for (int i = 0; i < numbers.length - 1; i++) { 29 | if (numbers[i] == 0) { 30 | count++; 31 | continue; 32 | } 33 | if (numbers[i] == numbers[i+1]) { 34 | return false; 35 | } 36 | 37 | diff += numbers[i+1] - numbers[i] - 1; 38 | } 39 | 40 | return diff <= count; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/com/so/IsNumber54.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第54题 5 | * 判断字符串是否表示数值(包括整数和小数) 6 | * 7 | * @author qgl 8 | * @date 2017/08/30 9 | */ 10 | public class IsNumber54 { 11 | 12 | /** 13 | * 解法一:逐个字符进行判断 14 | * 15 | * @param str 16 | * @return 17 | */ 18 | public static boolean isNumber1(char[] str) { 19 | if (str == null) { 20 | return false; 21 | } 22 | int index = 0; 23 | int eCount = 0; 24 | int point = 0; 25 | // 如果第一个字符是符号就跳过 26 | if (str[0] == '-' || str[0] == '+') 27 | index++; 28 | 29 | for (int i = index; i < str.length; i++) { 30 | if (str[i] == '-' || str[i] == '+') { 31 | if (str[i - 1] != 'e' && str[i - 1] != 'E') 32 | return false; 33 | continue; 34 | } 35 | 36 | if (str[i] == 'e' || str[i] == 'E') { 37 | eCount++; 38 | if (eCount > 1) 39 | return false; 40 | if (i == 0 || str[i - 1] < 48 || str[i - 1] > 57 || i == str.length - 1) 41 | return false; 42 | point++; 43 | continue; 44 | } 45 | 46 | if (str[i] == '.') { 47 | point++; 48 | if (point > 1) 49 | return false; 50 | continue; 51 | } 52 | // 出现非数字且不是e/E则返回false(小数点和符号用continue跳过了) 53 | if ((str[i] < 48 || str[i] > 57) && (str[i] != 'e') && (str[i] != 'E')) 54 | return false; 55 | } 56 | return true; 57 | } 58 | 59 | /** 60 | * 解法二:正则表达式 61 | ? 表示零次或一次匹配前面的字符或子表达式 * 表示零次或多次匹配前面的字符或子表达式 62 | + 表示一次或多次匹配前面的字符或子表达式 . 表示匹配除了换行符的任何单个字符 63 | * 64 | * @param str 65 | * @return 66 | */ 67 | public static boolean isNumber2(char[] str) { 68 | String s = String.valueOf(str); 69 | return s.matches("[+-]?[0-9]*(\\.[0-9]*)?([eE][+-]?[0-9]+)?"); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/so/IsPopOrder22.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Stack; 4 | import java.util.Vector; 5 | 6 | /** 7 | * 第22题 8 | * 输入两个整数序列,第一个序列表示压入顺序,判断第二个序列是否为弹出顺序 9 | * 10 | * @author qgl 11 | * @date 2017/08/10 12 | */ 13 | public class IsPopOrder22 { 14 | 15 | /** 16 | * 利用栈判断一个序列是否是另一个序列的弹出顺序 17 | * @param pushList 压入顺序序列 18 | * @param popList 弹出顺序序列 19 | * @return 判断结果 20 | */ 21 | public static boolean isPopOrder(int[] pushList, int[] popList) { 22 | if (pushList == null || popList == null) { 23 | return false; 24 | } 25 | 26 | int point = 0; 27 | Stack stack = new Stack(); 28 | 29 | for (int i = 0; i < pushList.length; i++) { 30 | stack.push(pushList[i]); 31 | while (!stack.isEmpty() && stack.peek() == popList[point]) { 32 | stack.pop(); 33 | point++; 34 | } 35 | } 36 | return stack.isEmpty(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/so/IsSymmetrical59.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.TreeNode; 4 | 5 | import java.util.Stack; 6 | 7 | /** 8 | * 第59题 9 | * 判断二叉树是否是对称的 10 | * 11 | * @author qgl 12 | * @date 2017/08/30 13 | */ 14 | public class IsSymmetrical59 { 15 | 16 | /** 17 | * 判断二叉树是不是对称的 18 | * @param pRoot 19 | * @return 20 | */ 21 | public static boolean isSymmetrical(TreeNode pRoot){ 22 | return pRoot == null || isCommon(pRoot.left, pRoot.right); 23 | } 24 | 25 | /** 26 | * 判断左右子树是否相等 27 | * @param leftNode 28 | * @param rightNode 29 | * @return 30 | */ 31 | public static boolean isCommon(TreeNode leftNode, TreeNode rightNode) { 32 | if (leftNode == null && rightNode == null) { 33 | return true; 34 | } 35 | if (leftNode == null || rightNode == null) { 36 | return false; 37 | } 38 | 39 | return leftNode.val == rightNode.val && isCommon(leftNode.left,rightNode.right) && isCommon(leftNode.right,rightNode.left); 40 | } 41 | 42 | /** 43 | * 解法二:迭代 44 | * 时间复杂度:O(n),空间复杂度:O(n) 45 | * 46 | * @param root 47 | * @return 48 | */ 49 | public static boolean isSymmetric2(TreeNode root) { 50 | Stack stack = new Stack<>(); 51 | stack.push(root); 52 | stack.push(root); 53 | while (!stack.isEmpty()) { 54 | TreeNode t1 = stack.pop(); 55 | TreeNode t2 = stack.pop(); 56 | if (t1 == null && t2 == null) { 57 | continue; 58 | } 59 | if (t1 == null || t2 == null) { 60 | return false; 61 | } 62 | if (t1.val != t2.val) { 63 | return false; 64 | } 65 | stack.push(t1.left); 66 | stack.push(t2.right); 67 | stack.push(t1.right); 68 | stack.push(t2.left); 69 | } 70 | return true; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/so/KthNode63.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.TreeNode; 4 | 5 | import java.util.Stack; 6 | 7 | /** 8 | * 第63题 9 | * 给定一棵二叉搜索树,请找出其中的第k小的结点 10 | * 11 | * @author qgl 12 | * @date 2017/08/30 13 | */ 14 | public class KthNode63 { 15 | /** 16 | * 解法一:递归 17 | * 18 | * @param pRoot 19 | * @param k 20 | * @return 21 | */ 22 | private int count = 0; 23 | public TreeNode KthNode(TreeNode pRoot, int k) { 24 | if(pRoot == null) { 25 | return null; 26 | } 27 | TreeNode node = KthNode(pRoot.left, k); 28 | if(node != null) { 29 | return node; 30 | } 31 | count++; 32 | if(count == k) { 33 | return pRoot; 34 | } 35 | node = KthNode(pRoot.right, k); 36 | return node; 37 | } 38 | 39 | /** 40 | * 解法二:非递归,借用栈查找 41 | * 42 | * @param pRoot 43 | * @param k 44 | * @return 45 | */ 46 | public TreeNode getKthNode2(TreeNode pRoot, int k) { 47 | if (pRoot == null || k < 1) { 48 | return null; 49 | } 50 | int index = 0; 51 | TreeNode root = pRoot; 52 | Stack s = new Stack<>(); 53 | while (root != null || !s.isEmpty()) { 54 | while (root != null) { 55 | s.push(root); 56 | root = root.left; 57 | } 58 | 59 | if (!s.isEmpty()) { 60 | root = s.pop(); 61 | index++; 62 | if (index == k) { 63 | return root; 64 | } 65 | root = root.right; 66 | } 67 | } 68 | return null; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/so/LastRemaining45.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.LinkedList; 4 | 5 | /** 6 | * 第45题 7 | * 0,1...n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字. 8 | * 求这个圈圈里剩下的最后一个数字 9 | * 10 | * @author qgl 11 | * @date 2017/08/16 12 | */ 13 | public class LastRemaining45 { 14 | 15 | /** 16 | * 解法一:借助链表 17 | * @param n 18 | * @param m 19 | * @return 20 | */ 21 | public static int lastRemain1(int n, int m) { 22 | LinkedList list = new LinkedList(); 23 | int index = 0; 24 | 25 | for (int i = 0; i < n; i ++) { 26 | list.add(i); 27 | } 28 | 29 | while (list.size() > 1) { 30 | index = (index + m - 1) % list.size(); 31 | list.remove(index); 32 | } 33 | return list.size() == 1 ? list.get(0) : -1; 34 | } 35 | 36 | /** 37 | * 解法二:公式法 38 | * @param n 39 | * @param m 40 | * @return 41 | */ 42 | public static int lastRemain2(int n, int m) { 43 | if (n < 1 || m < 1) { 44 | return -1; 45 | } 46 | int last = 0; 47 | for (int i = 2; i <= n; i ++) { 48 | // i个人时删除数的索引等于i-1个人时删除数的索引+k(再对i取余) 49 | last = (last + m) % i; 50 | } 51 | return last; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/so/LevelPrintTree61.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.*; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第61题 8 | * 把二叉树打印成多行,从上到下按层打印二叉树,同一层结点从左至右输出。 9 | * 10 | * @author qgl 11 | * @date 2017/08/30 12 | */ 13 | public class LevelPrintTree61 { 14 | /** 15 | * 从左至右打印每行二叉树 16 | * @param pRoot 17 | * @return 18 | */ 19 | public static ArrayList> printTreeNodeByLeftToRight(TreeNode pRoot) { 20 | ArrayList> res = new ArrayList<>(); 21 | if (pRoot == null) { 22 | return res; 23 | } 24 | Queue queue = new LinkedList<>(); 25 | queue.add(pRoot); 26 | ArrayList tmp = new ArrayList<>(); 27 | int start = 0; 28 | int end = 1; 29 | 30 | while (!queue.isEmpty()) { 31 | TreeNode node = queue.poll(); 32 | tmp.add(node.val); 33 | start++; 34 | if (node.left != null) { 35 | queue.offer(node.left); 36 | } 37 | if (node.right != null) { 38 | queue.offer(node.right); 39 | } 40 | 41 | if (start == end) { 42 | start = 0; 43 | end = queue.size(); 44 | res.add(new ArrayList<>(tmp)); 45 | tmp.clear(); 46 | } 47 | } 48 | return res; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/so/MaxInWindows65.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * 第65题 7 | * 求滑动窗口的最大值 8 | * 9 | * @author qgl 10 | * @date 2017/08/31 11 | */ 12 | public class MaxInWindows65 { 13 | 14 | /** 15 | * 解法一:两个for循环 16 | * 17 | * @param num 18 | * @param size 19 | * @return 20 | */ 21 | public static ArrayList maxInWindows1(int[] num, int size) { 22 | ArrayList list = new ArrayList<>(); 23 | if (num == null || size < 1 || num.length < size) 24 | return list; 25 | int length = num.length - size + 1; 26 | 27 | for (int i = 0; i < length; i++) { 28 | int current = size + i; 29 | int max = num[i]; 30 | for (int j = i; j < current; j++) { 31 | if (max < num[j]) { 32 | max = num[j]; 33 | } 34 | } 35 | list.add(max); 36 | } 37 | return list; 38 | } 39 | 40 | /** 41 | * 解法二:时间复杂度更低的双端队列 42 | * 43 | * @param num 44 | * @param size 45 | * @return 46 | */ 47 | public static ArrayList maxInWindows2(int[] num, int size) { 48 | ArrayList res = new ArrayList<>(); 49 | if (size == 0) return res; 50 | ArrayDeque q = new ArrayDeque<>(); 51 | 52 | for (int i = 0; i < num.length; i++) { 53 | int begin = i - size + 1; 54 | if (q.isEmpty()) 55 | q.add(i); 56 | else if (begin > q.peekFirst()) 57 | q.pollFirst(); 58 | 59 | while ((!q.isEmpty()) && num[q.peekLast()] <= num[i]) 60 | q.pollLast(); 61 | q.add(i); 62 | if (begin >= 0) 63 | res.add(num[q.peekFirst()]); 64 | } 65 | return res; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/so/MergeLinked17.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.ListNode; 4 | 5 | /** 6 | * 第17题 7 | * 输入两个递增的链表,合并这两个链表并使新链表仍然是递增的 8 | * 9 | * @author qgl 10 | * @date 2017/08/10 11 | */ 12 | public class MergeLinked17 { 13 | /** 14 | * 解法一:递归 15 | * 时间复杂度:O(m+n),空间复杂度:O(m+n) 16 | * 17 | * @param list1 18 | * @param list2 19 | * @return 20 | */ 21 | public static ListNode mergeTwoLists(ListNode list1, ListNode list2) { 22 | if (list1 == null) { 23 | return list2; 24 | } 25 | if (list2 == null) { 26 | return list1; 27 | } 28 | 29 | if (list1.val < list2.val) { 30 | list1.next = mergeTwoLists(list1.next, list2); 31 | return list1; 32 | } else { 33 | list2.next = mergeTwoLists(list1, list2.next); 34 | return list2; 35 | } 36 | } 37 | 38 | /** 39 | * 解法二:迭代 40 | * 时间复杂度:O(m+n),空间复杂度:O(1) 41 | * 42 | * @param list1 43 | * @param list2 44 | * @return 45 | */ 46 | public static ListNode mergeTwoLists2(ListNode list1, ListNode list2) { 47 | ListNode preHead = new ListNode(-1); 48 | ListNode pre = preHead; 49 | 50 | while (list1 != null && list2 != null) { 51 | if (list1.val < list2.val) { 52 | pre.next = list1; 53 | list1 = list1.next; 54 | } else { 55 | pre.next = list2; 56 | list2 = list2.next; 57 | } 58 | pre = pre.next; 59 | } 60 | 61 | pre.next = list1 == null ? list2 : list1; 62 | return preHead.next; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/so/MinCParent50.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 第50题 7 | * 寻找树的两个节点的最低公共祖先 8 | * 9 | * @author qgl 10 | * @date 2017/09/02 11 | */ 12 | public class MinCParent50 { 13 | 14 | static class BinaryTreeNode { 15 | public int value; 16 | public BinaryTreeNode leftNode; 17 | public BinaryTreeNode rightNode; 18 | public BinaryTreeNode parentNode; 19 | 20 | public BinaryTreeNode(int value) { 21 | this.value = value; 22 | } 23 | } 24 | 25 | /** 26 | * 若树是二叉搜素树,递归调用二叉树 27 | * 时间复杂度是O(log n),空间复杂度是O(1) 28 | * 29 | * @param rootParent 30 | * @param root 31 | * @param node1 32 | * @param node2 33 | * @return 34 | */ 35 | public static BinaryTreeNode getLowestCommonAncestor1(BinaryTreeNode rootParent, BinaryTreeNode root, BinaryTreeNode node1, BinaryTreeNode node2) { 36 | if (root == null || node1 == null || node2 == null) { 37 | return null; 38 | } 39 | if ((root.value - node1.value) * (root.value - node2.value) < 0) { 40 | return root; 41 | } else if ((root.value - node1.value) * (root.value - node2.value) > 0) { 42 | BinaryTreeNode newRoot = ((root.value > node1.value) && (root.value > node2.value)) 43 | ? root.leftNode : root.rightNode; 44 | return getLowestCommonAncestor1(root, newRoot, node1, node2); 45 | } else { 46 | return rootParent; 47 | } 48 | } 49 | 50 | /** 51 | * 若树是普通树,并没有指向父节点的指针,获取node节点的路径时间复杂度为O(n) 52 | * 时间复杂度是O(n),空间复杂度是O(log n) 53 | * 54 | * @param root 55 | * @param node1 56 | * @param node2 57 | * @return 58 | */ 59 | public static BinaryTreeNode getLowestCommonAncestor2(BinaryTreeNode root, BinaryTreeNode node1, BinaryTreeNode node2) { 60 | if (root == null || node1 == null || node2 == null) { 61 | return null; 62 | } 63 | Stack path1 = new Stack(); 64 | boolean flag1 = getThePathOfTheNode(root, node1, path1); 65 | if (!flag1) {//树上没有node1节点 66 | return null; 67 | } 68 | Stack path2 = new Stack(); 69 | boolean flag2 = getThePathOfTheNode(root, node2, path2); 70 | if (!flag2) {//树上没有node2节点 71 | return null; 72 | } 73 | if (path1.size() > path2.size()) { //让两个路径等长 74 | while (path1.size() != path2.size()) { 75 | path1.pop(); 76 | } 77 | } else { 78 | while (path1.size() != path2.size()) { 79 | path2.pop(); 80 | } 81 | } 82 | if (path1 == path2) {//当两个节点在一条路径上时 83 | path1.pop(); 84 | return path1.pop(); 85 | } else { 86 | BinaryTreeNode p = path1.pop(); 87 | BinaryTreeNode q = path2.pop(); 88 | while (q != p) { 89 | p = path1.pop(); 90 | q = path2.pop(); 91 | } 92 | return p; 93 | } 94 | } 95 | 96 | /** 97 | * 若树是普通树,但有指向父节点的指针,类似于求两个链表的第一个公共节点。由于每个节点的深度最多为log n 98 | * 时间复杂度为O(log n),空间复杂度O(1) 99 | * 100 | * @param root 101 | * @param node1 102 | * @param node2 103 | * @return 104 | */ 105 | public static BinaryTreeNode getLowestCommonAncestor3(BinaryTreeNode root, BinaryTreeNode node1, BinaryTreeNode node2) { 106 | if (root == null || node1 == null || node2 == null) { 107 | return null; 108 | } 109 | int depth1 = findTheDepthOfTheNode(node1, node2); 110 | if (depth1 == -1) { 111 | return node2.parentNode; 112 | } 113 | int depth2 = findTheDepthOfTheNode(node2, node1); 114 | if (depth2 == -1) { 115 | return node1.parentNode; 116 | } 117 | //p指向较深的节点q指向较浅的节点 118 | BinaryTreeNode p = depth1 > depth2 ? node1 : node2; 119 | BinaryTreeNode q = depth1 > depth2 ? node2 : node1; 120 | int depth = Math.abs(depth1 - depth2); 121 | while (depth > 0) { 122 | p = p.parentNode; 123 | depth--; 124 | } 125 | while (p != q) { 126 | p = p.parentNode; 127 | q = q.parentNode; 128 | } 129 | return p; 130 | } 131 | 132 | /** 133 | * 获得根节点到node节点的路径 134 | * 135 | * @param root 136 | * @param node 137 | * @param path 138 | * @return 139 | */ 140 | public static boolean getThePathOfTheNode(BinaryTreeNode root, BinaryTreeNode node, Stack path) { 141 | path.push(root); 142 | if (root == node) { 143 | return true; 144 | } 145 | boolean found = false; 146 | if (root.leftNode != null) { 147 | found = getThePathOfTheNode(root.leftNode, node, path); 148 | } 149 | if (!found && root.rightNode != null) { 150 | found = getThePathOfTheNode(root.rightNode, node, path); 151 | } 152 | if (!found) { 153 | path.pop(); 154 | } 155 | return found; 156 | } 157 | 158 | /** 159 | * 求node1的深度 160 | * 如果node1和node2在一条路径上,则返回-1,否则返回node1的深度 161 | * 162 | * @param node1 163 | * @param node2 164 | * @return 165 | */ 166 | public static int findTheDepthOfTheNode(BinaryTreeNode node1, BinaryTreeNode node2) { 167 | int depth = 0; 168 | while (node1.parentNode != null) { 169 | node1 = node1.parentNode; 170 | depth++; 171 | if (node1 == node2) { 172 | return -1; 173 | } 174 | } 175 | return depth; 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /src/main/java/com/so/MinNumber8.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第8题 5 | * 输入一个非递减排序数组的一个旋转,输出旋转数组的最小元素。 6 | * 7 | * @author qgl 8 | * @date 2017/08/09 9 | */ 10 | public class MinNumber8 { 11 | 12 | /** 13 | * 解法一:二分查找(寻找变化点) 14 | * 时间复杂度:O(log n),空间复杂度:O(1) 15 | * 16 | * @param array 17 | * @return 18 | */ 19 | public static int minInReversingList(int[] array) { 20 | if (array == null || array.length == 0) { 21 | return -1; 22 | } 23 | if (array.length == 1 || array[array.length - 1] > array[0]) { 24 | return array[0]; 25 | } 26 | 27 | int left = 0; 28 | int right = array.length - 1; 29 | while (left <= right) { 30 | int mid = (left + right) / 2; 31 | if (array[mid] > array[mid + 1]) { 32 | return array[mid + 1]; 33 | } 34 | if (array[mid - 1] > array[mid]) { 35 | return array[mid]; 36 | } 37 | 38 | if (array[mid] > array[0]) { 39 | left = mid + 1; 40 | } else { 41 | right = mid - 1; 42 | } 43 | } 44 | 45 | return -1; 46 | } 47 | 48 | /** 49 | * 解法二:二分查找(最左下标) 50 | * 时间复杂度:O(log n),空间复杂度:O(1) 51 | * 52 | * @param nums 53 | * @return 54 | */ 55 | public int minInReversingList2(int[] nums) { 56 | if (nums == null || nums.length == 0) { 57 | return -1; 58 | } 59 | 60 | int left = 0; 61 | int right = nums.length - 1; 62 | while (left < right) { 63 | int mid = (left + right) / 2; 64 | if (nums[mid] > nums[right]) { 65 | left = mid + 1; 66 | } else { 67 | right = mid; 68 | } 69 | } 70 | return nums[left]; 71 | } 72 | 73 | /** 74 | * 第8.1题:若非递减排序数组中有重复元素,求最小元素 75 | * 时间复杂度:O(log n),空间复杂度:O(1) 76 | * 77 | * @param nums 78 | * @return 79 | */ 80 | public int findMin(int[] nums) { 81 | if (nums == null || nums.length == 0) { 82 | return -1; 83 | } 84 | 85 | int left = 0; 86 | int right = nums.length - 1; 87 | while (left < right) { 88 | int mid = (left + right) / 2; 89 | if (nums[mid] > nums[right]) { 90 | left = mid + 1; 91 | } else if (nums[mid] < nums[right]) { 92 | right = mid; 93 | } else { 94 | right--; 95 | } 96 | } 97 | return nums[left]; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/so/MirrorRecursively19.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Stack; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第19题 8 | * 输入一个二叉树,输出它的镜像 9 | * 10 | * @author qgl 11 | * @date 2017/08/10 12 | */ 13 | public class MirrorRecursively19 { 14 | 15 | /** 16 | * 解法一:递归 17 | * @param root 18 | */ 19 | public void Mirror(TreeNode root) { 20 | if (root == null) { 21 | return; 22 | } 23 | TreeNode tmp = root.left; 24 | root.left = root.right; 25 | root.right = tmp; 26 | 27 | Mirror(root.left); 28 | Mirror(root.right); 29 | } 30 | 31 | /** 32 | * 解法二:非递归,利用栈 33 | * @param root 34 | * @return 35 | */ 36 | public void Mirror2(TreeNode root) { 37 | if (root == null) { 38 | return ; 39 | } 40 | Stack stack = new Stack<>(); 41 | 42 | while (root != null || !stack.isEmpty()) { 43 | while (root != null) { 44 | // 交换左右子节点 45 | TreeNode temp = root.left; 46 | root.left = root.right; 47 | root.right = temp; 48 | stack.push(root); 49 | root = root.left; 50 | } 51 | 52 | root = stack.pop(); 53 | root = root.right; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/so/MoreThanHalfNum29.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第29题 5 | * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字 6 | * 7 | * @author qgl 8 | * @date 2017/08/14 9 | */ 10 | public class MoreThanHalfNum29 { 11 | /** 12 | * 获取数组中出现次数超过数组长度一半的数字 13 | * 14 | * @param nums 15 | * @return 16 | */ 17 | public static int moreThanHalfNum(int[] nums) { 18 | int count = 0; 19 | int candidate = 0; 20 | 21 | for (int num : nums) { 22 | if (count == 0) { 23 | candidate = num; 24 | } 25 | count += (num == candidate) ? 1 : -1; 26 | } 27 | 28 | return checkMoreThanHalf(nums, candidate) ? candidate : 0; 29 | } 30 | 31 | /** 32 | * 检查输入的数字出现的次数是否超过数组长度一半 33 | * 34 | * @param array 35 | * @param number 36 | * @return 37 | */ 38 | private static boolean checkMoreThanHalf(int[] array, Integer number) { 39 | int times = 0; 40 | for (int i : array) { 41 | if (i == number) { 42 | times++; 43 | } 44 | } 45 | return times * 2 >= array.length; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/so/MovingCount67.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第67题 5 | * 机器人的运动范围,一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格, 6 | * 但是不能进入行坐标和列坐标的数位之和大于k的格子。求机器人能够达到多少个格子 7 | * 8 | * @author qgl 9 | * @date 2017/08/31 10 | */ 11 | public class MovingCount67 { 12 | 13 | /** 14 | * 机器人能到达的格子数 15 | * @param k 16 | * @param rows 17 | * @param cols 18 | * @return 19 | */ 20 | public static int movingCount(int k, int rows, int cols) { 21 | int[][] flag = new int[rows][cols]; // 记录是否已经走过 22 | return helper(0, 0, rows, cols, flag, k); 23 | } 24 | 25 | /** 26 | * 递归查找 27 | * @param i 28 | * @param j 29 | * @param rows 30 | * @param cols 31 | * @param flag 32 | * @param k 33 | * @return 34 | */ 35 | private static int helper(int i, int j, int rows, int cols, int[][] flag, int k) { 36 | if (i < 0 || i >= rows || j < 0 || j >= cols || 37 | numSum(i) + numSum(j) > k || flag[i][j] == 1) { 38 | return 0; 39 | } 40 | flag[i][j] = 1; 41 | return helper(i - 1, j, rows, cols, flag, k) 42 | + helper(i + 1, j, rows, cols, flag, k) 43 | + helper(i, j - 1, rows, cols, flag, k) 44 | + helper(i, j + 1, rows, cols, flag, k) + 1; 45 | } 46 | 47 | /** 48 | * 求输入数的每一位之和 49 | * @param i 50 | * @return 51 | */ 52 | private static int numSum(int i) { 53 | int sum = 0; 54 | while (i > 0) { 55 | sum += i % 10; 56 | i = i / 10; 57 | } 58 | return sum; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/so/MultiplyArray52.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第52题 5 | * 构建乘积数组 6 | * 7 | * @author qgl 8 | * @date 2017/08/29 9 | */ 10 | public class MultiplyArray52 { 11 | 12 | /** 13 | * 利用矩阵法构建乘积数组 14 | * 15 | * @param A 16 | * @return 17 | */ 18 | public static int[] multiply(int[] A) { 19 | int length = A.length; 20 | int[] B = new int[length]; 21 | if (length != 0) { 22 | B[0] = 1; 23 | //计算下三角连乘 24 | for (int i = 1; i < length; i++) { 25 | B[i] = B[i - 1] * A[i - 1]; 26 | } 27 | int temp = 1; 28 | //计算上三角连乘 29 | for (int j = length - 2; j >= 0; j--) { 30 | temp *= A[j + 1]; 31 | B[j] *= temp; 32 | } 33 | } 34 | return B; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/so/NextTreeNode58.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第58题 5 | * 给定一个二叉树的某个结点,请找出中序遍历顺序的下一个结点并且返回 6 | * 7 | * @author qgl 8 | * @date 2017/08/30 9 | */ 10 | public class NextTreeNode58 { 11 | /** 12 | * 二叉树 13 | */ 14 | static class TreeLinkNode { 15 | int val; 16 | TreeLinkNode left = null; 17 | TreeLinkNode right = null; 18 | TreeLinkNode next = null; 19 | 20 | TreeLinkNode(int val) { 21 | this.val = val; 22 | } 23 | } 24 | 25 | /** 26 | * 获取输入节点的下一个节点 27 | * 28 | * @param pNode 29 | * @return 30 | */ 31 | public static TreeLinkNode getTreeLinkNextNode(TreeLinkNode pNode) { 32 | if (pNode == null) { 33 | return null; 34 | } 35 | if (pNode.right != null) { 36 | pNode = pNode.right; 37 | while (pNode.left != null) { 38 | pNode = pNode.left; 39 | } 40 | return pNode; 41 | } 42 | 43 | while (pNode.next != null) { 44 | // 找第一个当前节点是父节点左孩子的节点 45 | if (pNode.next.left == pNode) 46 | return pNode.next; 47 | pNode = pNode.next; 48 | } 49 | return null; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/so/NumberOf1Bw32.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第32题 5 | * 输入一个整数n,求从1到n这N个十进制表示中1出现的次数 6 | * 7 | * @author qgl 8 | * @date 2017/08/14 9 | */ 10 | public class NumberOf1Bw32 { 11 | 12 | /** 13 | * 解法一 14 | * 主要思路:设定整数点作为位置点i(对应n的个位、十位等),分别对每个数位上有多少包含1的点进行分析 15 | * 根据设定的整数位置,对n进行分割,分为高位和低位 16 | * 当i表示百位,且百位对应的数>=2,如n=31456,i=100,则a=314,b=56,此时百位为1的次数有a/10+1=32(最高两位0~31), 17 | * 每一次都包含100个连续的点,即共有(a%10+1)*100个点的百位为1 18 | * 当i表示百位,且百位对应的数为1,如n=31156,i=100,则a=311,b=56,此时百位对应的就是1,则共有a%10(最高两位0-30)次是 19 | * 包含100个连续点,当最高两位为31(即a=311),本次只对应局部点00~56,共b+1次,所有点加起来共有(a%10*100)+(b+1),这些点百位对应为1 20 | * 当i表示百位,且百位对应的数为0,如n=31056,i=100,则a=310,b=56,此时百位为1的次数有a/10=31(最高两位0~30) 21 | * 综合以上三种情况,当百位对应0或>=2时,有(a+8)/10次包含所有100个点,还有当百位为1(a%10==1),需要增加局部点b+1 22 | * 补8是因为当百位为0,则a/10==(a+8)/10,当百位>=2,补8会产生进位位,效果等同于(a/10+1) 23 | * 24 | * @param n 25 | * @return 26 | */ 27 | public static int NumberOf1Between1AndN1(int n) { 28 | int count = 0; 29 | 30 | for (int i = 1; i <= n; i *= 10) { 31 | int a = n / i; // 高位 32 | int b = n % i; // 低位 33 | count += (a + 8) / 10 * i; 34 | if (a % 10 == 1) { 35 | count += b + 1; 36 | } 37 | } 38 | return count; 39 | } 40 | 41 | /** 42 | * 解法二 43 | * 44 | * @param n 45 | * @return 46 | */ 47 | public static long NumberOf1Between1AndN2(long n) { 48 | long count = 0; // 1的个数 49 | long i = 1; // 当前位 50 | long current = 0, after = 0, before = 0; 51 | 52 | while ((n / i) != 0) { 53 | before = n / (i * 10); // 高位 54 | current = (n / i) % 10; // 当前位 55 | after = n - (n / i) * i; // 低位 56 | 57 | if (current == 0) { 58 | //如果为0,出现1的次数由高位决定,等于高位数字 * 当前位数 59 | count = count + before * i; 60 | } else if (current == 1) { 61 | //如果为1,出现1的次数由高位和低位决定,高位*当前位+低位+1 62 | count = count + before * i + after + 1; 63 | } else if (current > 1) { 64 | // 如果大于1,出现1的次数由高位决定,(高位数字+1)* 当前位数 65 | count = count + (before + 1) * i; 66 | } 67 | //前移一位 68 | i = i * 10; 69 | } 70 | return count; 71 | } 72 | 73 | /** 74 | * 解法三:不推荐,时间复杂度高 75 | * 76 | * @param n 77 | * @return 78 | */ 79 | public static int NumberOf1Between1AndN3(int n) { 80 | if (n <= 0) { 81 | return 0; 82 | } 83 | int count = 0; 84 | 85 | for (int i = 1; i < n + 1; i++) { 86 | String s = String.valueOf(i); 87 | for (int j = 0; j < s.length(); j++) { 88 | if ('1' == s.charAt(j)) { 89 | count++; 90 | } 91 | } 92 | } 93 | return count; 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/so/NumberOfBin10.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第10题 5 | * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 6 | * 7 | * @author qgl 8 | * @date 2017/08/09 9 | */ 10 | public class NumberOfBin10 { 11 | 12 | /** 13 | * 思路:把一个整数减去1再和原整数与,就会把整数最右边一个1变成0 14 | * 15 | * @param n 16 | * @return 17 | */ 18 | public static int numberOfBin(int n) { 19 | int count = 0; 20 | 21 | while (n != 0) { 22 | count++; 23 | n = (n - 1) & n; 24 | } 25 | return count; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/so/OddEvenNumber14.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第14题 5 | * 输入一个整数数组,实现一个函数来调整数组中的数字的顺序, 6 | * 使得所有奇数位于数组的前半部分,偶数位于后半部分 7 | * 8 | * @author qgl 9 | * @date 2017/08/10 10 | */ 11 | public class OddEvenNumber14 { 12 | 13 | /** 14 | * 解法一:移动偶数位置 15 | * 时间复杂度 O(n²),空间复杂度 O(1) 16 | * 17 | * @param array 18 | */ 19 | public void reOrderArray(int[] array) { 20 | if (array == null || array.length == 0) { 21 | return; 22 | } 23 | 24 | for (int i = 1; i < array.length; i++) { 25 | int j = i - 1; 26 | if (array[i] % 2 != 0) { 27 | while (j >= 0) { 28 | if (array[j] % 2 != 0) { 29 | break; 30 | } 31 | if (array[j] % 2 == 0) { 32 | int t = array[j + 1]; 33 | array[j + 1] = array[j]; 34 | array[j] = t; 35 | j--; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * 解法二:双指针法 44 | * 时间复杂度 O(n),空间复杂度 O(1) 45 | * 46 | * @param array 47 | */ 48 | public void reOrderArray2(int[] array) { 49 | if (array == null || array.length == 0) { 50 | return; 51 | } 52 | 53 | int left = 0; 54 | int right = array.length - 1; 55 | while (left < right) { 56 | while (left < right && array[left] % 2 != 0) { 57 | left++; 58 | } 59 | while (left < right && array[right] % 2 == 0) { 60 | right--; 61 | } 62 | 63 | if (left < right) { 64 | int tmp = array[left]; 65 | array[left] = array[right]; 66 | array[right] = tmp; 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/so/Permutation28.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * 第28题 7 | * 输入一个字符串,打印出字符串中字符的所有排列 8 | * 9 | * @author qgl 10 | * @date 2017/08/14 11 | */ 12 | public class Permutation28 { 13 | 14 | /** 15 | * 解法一:while循环 16 | * 17 | * @param str 18 | * @return 19 | */ 20 | public static String permutation1(String str) { 21 | if (str == null || str.length() == 0) { 22 | return null; 23 | } 24 | StringBuilder sb = new StringBuilder(); 25 | if (str.length() == 1) { 26 | sb.append(str); 27 | return String.valueOf(sb); 28 | } 29 | 30 | char[] output = str.toCharArray(); 31 | int point = 0; 32 | sb.append(output).append(","); 33 | swap(output, point, ++point); 34 | 35 | while (!String.valueOf(output).equals(str)) { 36 | sb.append(output).append(","); 37 | if (point == output.length - 1) { 38 | swap(output, point, 0); 39 | point = 0; 40 | } else { 41 | swap(output, point, ++point); 42 | } 43 | } 44 | 45 | return String.valueOf(sb); 46 | } 47 | 48 | /** 49 | * 解法二:递归 50 | * 51 | * @param str 52 | * @return 53 | */ 54 | public static ArrayList Permutation(String str) { 55 | ArrayList res = new ArrayList<>(); 56 | if (str == null || str.length() == 0) { 57 | return res; 58 | } 59 | helper(res, 0, str.toCharArray()); 60 | // 符合结果的输出顺序 61 | Collections.sort(res); 62 | return res; 63 | 64 | } 65 | 66 | private static void helper(ArrayList res, int index, char[] s) { 67 | if (index == s.length - 1) { 68 | res.add(String.valueOf(s)); 69 | return; 70 | } 71 | 72 | for (int i = index; i < s.length; i++) { 73 | if (i == index || s[index] != s[i]) { 74 | swap(s, index, i); 75 | helper(res, index + 1, s); 76 | swap(s, index, i); 77 | } 78 | } 79 | } 80 | 81 | /** 82 | * 交换两个字符的位置 83 | * 84 | * @param output 85 | * @param i 86 | * @param j 87 | */ 88 | public static void swap(char[] output, int i, int j) { 89 | char temp = output[i]; 90 | output[i] = output[j]; 91 | output[j] = temp; 92 | } 93 | } -------------------------------------------------------------------------------- /src/main/java/com/so/Power11.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第11题 5 | * 求base的exponent次方,不得使用库函数,不需要考虑大数问题 6 | * 7 | * @author qgl 8 | * @date 2017/08/09 9 | */ 10 | public class Power11 { 11 | 12 | /** 13 | * 对输入的数进行条件判断后计算结果 14 | * 15 | * @param base 16 | * @param exponent 17 | * @return 18 | * @throws Exception 19 | */ 20 | public static double power(double base, int exponent) throws Exception { 21 | double result = 0.0; 22 | 23 | if (equal(base, 0.0) && exponent < 0) { 24 | throw new Exception("0的负数次幂无意义"); 25 | } 26 | 27 | if (equal(exponent, 0)) { 28 | return 1.0; 29 | } 30 | 31 | if (exponent < 0) { 32 | result = powerWithExponent(1.0 / base, -exponent); 33 | } else { 34 | result = powerWithExponent(base, exponent); 35 | } 36 | 37 | return result; 38 | } 39 | 40 | /** 41 | * 幂计算 42 | * 43 | * @param base 44 | * @param exponent 45 | * @return 46 | */ 47 | private static double powerWithExponent(double base, int exponent) { 48 | double result = 1.0; 49 | 50 | for (int i = 1; i <= exponent; i++) { 51 | result = result * base; 52 | } 53 | 54 | return result; 55 | } 56 | 57 | /** 58 | * 判断两个double型数值是否相等(有误差) 59 | * 60 | * @param num1 61 | * @param num2 62 | * @return 63 | */ 64 | private static boolean equal(double num1, double num2) { 65 | return (num1 - num2 > -0.0000001) && num1 - num2 < 0.0000001; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/so/PrintFromTopToBottom23.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import com.so.Common.TreeNode; 6 | import java.util.Queue; 7 | 8 | /** 9 | * 第23题 10 | * 层序遍历二叉树 11 | * 12 | * @author qgl 13 | * @date 2017/08/11 14 | */ 15 | public class PrintFromTopToBottom23 { 16 | /** 17 | * 解法一:迭代 18 | * 时间复杂度:O(n),空间复杂度:O(n) 19 | * 20 | * @param root 21 | * @return 22 | */ 23 | public ArrayList PrintFromTopToBottom(TreeNode root) { 24 | ArrayList list = new ArrayList<>(); 25 | if (root == null) { 26 | return list; 27 | } 28 | Queue queue = new LinkedList<>(); 29 | queue.offer(root); 30 | 31 | while (!queue.isEmpty()) { 32 | TreeNode node = queue.poll(); 33 | list.add(node.val); 34 | if (node.left != null) { 35 | queue.offer(node.left); 36 | } 37 | if (node.right != null) { 38 | queue.offer(node.right); 39 | } 40 | } 41 | return list; 42 | } 43 | 44 | /** 45 | * 解法二:递归 46 | * 时间复杂度:O(n),空间复杂度:O(n) 47 | * 48 | * @param root 49 | * @return 50 | */ 51 | public ArrayList PrintFromTopToBottom2(TreeNode root) { 52 | ArrayList list = new ArrayList(); 53 | if (root == null) { 54 | return list; 55 | } 56 | 57 | list.add(root.val); 58 | levelOrder(root, list); 59 | return list; 60 | } 61 | 62 | public void levelOrder(TreeNode root, ArrayList list) { 63 | if (root == null) { 64 | return; 65 | } 66 | 67 | if (root.left != null) { 68 | list.add(root.left.val); 69 | } 70 | if (root.right != null) { 71 | list.add(root.right.val); 72 | } 73 | levelOrder(root.left, list); 74 | levelOrder(root.right, list); 75 | } 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/main/java/com/so/PrintListReversing5.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Stack; 5 | import com.so.Common.ListNode; 6 | 7 | /** 8 | * 第5题 从尾到头打印链表 9 | * 输入一个链表,从尾到头打印链表每个节点的值 10 | * 11 | * @author qgl 12 | * @date 2017/08/08 13 | */ 14 | public class PrintListReversing5 { 15 | 16 | /** 17 | * 解法一:利用栈输出 18 | * @param headNode 19 | */ 20 | public static ArrayList printListReverse1(ListNode headNode) { 21 | ArrayList list = new ArrayList<>(); 22 | Stack stack = new Stack<>(); 23 | while (headNode != null) { 24 | stack.push(headNode); 25 | headNode = headNode.next; 26 | } 27 | 28 | while (!stack.isEmpty()) { 29 | list.add(stack.pop().val); 30 | } 31 | return list; 32 | } 33 | 34 | /** 35 | * 解法二:递归(其实底层还是栈) 36 | * @param headNode 37 | * @return 38 | */ 39 | public static ArrayList printListReverse2(ListNode headNode) { 40 | ArrayList list = new ArrayList(); 41 | 42 | if (headNode != null) { 43 | if (headNode.next != null) { 44 | list = printListReverse2(headNode.next); 45 | } 46 | list.add(headNode.val); 47 | } 48 | return list; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/so/PrintMatrixInCircle20.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 第20题 7 | * 顺时针打印矩阵 8 | * 9 | * @author qgl 10 | * @date 2017/08/10 11 | */ 12 | public class PrintMatrixInCircle20 { 13 | 14 | /** 15 | * 打印矩阵 16 | * @param matrix 17 | * @return 18 | */ 19 | public static ArrayList printMatrix(int[][] matrix) { 20 | ArrayList list = new ArrayList<>(); 21 | if (matrix == null) 22 | return list; 23 | int start = 0; 24 | while (matrix[0].length > start * 2 && matrix.length > start * 2) { 25 | saveOneCircle(matrix, start, list); 26 | start++; 27 | } 28 | return list; 29 | } 30 | 31 | /** 32 | * 记录矩阵的环 33 | * @param matrix 34 | * @param start 35 | * @param list 36 | */ 37 | private static void saveOneCircle(int[][] matrix, int start, ArrayList list) { 38 | int endX = matrix[0].length - 1 - start; // 列 39 | int endY = matrix.length - 1 - start; // 行 40 | // 从左往右 41 | for (int i = start; i <= endX; i++) 42 | list.add(matrix[start][i]); 43 | // 从上往下 44 | if (start < endY) { 45 | for (int i = start + 1; i <= endY; i++) 46 | list.add(matrix[i][endX]); 47 | } 48 | // 从右往左(判断是否会重复打印) 49 | if (start < endX && start < endY) { 50 | for (int i = endX - 1; i >= start; i--) 51 | list.add(matrix[endY][i]); 52 | } 53 | // 从下往上(判断是否会重复打印) 54 | if (start < endX && start < endY - 1) { 55 | for (int i = endY - 1; i >= start + 1; i--) 56 | list.add(matrix[i][start]); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/so/PrintMinNumber33.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Arrays; 4 | import java.util.Comparator; 5 | 6 | /** 7 | * 第33题 8 | * 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印出能拼接出的所有数字中的最小的一个。 9 | * 10 | * @author qgl 11 | * @date 2017/08/14 12 | */ 13 | public class PrintMinNumber33 { 14 | /** 15 | * 解法一:自定义快排 16 | * @param array 17 | * @return 18 | */ 19 | public static String printMinNumber1(int[] array) { 20 | int[] clone = array.clone(); 21 | StringBuilder sb = new StringBuilder(); 22 | printMin(clone, 0, clone.length - 1); 23 | for (int i : clone) { 24 | sb.append(i); 25 | } 26 | return sb.toString(); 27 | } 28 | 29 | /** 30 | * 比较+快排 31 | * @param array 32 | * @param start 33 | * @param end 34 | */ 35 | public static void printMin(int[] array, int start, int end) { 36 | if (start < end) { 37 | int main_number = array[end]; 38 | int small_cur = start; 39 | for (int j = start; j < end; j++) { 40 | // array[j]、main_number的组合较小,就把array[j]换到最前面 41 | if (isSmall(String.valueOf(array[j]), String.valueOf(main_number))) { 42 | int temp = array[j]; 43 | array[j] = array[small_cur]; 44 | array[small_cur] = temp; 45 | small_cur++; 46 | } 47 | } 48 | 49 | array[end] = array[small_cur]; 50 | array[small_cur] = main_number; 51 | printMin(array, 0, small_cur - 1); 52 | printMin(array, small_cur + 1, end); 53 | } 54 | } 55 | 56 | /** 57 | * 比较两个字符的大小(判断m是否比n小) 58 | * @param m 59 | * @param n 60 | * @return 61 | */ 62 | private static boolean isSmall(String m, String n) { 63 | String left = m + n; 64 | String right = n + m; 65 | 66 | for (int i = 0; i < left.length(); i++) { 67 | if (left.charAt(i) < right.charAt(i)) { 68 | return true; 69 | } 70 | if (left.charAt(i) > right.charAt(i)) 71 | return false; 72 | } 73 | return false; 74 | } 75 | 76 | /** 77 | * 解法二:使用JDK的归并排序 78 | * @param numbers 79 | * @return 80 | */ 81 | public static String printMinNumber2(int[] numbers) { 82 | if (numbers == null || numbers.length == 0) 83 | return ""; 84 | int len = numbers.length; 85 | String[] str = new String[len]; 86 | StringBuilder sb = new StringBuilder(); 87 | for (int i = 0; i < len; i++) { 88 | str[i] = String.valueOf(numbers[i]); 89 | } 90 | Arrays.sort(str, new Comparator() { 91 | @Override 92 | public int compare(String s1, String s2) { 93 | String c1 = s1 + s2; 94 | String c2 = s2 + s1; 95 | return c1.compareTo(c2); 96 | } 97 | }); 98 | 99 | for (int i = 0; i < len; i++) { 100 | sb.append(str[i]); 101 | } 102 | return sb.toString(); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/so/PrintToMaxOfNDigits12.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第12题 5 | * 打印1到最大的n位数 6 | * 7 | * @author qgl 8 | * @date 2017/08/09 9 | */ 10 | public class PrintToMaxOfNDigits12 { 11 | 12 | /** 13 | * 创建数组并校验输入值 14 | * 15 | * @param n 16 | */ 17 | public static void printToMaxOfNDigits(int n) { 18 | int[] array = new int[n]; 19 | if (n <= 0) 20 | return; 21 | printArray(array, 0); 22 | } 23 | 24 | /** 25 | * 输出数值 26 | * 27 | * @param array 28 | * @param n 29 | */ 30 | private static void printArray(int[] array, int n) { 31 | for (int i = 0; i < 10; i++) { 32 | if (n != array.length) { 33 | array[n] = i; 34 | printArray(array, n + 1); 35 | } else { 36 | boolean isFirstNo0 = false; 37 | for (int j = 0; j < array.length; j++) { 38 | if (array[j] != 0) { 39 | System.out.print(array[j]); 40 | if (!isFirstNo0) 41 | isFirstNo0 = true; 42 | } else { 43 | if (isFirstNo0) 44 | System.out.print(array[j]); 45 | } 46 | } 47 | System.out.println(); 48 | return; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/so/RegularMatch53.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第53题 5 | * 正则表达式匹配字符串,实现一个函数用来匹配包括'.'和'*'的正则表达式 6 | * 其中'*'表示它前面的字符可以出现任意次(包含0次) 7 | * 8 | * @author qgl 9 | * @date 2017/08/29 10 | */ 11 | public class RegularMatch53 { 12 | 13 | /** 14 | * 是否匹配 15 | * @param str 16 | * @param pattern 17 | * @return 18 | */ 19 | public static boolean match(char[] str, char[] pattern) { 20 | if (str == null || pattern == null) { 21 | return false; 22 | } 23 | // 若字符串的长度为1 24 | if (str.length == 1 && pattern.length == 1) { 25 | return str[0] == pattern[0] || pattern[0] == '.'; 26 | } 27 | 28 | return matchIndex(str,0,pattern,0); 29 | } 30 | 31 | public static boolean matchIndex(char[] str,int sIndex, char[] pattern, int pIndex) { 32 | // str和pattern同时到达末尾,则匹配成功 33 | if (sIndex == str.length && pIndex == pattern.length) 34 | return true; 35 | // 若pattern先到尾,而str没有到达末尾,则匹配失败 36 | if (sIndex != str.length && pIndex == pattern.length) 37 | return false; 38 | // 若pattern第二个字符是* 39 | if (pIndex + 1 < pattern.length && pattern[pIndex + 1] == '*') { 40 | if (sIndex != str.length && pattern[pIndex] == str[sIndex] || 41 | sIndex != str.length && pattern[pIndex] == '.') { 42 | return matchIndex(str,sIndex+1,pattern,pIndex+2) 43 | || matchIndex(str,sIndex,pattern,pIndex+2) 44 | || matchIndex(str,sIndex+1,pattern,pIndex); 45 | } else { 46 | return matchIndex(str,sIndex,pattern,pIndex+2); 47 | } 48 | } 49 | // 若pattern第二个字符不是* 50 | if (sIndex != str.length && pattern[pIndex] == str[sIndex] || 51 | sIndex != str.length && pattern[pIndex] == '.') 52 | return matchIndex(str,sIndex+1,pattern,pIndex+1); 53 | return false; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/so/ReplaceBlank4.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第4题 5 | * 将一个字符串中的空格替换成"%20" 6 | * 7 | * @author qgl 8 | * @date 2017/08/07 9 | */ 10 | public class ReplaceBlank4 { 11 | 12 | /** 13 | * 解法一:使用StringBuffer 14 | * 15 | * @param input 16 | * @return 17 | */ 18 | public static String replaceBlank1(String input) { 19 | if (input == null) { 20 | return null; 21 | } 22 | StringBuffer outputBuffer = new StringBuffer(); 23 | 24 | for (int i = 0; i < input.length(); i++) { 25 | if (input.charAt(i) == ' ') { 26 | outputBuffer.append("%20"); 27 | } else { 28 | outputBuffer.append(String.valueOf(input.charAt(i))); 29 | } 30 | } 31 | return new String(outputBuffer); 32 | } 33 | 34 | /** 35 | * 解法二:使用StringBuilder 36 | * 37 | * @param input 38 | * @return 39 | */ 40 | public static String replaceBlank2(String input) { 41 | if (input == null) { 42 | return null; 43 | } 44 | StringBuilder sb = new StringBuilder(); 45 | 46 | for (int i = 0; i < input.length(); i++) { 47 | if (String.valueOf(input.charAt(i)).equals(" ")) { 48 | sb.append("%20"); 49 | } else { 50 | sb.append(input.charAt(i)); 51 | } 52 | } 53 | return String.valueOf(sb); 54 | } 55 | 56 | /** 57 | * 解法三:从后往前复制 58 | * 59 | * @param input 60 | * @return 61 | */ 62 | public static String replaceBlank3(String input) { 63 | if (input == null) { 64 | return null; 65 | } 66 | int blankNum = 0; 67 | int length = input.length(); 68 | int newLength = 0; 69 | for (int i = 0; i < length; i++) { 70 | if (input.charAt(i) == ' ') { 71 | blankNum++; 72 | } 73 | } 74 | // 替换后的字符串长度 75 | newLength = length + 2 * blankNum; 76 | char[] newChars = new char[newLength]; 77 | int index = newLength - 1; 78 | for (int i = length - 1; i >= 0; i--) { 79 | if (input.charAt(i) == ' ') { 80 | newChars[index--] = '0'; 81 | newChars[index--] = '2'; 82 | newChars[index--] = '%'; 83 | } else { 84 | newChars[index--] = input.charAt(i); 85 | } 86 | } 87 | return new String(newChars); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/so/ReverseList16.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.ListNode; 4 | 5 | /** 6 | * 第16题 反转链表 7 | * 输入一个链表的头结点,反转该链表并输出翻转后的头结点 8 | * 9 | * @author qgl 10 | * @date 2017/08/10 11 | */ 12 | public class ReverseList16 { 13 | /** 14 | * 解法一:迭代:两个指针,反向输出 15 | * 时间复杂度:O(n),空间复杂度:O(1) 16 | * 17 | * @param head 18 | * @return 19 | */ 20 | public static ListNode reverseList1(ListNode head) { 21 | ListNode pre = null; 22 | ListNode curr = head; 23 | 24 | while (curr != null) { 25 | ListNode tmp = curr.next; 26 | curr.next = pre; 27 | pre = curr; 28 | curr = tmp; 29 | } 30 | return pre; 31 | } 32 | 33 | /** 34 | * 解法二:迭代:单指针依次往后移动,改变原节点间的指向 35 | * 时间复杂度:O(n),空间复杂度:O(1) 36 | * 37 | * @param head 38 | * @return 39 | */ 40 | public static ListNode reverseList2(ListNode head) { 41 | ListNode pre = null; 42 | 43 | while (head != null) { 44 | ListNode p = head.next; 45 | head.next = pre; 46 | pre = head; 47 | head = p; 48 | } 49 | return pre; 50 | } 51 | 52 | /** 53 | * 解法三:递归 54 | * 时间复杂度:O(n),空间复杂度:O(n) 55 | * 56 | * @param head 57 | * @return 58 | */ 59 | public static ListNode reverseList3(ListNode head) { 60 | if (head == null || head.next == null) { 61 | return head; 62 | } 63 | 64 | ListNode p = reverseList3(head.next); 65 | head.next.next = head.next; 66 | head.next = null; 67 | return p; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/so/ReverseSentence42.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第42题 5 | * 输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变 6 | * 7 | * @author qgl 8 | * @date 2017/08/16 9 | */ 10 | public class ReverseSentence42 { 11 | /** 12 | * 翻转字符串内的单词顺序 13 | * 14 | * @param sentence 15 | * @return 16 | */ 17 | public static String reverseSentence(String sentence) { 18 | if (sentence == null || sentence.length() == 0 || sentence.trim().length() == 0) { 19 | return sentence; 20 | } 21 | String blank = " "; 22 | String sentenceReverse = reverse(sentence); 23 | String[] splitStrings = sentenceReverse.split(blank); 24 | StringBuilder sb = new StringBuilder(); 25 | 26 | for (int i = 0; i < splitStrings.length - 1; i++) { 27 | sb.append(reverse(splitStrings[i])).append(blank); 28 | } 29 | sb.append(reverse(splitStrings[splitStrings.length - 1])); 30 | return String.valueOf(sb); 31 | } 32 | 33 | /** 34 | * 翻转字符串 35 | * 36 | * @param str 37 | * @return 38 | */ 39 | public static String reverse(String str) { 40 | StringBuilder sb = new StringBuilder(); 41 | for (int i = str.length() - 1; i >= 0; i--) { 42 | sb.append(str.substring(i, i + 1)); 43 | } 44 | return String.valueOf(sb); 45 | } 46 | 47 | /** 48 | * 字符串的左旋 49 | * 50 | * @param sentence abcdefg 51 | * @param index 2 52 | * @return cdefgab 53 | */ 54 | public static String leftRotateString(String sentence, int index) { 55 | if (sentence == null || index > sentence.length() || index < 0) { 56 | return null; 57 | } 58 | String sentenceReverse = reverse(sentence); 59 | String[] splitStrings = {sentenceReverse.substring(0, sentence.length() - index), 60 | sentenceReverse.substring(sentence.length() - index, sentence.length())}; 61 | StringBuilder sb = new StringBuilder(); 62 | for (String s : splitStrings) { 63 | sb.append(reverse(s)); 64 | } 65 | return String.valueOf(sb); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/so/Serializer62.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.TreeNode; 4 | 5 | /** 6 | * 第62题 7 | * 二叉树的序列化与反序列化 8 | * 9 | * @author qgl 10 | * @date 2017/08/30 11 | */ 12 | public class Serializer62 { 13 | 14 | /** 15 | * 序列化二叉树 (前序遍历) 16 | * 17 | * @param root 18 | * @return 19 | */ 20 | public static String serialize(TreeNode root) { 21 | StringBuffer sb = new StringBuffer(); 22 | if (root == null) { 23 | sb.append("#,"); 24 | return sb.toString(); 25 | } 26 | 27 | sb.append(root.val + ","); 28 | sb.append(serialize(root.left)); 29 | sb.append(serialize(root.right)); 30 | return sb.toString(); 31 | } 32 | 33 | private static int index = -1; 34 | 35 | /** 36 | * 反序列化二叉树 37 | * 38 | * @param str 39 | * @return 40 | */ 41 | public static TreeNode deserialize(String str) { 42 | index++; 43 | int len = str.length(); 44 | String[] strArray = str.split(","); 45 | TreeNode node = null; 46 | 47 | if (index >= len) { 48 | return null; 49 | } 50 | 51 | if (!strArray[index].equals("#")) { 52 | node = new TreeNode(Integer.valueOf(strArray[index])); 53 | node.left = deserialize(str); 54 | node.right = deserialize(str); 55 | } 56 | return node; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/so/SingletonPattern2.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第2题 单例设计模式 5 | * 设计一个类,只能生成该类的一个实例。 6 | * 7 | * @author qgl 8 | * @date 2019/06/21 9 | */ 10 | public class SingletonPattern2 {} 11 | 12 | /** 13 | * 1.饿汉式:线程安全,耗费资源 14 | */ 15 | class HugerSingleton1 { 16 | //该对象的引用不可修改 17 | private static final HugerSingleton1 ourInstance = new HugerSingleton1(); 18 | public static HugerSingleton1 getInstance() { 19 | return ourInstance; 20 | } 21 | private HugerSingleton1() {} 22 | } 23 | 24 | /** 25 | * 2.饿汉式:在静态代码块实例对象 26 | */ 27 | class HugerSingleton2 { 28 | private static HugerSingleton2 ourInstance; 29 | static { 30 | ourInstance = new HugerSingleton2(); 31 | } 32 | public static HugerSingleton2 getInstance() { 33 | return ourInstance; 34 | } 35 | private HugerSingleton2() {} 36 | } 37 | 38 | /** 39 | * 3.懒汉式:非线程安全 40 | */ 41 | class Singleton1 { 42 | private static Singleton1 ourInstance; 43 | public static Singleton1 getInstance() { 44 | if (null == ourInstance) { 45 | ourInstance = new Singleton1(); 46 | } 47 | return ourInstance; 48 | } 49 | private Singleton1() {} 50 | } 51 | 52 | /** 53 | * 4.线程安全的懒汉式:给方法加锁 54 | */ 55 | class Singleton2 { 56 | private static Singleton2 ourInstance; 57 | public synchronized static Singleton2 getInstance() { 58 | if (null == ourInstance) { 59 | ourInstance = new Singleton2(); 60 | } 61 | return ourInstance; 62 | } 63 | private Singleton2() {} 64 | } 65 | 66 | /** 67 | * 5.线程安全的懒汉式:双重检查锁(同步代码块) 68 | */ 69 | class Singleton3 { 70 | private static Singleton3 ourInstance; 71 | public static Singleton3 getInstance() { 72 | if (null == ourInstance) { 73 | synchronized (Singleton3.class) { 74 | if (null == ourInstance) { 75 | ourInstance = new Singleton3(); 76 | } 77 | } 78 | } 79 | return ourInstance; 80 | } 81 | private Singleton3() {} 82 | } 83 | 84 | /** 85 | * 6.线程安全的懒汉式:静态内部类(推荐) 86 | */ 87 | class Singleton4 { 88 | private static class SingletonHolder { 89 | private static Singleton4 ourInstance = new Singleton4(); 90 | } 91 | public static Singleton4 getInstance() { 92 | return SingletonHolder.ourInstance; 93 | } 94 | private Singleton4() { 95 | } 96 | } 97 | 98 | /** 99 | * 7.线程安全的懒汉式:枚举 100 | */ 101 | enum Singleton5 { 102 | INSTANCE; 103 | public void whateverMethod() { 104 | // do something 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/so/StackWithMin21.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * 第21题 7 | * 定义一个栈,在该类型中实现一个能够得到栈的最小元素的Min函数。 8 | * 9 | * @author qgl 10 | * @date 2017/08/10 11 | */ 12 | public class StackWithMin21 { 13 | 14 | /** 15 | * 解法一:栈使用JDK的 Stack 16 | */ 17 | static Stack stack1 = new Stack<>(); 18 | static Stack stack2 = new Stack<>(); 19 | 20 | public static void push(int node) { 21 | stack1.push(node); 22 | if (stack2.isEmpty()) { 23 | stack2.push(node); 24 | } else { 25 | if (stack2.peek() > node) { 26 | stack2.push(node); 27 | } 28 | } 29 | } 30 | 31 | public static void pop() { 32 | if (stack1.pop() == stack2.peek()) { 33 | stack2.pop(); 34 | } 35 | } 36 | 37 | public static int top() { 38 | return stack1.peek(); 39 | } 40 | 41 | public static int min() { 42 | return stack2.peek(); 43 | } 44 | 45 | /** 46 | * 解法二:栈使用自定义的 MyStack 47 | */ 48 | private static MyStack minStack = new MyStack<>(); 49 | private static MyStack dataStack = new MyStack<>(); 50 | 51 | public static void push2(Integer item) { 52 | dataStack.push(item); 53 | if (minStack.length == 0 || item <= minStack.head.data) { 54 | minStack.push(item); 55 | } else { 56 | minStack.push(minStack.head.data); 57 | } 58 | } 59 | 60 | public static Integer pop2() { 61 | if (dataStack.length == 0 || minStack.length == 0) 62 | return null; 63 | minStack.pop(); 64 | return dataStack.pop(); 65 | } 66 | 67 | public static Integer min2() { 68 | if (minStack.length == 0) 69 | return null; 70 | return minStack.head.data; 71 | } 72 | 73 | static class MyStack { 74 | public ListNode head; 75 | public int length; 76 | 77 | public void push(K item) { 78 | ListNode node = new ListNode(); 79 | node.data = item; 80 | node.nextNode = head; 81 | head = node; 82 | length++; 83 | } 84 | 85 | public K pop() { 86 | if (head == null) 87 | return null; 88 | ListNode temp = head; 89 | head = head.nextNode; 90 | length--; 91 | return temp.data; 92 | 93 | } 94 | } 95 | 96 | static class ListNode { 97 | K data; 98 | ListNode nextNode; 99 | } 100 | 101 | } 102 | 103 | -------------------------------------------------------------------------------- /src/main/java/com/so/StrToInt49.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第49题 5 | * 输入一个字符串,包括数字字母符号,可以为空,如果是合法的数值表达则返回该数字,否则返回0 6 | * 7 | * @author qgl 8 | * @date 2017/08/29 9 | */ 10 | public class StrToInt49 { 11 | 12 | /** 13 | * 将字符串转换为整数 14 | * @param str 15 | * @return 16 | */ 17 | public static int StrToInt(String str) { 18 | if (str == null || str.length() == 0) { 19 | return 0; 20 | } 21 | int mark = 0; 22 | int number = 0; 23 | char[] chars = str.toCharArray(); 24 | 25 | if (chars[0] == '-') { 26 | mark = 1; 27 | } 28 | 29 | for (int i = mark; i < chars.length; i++) { 30 | if (chars[i] == '+') { 31 | continue; 32 | } 33 | 34 | if (chars[i] < 48 || chars[i] > 57) { 35 | return 0; 36 | } 37 | 38 | number = number * 10 + chars[i] - 48; 39 | } 40 | return mark == 0 ? number : -number; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/so/TreePath39.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第39题 5 | * 输入根节点求树的深度 6 | * 7 | * @author qgl 8 | * @date 2017/08/15 9 | */ 10 | public class TreePath39 { 11 | static class BinaryTreeNode { 12 | int data; 13 | BinaryTreeNode leftNode; 14 | BinaryTreeNode rightNode; 15 | } 16 | 17 | /** 18 | * 获取树的深度 19 | * 20 | * @param root 21 | * @return 22 | */ 23 | public static int treePath(BinaryTreeNode root) { 24 | if (root == null) { 25 | return 0; 26 | } 27 | int left = treePath(root.leftNode); 28 | int right = treePath(root.rightNode); 29 | return left > right ? (left + 1) : (right + 1); 30 | } 31 | 32 | /** 33 | * 判断输入的二叉树是不是平衡二叉树 34 | * (如果二叉树任意节点的左右子树深度相差不超过1,就是平衡的) 35 | * 36 | * @param root 37 | * @return 38 | */ 39 | public static boolean isBalanced(BinaryTreeNode root) { 40 | if (root == null) { 41 | return true; 42 | } 43 | int left = treePath(root.leftNode); 44 | int right = treePath(root.rightNode); 45 | return Math.abs(left - right) <= 1; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/so/UglyNumber34.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | /** 4 | * 第34题 5 | * 求从小到大的第1500个丑数(只包含因子2,3,5的数为丑数,1是第一个丑数) 6 | * 7 | * @author qgl 8 | * @date 2017/08/15 9 | */ 10 | public class UglyNumber34 { 11 | 12 | /** 13 | * 获取第n个丑数 14 | * 15 | * @param n 16 | * @return 17 | */ 18 | public static int getUglyNumber(int n) { 19 | if (n <= 0) { 20 | return 0; 21 | } 22 | int[] arr = new int[n]; 23 | arr[0] = 1; 24 | int multiply2 = 0; 25 | int multiply3 = 0; 26 | int multiply5 = 0; 27 | 28 | for (int i = 1; i < n; i++) { 29 | int min = Math.min(arr[multiply2] * 2, Math.min(arr[multiply3] * 3, arr[multiply5] * 5)); 30 | arr[i] = min; 31 | if (arr[multiply2] * 2 == min) { 32 | multiply2++; 33 | } 34 | if (arr[multiply3] * 3 == min) { 35 | multiply3++; 36 | } 37 | if (arr[multiply5] * 5 == min) { 38 | multiply5++; 39 | } 40 | } 41 | return arr[n - 1]; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/so/VerifySequenceOfBST24.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 第24题 7 | * 输入一个数组,判断数组是不是二叉搜索树的后序遍历结果 8 | * 9 | * @author qgl 10 | * @date 2017/08/11 11 | */ 12 | public class VerifySequenceOfBST24 { 13 | 14 | /** 15 | * 判断输入的数组是否是二叉搜索树的后序遍历结果 16 | * @param sequence 17 | * @return 18 | */ 19 | public static boolean VerifySquenceOfBST(int[] sequence) { 20 | if (sequence == null || sequence.length == 0) { 21 | return false; 22 | } 23 | 24 | int rstart = 0; 25 | int rootIndex = sequence.length - 1; 26 | for (int i = 0; i < rootIndex; i++) { 27 | if (sequence[i] < sequence[rootIndex]) 28 | rstart++; 29 | } 30 | 31 | if (rstart == 0) { 32 | VerifySquenceOfBST(Arrays.copyOfRange(sequence,0,rootIndex)); 33 | return true; 34 | } 35 | 36 | for (int i = rstart; i < rootIndex; i++) { 37 | if (sequence[i] <= sequence[rootIndex]) { 38 | return false; 39 | } 40 | } 41 | VerifySquenceOfBST(Arrays.copyOfRange(sequence,0,rstart)); 42 | VerifySquenceOfBST(Arrays.copyOfRange(sequence,rstart,rootIndex)); 43 | return true; 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/main/java/com/so/ZTreePrint60.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import java.util.*; 4 | 5 | import com.so.Common.TreeNode; 6 | 7 | /** 8 | * 第60题 9 | * 之字形打印二叉树 10 | * 11 | * @author qgl 12 | * @date 2017/08/30 13 | */ 14 | public class ZTreePrint60 { 15 | /** 16 | * 解法一:迭代 17 | * 18 | * @param root 19 | * @return 20 | */ 21 | public static List> Print(TreeNode root) { 22 | List> res = new ArrayList<>(); 23 | if (root == null) { 24 | return res; 25 | } 26 | Queue queue = new LinkedList<>(); 27 | queue.add(root); 28 | int depth = 0; 29 | while (!queue.isEmpty()) { 30 | LinkedList tmp = new LinkedList<>(); 31 | int size = queue.size(); 32 | for (int i = 0; i < size; i++) { 33 | TreeNode node = queue.poll(); 34 | if (depth % 2 == 0) { 35 | tmp.add(node.val); 36 | } else { 37 | tmp.addFirst(node.val); 38 | } 39 | if (node.left != null) { 40 | queue.add(node.left); 41 | } 42 | if (node.right != null) { 43 | queue.add(node.right); 44 | } 45 | } 46 | res.add(tmp); 47 | depth++; 48 | } 49 | return res; 50 | } 51 | 52 | /** 53 | * 解法二:递归 54 | * 55 | * @param root 56 | * @return 57 | */ 58 | public List> zigzagLevelOrder(TreeNode root) { 59 | List> res = new ArrayList<>(); 60 | helper(res, root, 0); 61 | return res; 62 | 63 | } 64 | 65 | private void helper(List> res, TreeNode root, int depth) { 66 | if (root == null) { 67 | return; 68 | } 69 | if (res.size() == depth) { 70 | res.add(new LinkedList<>()); 71 | } 72 | if (depth % 2 == 0) { 73 | res.get(depth).add(root.val); 74 | } else { 75 | res.get(depth).add(0, root.val); 76 | } 77 | helper(res, root.left, depth + 1); 78 | helper(res, root.right, depth + 1); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test10.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第10题 7 | * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 8 | * 9 | * @author qgl 10 | * @date 2019/02/24 11 | */ 12 | public class Test10 { 13 | @Test 14 | public void test10() throws Exception { 15 | int number = 7; 16 | System.out.println(number + " 的二进制表示中1的个数:" + NumberOfBin10.numberOfBin(number)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test11.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第11题 7 | * 求base的exponent次方,不得使用库函数,不需要考虑大数问题 8 | * 9 | * @author qgl 10 | * @date 2019/02/25 11 | */ 12 | public class Test11 { 13 | @Test 14 | public void test11() throws Exception { 15 | double base = 2.0; 16 | int exponent = 10; 17 | System.out.println(base + "^" + exponent + " = " + Power11.power(base, exponent)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test12.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第12题 7 | * 打印1到最大的n位数 8 | * 9 | * @author qgl 10 | * @date 2019/02/26 11 | */ 12 | public class Test12 { 13 | @Test 14 | public void test12() throws Exception { 15 | int n = 3; 16 | PrintToMaxOfNDigits12.printToMaxOfNDigits(n); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test13.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第13题 7 | * 给定单向链表的头指针和一个节点,在O(1)时间删除该节点。 8 | * 9 | * @author qgl 10 | * @date 2019/02/27 11 | */ 12 | public class Test13 { 13 | @Test 14 | public void test13() throws Exception { 15 | DeleteNode13.ListNode head = new DeleteNode13.ListNode(); 16 | DeleteNode13.ListNode second = new DeleteNode13.ListNode(); 17 | DeleteNode13.ListNode third = new DeleteNode13.ListNode(); 18 | head.nextNode = second; 19 | second.nextNode = third; 20 | head.data = 1; 21 | second.data = 2; 22 | third.data = 3; 23 | 24 | // 删除链表第二个节点 25 | DeleteNode13.deleteNode(head, second); 26 | 27 | // 输出链表的值 28 | printListNode(head); 29 | } 30 | 31 | /** 32 | * 输出链表的所有值 33 | * @param head 34 | */ 35 | public void printListNode(DeleteNode13.ListNode head) { 36 | DeleteNode13.ListNode tmp = head; 37 | while (tmp != null) { 38 | System.out.println(tmp.data); 39 | tmp = tmp.nextNode; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test14.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 第14题 9 | * 输入一个整数数组,实现一个函数来调整数组中的数字的顺序, 10 | * 使得所有奇数位于数组的前半部分,偶数位于后半部分 11 | * 12 | * @author qgl 13 | * @date 2019/02/28 14 | */ 15 | public class Test14 { 16 | @Test 17 | public void test14() throws Exception { 18 | OddEvenNumber14 oddEvenNumber14 = new OddEvenNumber14(); 19 | int[] array = {1, 2, 3, 4, 5, 6, 7, 8}; 20 | oddEvenNumber14.reOrderArray(array); 21 | System.out.println("解法一:移动偶数位置 " + Arrays.toString(array)); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test15.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.ListNode; 5 | 6 | /** 7 | * 第15题 8 | * 输入一个链表,输出该链表的倒数第K个结点 9 | * 10 | * @author qgl 11 | * @date 2019/03/01 12 | */ 13 | public class Test15 { 14 | @Test 15 | public void test15() throws Exception { 16 | ListNode head = new ListNode(1); 17 | ListNode second = new ListNode(2); 18 | ListNode third = new ListNode(3); 19 | ListNode forth = new ListNode(4); 20 | head.next = second; 21 | second.next = third; 22 | third.next = forth; 23 | 24 | ListNode kthToTail = FindKthToTail15.findKthToTail(head, 5); 25 | System.out.println("解法一:" + Common.getAllListNode(kthToTail)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test16.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.ListNode; 5 | 6 | /** 7 | * 第16题 反转链表 8 | * 输入一个链表的头结点,反转该链表并输出翻转后的头结点 9 | * 10 | * @author qgl 11 | * @date 2019/03/02 12 | */ 13 | public class Test16 { 14 | @Test 15 | public void test16() throws Exception { 16 | ListNode head = new ListNode(1); 17 | ListNode second = new ListNode(2); 18 | ListNode third = new ListNode(3); 19 | ListNode forth = new ListNode(4); 20 | head.next = second; 21 | second.next = third; 22 | third.next = forth; 23 | 24 | ListNode listNode = ReverseList16.reverseList1(head); 25 | System.out.println("解法一:" + Common.getAllListNode(listNode)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test17.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.ListNode; 5 | 6 | /** 7 | * 第17题 8 | * 输入两个递增的链表,合并这两个链表并使新链表仍然是递增的 9 | * 10 | * @author qgl 11 | * @date 2019/03/03 12 | */ 13 | public class Test17 { 14 | @Test 15 | public void test17() throws Exception { 16 | ListNode head = new ListNode(1); 17 | ListNode second = new ListNode(3); 18 | ListNode third = new ListNode(5); 19 | ListNode forth = new ListNode(7); 20 | head.next = second; 21 | second.next = third; 22 | third.next = forth; 23 | 24 | ListNode head2 = new ListNode(2); 25 | ListNode second2 = new ListNode(4); 26 | ListNode third2= new ListNode(6); 27 | ListNode forth2 = new ListNode(8); 28 | head2.next = second2; 29 | second2.next = third2; 30 | third2.next = forth2; 31 | 32 | ListNode listNode = MergeLinked17.mergeTwoLists(head, head2); 33 | System.out.println("解法一:" + Common.getAllListNode(listNode)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test18.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.TreeNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * 第18题 8 | * 判断二叉树A中是否包含子树B 9 | * 10 | * @author qgl 11 | * @date 2019/03/04 12 | */ 13 | public class Test18 { 14 | @Test 15 | public void test18() throws Exception { 16 | TreeNode root1 = new TreeNode(3); 17 | TreeNode node1 = new TreeNode(4); 18 | TreeNode node2 = new TreeNode(5); 19 | TreeNode node3 = new TreeNode(1); 20 | TreeNode node4 = new TreeNode(2); 21 | TreeNode node5 = new TreeNode(0); 22 | TreeNode node6 = new TreeNode(0); 23 | root1.left = node1; 24 | root1.right = node2; 25 | node1.left = node3; 26 | node1.right = node4; 27 | node4.left = node5; 28 | node4.right = node6; 29 | 30 | TreeNode root2 = new TreeNode(4); 31 | TreeNode a = new TreeNode(1); 32 | TreeNode b = new TreeNode(2); 33 | root2.left = a; 34 | root2.right = b; 35 | 36 | System.out.println("是否包含 " + DoesTreeHave18.hasSubTree(root1, root2)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test19.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第19题 8 | * 输入一个二叉树,输出它的镜像 9 | * 10 | * @author qgl 11 | * @date 2019/03/05 12 | */ 13 | public class Test19 { 14 | @Test 15 | public void test19() throws Exception { 16 | TreeNode root = new TreeNode(8); 17 | TreeNode node1 = new TreeNode(5); 18 | TreeNode node2 = new TreeNode(7); 19 | TreeNode node3 = new TreeNode(9); 20 | TreeNode node4 = new TreeNode(2); 21 | TreeNode node5 = new TreeNode(4); 22 | TreeNode node6 = new TreeNode(1); 23 | root.left = node1; 24 | root.right = node2; 25 | node1.left = node3; 26 | node1.right = node4; 27 | node4.left = node5; 28 | node4.right = node6; 29 | /* 30 | 原二叉树 二叉树的镜像 31 | 8 8 32 | / \ / \ 33 | 5 7 7 5 34 | / \ / \ 35 | 9 2 2 9 36 | / \ / \ 37 | 4 1 1 4 38 | */ 39 | 40 | System.out.println("原二叉树的根节点的右子树 = " + root.right.val); 41 | MirrorRecursively19 mirror = new MirrorRecursively19(); 42 | mirror.Mirror(root); 43 | System.out.println("解法一:递归,二叉树的镜像 根节点的右子树 = " + root.right.val); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test2.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第2题 单例设计模式 7 | * 设计一个类,只能生成该类的一个实例。 8 | * 9 | * @author qgl 10 | * @date 2019/06/22 11 | */ 12 | public class Test2 { 13 | @Test 14 | public void test2() { 15 | Singleton1 singleton = Singleton1.getInstance(); 16 | Singleton1 singleton2 = Singleton1.getInstance(); 17 | System.out.println("使用单例模式获取对象,是否是同一个实例:" + singleton.equals(singleton2)); 18 | // Singleton1 singleton3 = new Singleton1(); 19 | // System.out.println("使用new创建对象,是否是同一个实例:" + singleton.equals(singleton3)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test20.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第20题 7 | * 顺时针打印矩阵 8 | * 9 | * @author qgl 10 | * @date 2019/03/06 11 | */ 12 | public class Test20 { 13 | @Test 14 | public void test20() throws Exception { 15 | int[][] array = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}}; 16 | System.out.println("顺时针输出矩阵:" + PrintMatrixInCircle20.printMatrix(array)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test21.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第21题 7 | * 定义一个栈,在该类型中实现一个能够得到栈的最小元素的Min函数。 8 | * 9 | * @author qgl 10 | * @date 2019/03/07 11 | */ 12 | public class Test21 { 13 | @Test 14 | public void test21() throws Exception { 15 | StackWithMin21.push(3); 16 | StackWithMin21.push(1); 17 | StackWithMin21.push(4); 18 | StackWithMin21.push(9); 19 | System.out.println("解法一,使用JDK的 Stack 栈,最小值:" + StackWithMin21.min()); 20 | 21 | StackWithMin21.push2(3); 22 | StackWithMin21.push2(1); 23 | StackWithMin21.push2(4); 24 | StackWithMin21.push2(9); 25 | System.out.println("解法二,自定义的 MyStack 栈,最小值:" + StackWithMin21.min2()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test22.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第22题 7 | * 输入两个整数序列,第一个序列表示压入顺序,判断第二个序列是否为弹出顺序 8 | * 9 | * @author qgl 10 | * @date 2019/03/08 11 | */ 12 | public class Test22 { 13 | @Test 14 | public void test22() throws Exception { 15 | int[] pushList = {1, 2, 3, 4, 5}; 16 | int[] popList = {4, 3, 5, 2, 1}; 17 | 18 | System.out.println("是否是弹出顺序:" + IsPopOrder22.isPopOrder(pushList, popList)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test23.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第23题 8 | * 层序遍历二叉树 9 | * 10 | * @author qgl 11 | * @date 2019/03/09 12 | */ 13 | public class Test23 { 14 | @Test 15 | public void test23() throws Exception { 16 | TreeNode root = new TreeNode(8); 17 | TreeNode node1 = new TreeNode(9); 18 | TreeNode node2 = new TreeNode(7); 19 | TreeNode node3 = new TreeNode(10); 20 | TreeNode node4 = new TreeNode(2); 21 | TreeNode node5 = new TreeNode(4); 22 | TreeNode node6 = new TreeNode(1); 23 | root.left = node1; 24 | root.right = node2; 25 | node1.left = node3; 26 | node1.right = node4; 27 | node4.left = node5; 28 | node4.right = node6; 29 | 30 | /* 31 | 原二叉树 32 | 8 33 | / \ 34 | 9 7 35 | / \ 36 | 10 2 37 | / \ 38 | 4 1 39 | */ 40 | 41 | PrintFromTopToBottom23 printFromTopToBottom23 = new PrintFromTopToBottom23(); 42 | System.out.print("层序输出的二叉树:" + printFromTopToBottom23.PrintFromTopToBottom(root)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test24.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第24题 7 | * 输入一个数组,判断数组是不是二叉搜索树的后序遍历结果 8 | * 9 | * @author qgl 10 | * @date 2019/03/10 11 | */ 12 | public class Test24 { 13 | @Test 14 | public void test24() throws Exception { 15 | int[] array = {4, 8, 6, 12, 16, 14, 10}; 16 | System.out.println("结果:" + VerifySequenceOfBST24.VerifySquenceOfBST(array)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test25.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第25题 8 | * 输入一个二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径 9 | * 10 | * @author qgl 11 | * @date 2019/03/11 12 | */ 13 | public class Test25 { 14 | @Test 15 | public void test25() throws Exception { 16 | TreeNode root = new TreeNode(8); 17 | TreeNode node1 = new TreeNode(9); 18 | TreeNode node2 = new TreeNode(7); 19 | TreeNode node3 = new TreeNode(10); 20 | TreeNode node4 = new TreeNode(2); 21 | TreeNode node5 = new TreeNode(4); 22 | TreeNode node6 = new TreeNode(1); 23 | root.left = node1; 24 | root.right = node2; 25 | node1.left = node3; 26 | node1.right = node4; 27 | node4.left = node5; 28 | node4.right = node6; 29 | 30 | FindPath25 findPath25 = new FindPath25(); 31 | System.out.println("所有路径:" + findPath25.FindPath(root, 20)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test26.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第26题 7 | * 复制一个复杂链表 8 | * 9 | * @author qgl 10 | * @date 2019/03/12 11 | */ 12 | public class Test26 { 13 | @Test 14 | public void test26() throws Exception { 15 | CloneCLinkedList26.RandomListNode root = new CloneCLinkedList26.RandomListNode(1); 16 | CloneCLinkedList26.RandomListNode node1 = new CloneCLinkedList26.RandomListNode(2); 17 | CloneCLinkedList26.RandomListNode node2 = new CloneCLinkedList26.RandomListNode(3); 18 | CloneCLinkedList26.RandomListNode node3 = new CloneCLinkedList26.RandomListNode(4); 19 | CloneCLinkedList26.RandomListNode node4 = new CloneCLinkedList26.RandomListNode(5); 20 | node1.next = node2; 21 | node2.next = node3; 22 | node3.next = node4; 23 | root.random = node1; 24 | node1.random = root; 25 | node3.random = node1; 26 | 27 | System.out.println("解法一:" + CloneCLinkedList26.Clone1(root).label); 28 | System.out.println("解法二:" + CloneCLinkedList26.Clone2(root).label); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test27.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第27题 7 | * 将二叉搜索树转换成一个排序的双向链表 8 | * 9 | * @author qgl 10 | * @date 2019/03/13 11 | */ 12 | public class Test27 { 13 | @Test 14 | public void test27() throws Exception { 15 | BinaryToLinked27.BinaryTreeNode root1 = new BinaryToLinked27.BinaryTreeNode(); 16 | BinaryToLinked27.BinaryTreeNode node1 = new BinaryToLinked27.BinaryTreeNode(); 17 | BinaryToLinked27.BinaryTreeNode node2 = new BinaryToLinked27.BinaryTreeNode(); 18 | BinaryToLinked27.BinaryTreeNode node3 = new BinaryToLinked27.BinaryTreeNode(); 19 | BinaryToLinked27.BinaryTreeNode node4 = new BinaryToLinked27.BinaryTreeNode(); 20 | BinaryToLinked27.BinaryTreeNode node5 = new BinaryToLinked27.BinaryTreeNode(); 21 | BinaryToLinked27.BinaryTreeNode node6 = new BinaryToLinked27.BinaryTreeNode(); 22 | root1.leftNode = node1; 23 | root1.rightNode = node2; 24 | node1.leftNode = node3; 25 | node1.rightNode = node4; 26 | node4.leftNode = node5; 27 | node4.rightNode = node6; 28 | root1.data = 8; 29 | node1.data = 9; 30 | node2.data = 7; 31 | node3.data = 10; 32 | node4.data = 2; 33 | node5.data = 4; 34 | node6.data = 1; 35 | 36 | BinaryToLinked27.convert(root1); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test28.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第28题 7 | * 输入一个字符串,打印出字符串中字符的所有排列 8 | * 9 | * @author qgl 10 | * @date 2019/03/14 11 | */ 12 | public class Test28 { 13 | @Test 14 | public void test28() throws Exception { 15 | String testStr = "try"; 16 | System.out.println("解法一:while循环,结果:" + Permutation28.permutation1(testStr)); 17 | System.out.println("解法二:递归,结果:" + Permutation28.Permutation(testStr)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test29.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第29题 7 | * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字 8 | * 9 | * @author qgl 10 | * @date 2019/03/15 11 | */ 12 | public class Test29 { 13 | @Test 14 | public void test29() throws Exception { 15 | int[] array = {1, 2, 3, 4, 5, 4, 5, 5, 5, 6, 7, 5, 5, 5}; 16 | System.out.println("数组中出现次数超过数组长度一半的数字是:" + MoreThanHalfNum29.moreThanHalfNum(array)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test3.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第3题 7 | * 一个二维数组,每一行从左到右递增,每一列从上到下递增. 8 | * 输入一个二维数组和一个整数,判断数组中是否含有整数 9 | * 10 | * @author qgl 11 | * @date 2019/02/17 12 | */ 13 | public class Test3 { 14 | @Test 15 | public void test3() { 16 | int[][] testArray = {{1, 7, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15}}; 17 | int target = 6; 18 | System.out.println("解法一:两个指针,数组中是否含有" + target + " :" + FindNumber3.find(testArray, target)); 19 | System.out.println("解法二:二分法,数组中是否含有" + target + " :" + FindNumber3.find(testArray, target)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test30.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 第30题 9 | * 输入N个整数,找出其中最小的k个数 10 | * 11 | * @author qgl 12 | * @date 2019/03/16 13 | */ 14 | public class Test30 { 15 | @Test 16 | public void test30() throws Exception { 17 | int[] array = {4, 5, 1, 6, 2, 7, 3, 2}; 18 | int k = 3; 19 | System.out.println("最小的" + k + "个数是:" + GetLeastNumbers30.getLeastNumbers(array, k)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test31.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 第31题 9 | * 数组中一个或连续的多个整数组成一个子数组,求连续子数组的最大和 10 | * 11 | * @author qgl 12 | * @date 2019/03/17 13 | */ 14 | public class Test31 { 15 | @Test 16 | public void test30() throws Exception { 17 | int[] array = {1, -2, 3, 10, -4, 7, 2, -5}; 18 | System.out.println("连续子数组的最大和是:" + FindGreatestSum31.findGreatestSum(array)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test32.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第32题 7 | * 输入一个整数n,求从1到n这N个十进制表示中1出现的次数 8 | * 9 | * @author qgl 10 | * @date 2019/03/18 11 | */ 12 | public class Test32 { 13 | @Test 14 | public void test32() throws Exception { 15 | System.out.println("解法一,1出现的次数:" + NumberOf1Bw32.NumberOf1Between1AndN1(13)); 16 | System.out.println("解法二,1出现的次数:" + NumberOf1Bw32.NumberOf1Between1AndN2(13)); 17 | System.out.println("解法三,1出现的次数:" + NumberOf1Bw32.NumberOf1Between1AndN3(13)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test33.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第33题 7 | * 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印出能拼接出的所有数字中的最小的一个。 8 | * 9 | * @author qgl 10 | * @date 2019/03/19 11 | */ 12 | public class Test33 { 13 | @Test 14 | public void test32() throws Exception { 15 | int[] array = {3, 19, 32, 5, 26}; 16 | System.out.println("解法一,自定义快排:" + PrintMinNumber33.printMinNumber1(array)); 17 | System.out.println("解法二,JDK的归排:" + PrintMinNumber33.printMinNumber2(array)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test34.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第34题 7 | * 求从小到大的第1500个丑数(只包含因子2,3,5的数为丑数,1是第一个丑数) 8 | * 9 | * @author qgl 10 | * @date 2019/03/20 11 | */ 12 | public class Test34 { 13 | @Test 14 | public void test34() throws Exception { 15 | int num = 100; 16 | System.out.println("第 " + num + " 个丑数是 " + UglyNumber34.getUglyNumber(num)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test35.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第35题 7 | * 在字符串中找出第一个只出现一次的字符 8 | * 9 | * @author qgl 10 | * @date 2019/03/21 11 | */ 12 | public class Test35 { 13 | @Test 14 | public void test35() throws Exception { 15 | String str = "abdbatccdeff"; 16 | System.out.println("第一个只出现一次的字符的下标是:" + FirstNotRepeating35.getFirstNotRepeatingCharIndex(str)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test36.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第36题 7 | * 数组中的两个数字如果前面一个数字大于后面一个数字, 8 | * 则这两个数字组成一个逆序对,输入一个数组,求逆序对的总数 9 | * 10 | * @author qgl 11 | * @date 2019/03/22 12 | */ 13 | public class Test36 { 14 | @Test 15 | public void test36() throws Exception { 16 | int[] array = {1, 2, 3, 4, 5, 6, 7, 0}; 17 | int[] array2 = {364, 637, 341, 406, 747, 995, 234, 971, 571, 219, 993, 407, 416, 366, 315, 301, 601, 650, 418, 355, 460, 505, 360, 965, 516, 648, 727, 667, 465, 849, 455, 181, 486, 149, 588, 233, 144, 174, 557, 67, 746, 550, 474, 162, 268, 142, 463, 221, 882, 576, 604, 739, 288, 569, 256, 936, 275, 401, 497, 82, 935, 983, 583, 523, 697, 478, 147, 795, 380, 973, 958, 115, 773, 870, 259, 655, 446, 863, 735, 784, 3, 671, 433, 630, 425, 930, 64, 266, 235, 187, 284, 665, 874, 80, 45, 848, 38, 811, 267, 575}; 18 | System.out.println("逆序对总数:" + InversePairs36.inversePairs(array)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test37.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第37题 7 | * 求两个单向链表的第一个公共节点 8 | * 9 | * @author qgl 10 | * @date 2019/03/23 11 | */ 12 | public class Test37 { 13 | @Test 14 | public void test37() throws Exception { 15 | FindFirstCommonNode37.ListNode head1 = new FindFirstCommonNode37.ListNode(1); 16 | FindFirstCommonNode37.ListNode second1 = new FindFirstCommonNode37.ListNode(2); 17 | FindFirstCommonNode37.ListNode third1 = new FindFirstCommonNode37.ListNode(3); 18 | FindFirstCommonNode37.ListNode forth1 = new FindFirstCommonNode37.ListNode(6); 19 | FindFirstCommonNode37.ListNode fifth1 = new FindFirstCommonNode37.ListNode(7); 20 | FindFirstCommonNode37.ListNode head2 = new FindFirstCommonNode37.ListNode(1); 21 | FindFirstCommonNode37.ListNode second2 = new FindFirstCommonNode37.ListNode(5); 22 | FindFirstCommonNode37.ListNode third2 = new FindFirstCommonNode37.ListNode(6); 23 | FindFirstCommonNode37.ListNode forth2 = new FindFirstCommonNode37.ListNode(8); 24 | head1.next = second1; 25 | second1.next = third1; 26 | third1.next = forth1; 27 | forth1.next = fifth1; 28 | head2.next = second2; 29 | second2.next = forth1; 30 | third2.next = forth2; 31 | 32 | System.out.println("解法一:第一个公共节点是:" + FindFirstCommonNode37.findFirstCommonNode1(head1, head2).val); 33 | System.out.println("解法二:第一个公共节点是:" + FindFirstCommonNode37.findFirstCommonNode2(head1, head2).val); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test38.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第38题 7 | * 统计一个数字在排序数组中出现的次数 8 | * 9 | * @author qgl 10 | * @date 2019/03/24 11 | */ 12 | public class Test38 { 13 | @Test 14 | public void test38() throws Exception { 15 | int[] testArray = {1, 3, 3, 6, 7, 8, 8, 8, 8, 9}; 16 | int num = 8; 17 | System.out.println("解法一:" + num + " 在排序数组中出现的次数:" + GetNumberOfK38.getNumberOfK(testArray, num)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test39.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第39题 7 | * 输入根节点求树的深度 8 | * 9 | * @author qgl 10 | * @date 2019/03/25 11 | */ 12 | public class Test39 { 13 | @Test 14 | public void test39() throws Exception { 15 | TreePath39.BinaryTreeNode root1 = new TreePath39.BinaryTreeNode(); 16 | TreePath39.BinaryTreeNode node1 = new TreePath39.BinaryTreeNode(); 17 | TreePath39.BinaryTreeNode node2 = new TreePath39.BinaryTreeNode(); 18 | TreePath39.BinaryTreeNode node3 = new TreePath39.BinaryTreeNode(); 19 | TreePath39.BinaryTreeNode node4 = new TreePath39.BinaryTreeNode(); 20 | TreePath39.BinaryTreeNode node5 = new TreePath39.BinaryTreeNode(); 21 | TreePath39.BinaryTreeNode node6 = new TreePath39.BinaryTreeNode(); 22 | root1.leftNode = node1; 23 | root1.rightNode = node2; 24 | node1.leftNode = node3; 25 | node1.rightNode = node4; 26 | node4.leftNode = node5; 27 | node4.rightNode = node6; 28 | root1.data = 8; 29 | node1.data = 9; 30 | node2.data = 7; 31 | node3.data = 10; 32 | node4.data = 2; 33 | node5.data = 4; 34 | node6.data = 1; 35 | 36 | /* 37 | 二叉树 38 | 8 39 | / \ 40 | 9 7 41 | / \ 42 | 10 2 43 | / \ 44 | 4 1 45 | */ 46 | 47 | System.out.println("树的深度:" + TreePath39.treePath(root1)); 48 | System.out.println("是否是平衡二叉树:" + TreePath39.isBalanced(root1)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test4.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第4题 7 | * 将一个字符串中的空格替换成"%20" 8 | * 9 | * @author qgl 10 | * @date 2019/02/18 11 | */ 12 | public class Test4 { 13 | @Test 14 | public void test4() { 15 | String beforeStr = " ab g gt r "; 16 | System.out.println("解法一:使用StringBuffer, 替换前:" + beforeStr + " 替换后:" + ReplaceBlank4.replaceBlank1(beforeStr)); 17 | System.out.println("解法二:使用StringBuilder,替换前:" + beforeStr + " 替换后:" + ReplaceBlank4.replaceBlank2(beforeStr)); 18 | System.out.println("解法三:从后往前复制, 替换前:" + beforeStr + " 替换后:" + ReplaceBlank4.replaceBlank3(beforeStr)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test40.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 第40题 9 | * 一个整型数组里除了两个数字之外,其他的数字都出现了两次,找出这两个只出现了一次的数字 10 | * 11 | * @author qgl 12 | * @date 2019/03/26 13 | */ 14 | public class Test40 { 15 | @Test 16 | public void test40() throws Exception { 17 | int[] array = {4, 6, 7, 4, 9, 8, 6, 8}; 18 | System.out.println("只出现了一次的数字:" + Arrays.toString(FindNumAppearOnce40.findNumAppearOnce(array))); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test41.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第41题 7 | * 输入一个递增排序的数组和一个数字s.在数组中查找两个数使他们的和为s,如果有多对数字的和等于s,输出两个数的乘积最小的一对 8 | * 9 | * @author qgl 10 | * @date 2019/03/27 11 | */ 12 | public class Test41 { 13 | @Test 14 | public void test41() throws Exception { 15 | int[] array = {1, 2, 4, 6, 7, 8, 12, 15}; 16 | int s = 10; 17 | System.out.println("和为s的两个数:" + FindNumbersWithSum41.findNumbersWithSum(array, s)); 18 | System.out.println("所有和为s的连续正数序列:" + FindNumbersWithSum41.findContinuousSequence(s)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test42.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第42题 7 | * 输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变 8 | * 9 | * @author qgl 10 | * @date 2019/03/28 11 | */ 12 | public class Test42 { 13 | @Test 14 | public void test42() throws Exception { 15 | String str = "you maybe became a stronger"; 16 | System.out.println("翻转句子的单词顺序:" + ReverseSentence42.reverseSentence(str)); 17 | 18 | String rotationStr = "a pen I have "; 19 | System.out.println("字符串的左旋:" + ReverseSentence42.leftRotateString(rotationStr,5)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test43.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第43题 7 | * 把n个骰子扔在地上,所有骰子朝上一面的点数之和为s,输入n,打印出s的所有可能出现的概率 8 | * 9 | * @author qgl 10 | * @date 2019/03/29 11 | */ 12 | public class Test43 { 13 | @Test 14 | public void test43() throws Exception { 15 | int diceNum = 2; 16 | System.out.println("所有可能出现的概率:" + DicesProbability43.printProbability(diceNum)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test44.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第44题 7 | * 判断扑克牌中的顺子,0表示大小王(可以是任意数) 8 | * 1表示A,2~10为本身,11表示J,12表示Q,13表示K 9 | * 10 | * @author qgl 11 | * @date 2019/03/30 12 | */ 13 | public class Test44 { 14 | @Test 15 | public void test44() throws Exception { 16 | int[] array = {2, 6, 4, 5, 0}; 17 | System.out.println("是否是顺子:" + IsContinuous44.isContinuous(array)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test45.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第45题 7 | * 0,1...n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字. 8 | * 求这个圈圈里剩下的最后一个数字 9 | * 10 | * @author qgl 11 | * @date 2019/03/31 12 | */ 13 | public class Test45 { 14 | @Test 15 | public void test45() throws Exception { 16 | int n = 7; 17 | int m = 2; 18 | System.out.println("解法一,借助链表,圈圈里剩下的最后一个数字:" + LastRemaining45.lastRemain1(n,m)); 19 | System.out.println("解法二,公式法,圈圈里剩下的最后一个数字:" + LastRemaining45.lastRemain2(n,m)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test46.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第46题 7 | * 求1+2+...+n,不能使用乘除法,循环等 8 | * 9 | * @author qgl 10 | * @date 2019/04/01 11 | */ 12 | public class Test46 { 13 | @Test 14 | public void test46() throws Exception { 15 | int n = 10; 16 | System.out.println("解法一,利用递归,求1 + ...+ " + n + " 的和:" + Calculate46.sum(n)); 17 | System.out.println("解法二,利用递归和全局变量,求1 + ...+ " + n + " 的和:" + Calculate46.sum2(n)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test47.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第47题 7 | * 不用加减乘除做加法 8 | * 9 | * @author qgl 10 | * @date 2019/04/02 11 | */ 12 | public class Test47 { 13 | @Test 14 | public void test47() throws Exception { 15 | int num1 = 5; 16 | int num2 = 11; 17 | System.out.println("求和:" + num1 + " + " + num2 + " = " + Add47.add(num1, num2)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test48.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第48题 7 | * 不能被继承的类 8 | * 9 | * @author qgl 10 | * @date 2019/04/03 11 | */ 12 | public class Test48 { 13 | /** 14 | * 继承FinalClass48类会报错 15 | */ 16 | // class TestClass48 extends FinalClass48{} 17 | 18 | @Test 19 | public void test48() throws Exception { 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test49.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第49题 7 | * 将一个字符串转换成一个整数。数值为0或者字符串不是一个合法的数值则返回0 8 | * 9 | * @author qgl 10 | * @date 2019/04/04 11 | */ 12 | public class Test49 { 13 | 14 | @Test 15 | public void test49() throws Exception { 16 | String str = "+015303"; 17 | String str2 = "p015c303"; 18 | System.out.println("字符串转换为整数:" + StrToInt49.StrToInt(str)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test5.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.ListNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * 第5题 从尾到头打印链表 8 | * 输入一个链表,从尾到头打印链表每个节点的值 9 | * 10 | * @author qgl 11 | * @date 2019/02/19 12 | */ 13 | public class Test5 { 14 | @Test 15 | public void test5() { 16 | ListNode node1 = new ListNode(3); 17 | ListNode node2 = new ListNode(6); 18 | ListNode node3 = new ListNode(9); 19 | node1.next = node2; 20 | node2.next = node3; 21 | System.out.println("解法一:利用栈输出,反转后:" + PrintListReversing5.printListReverse1(node1)); 22 | System.out.println("解法二:递归,反转后:" + PrintListReversing5.printListReverse2(node1)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test50.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import static com.so.MinCParent50.*; 6 | 7 | /** 8 | * 第50题 9 | * 寻找树的两个节点的最低公共祖先 10 | * 11 | * @author qgl 12 | * @date 2019/04/06 13 | */ 14 | public class Test50 { 15 | 16 | @Test 17 | public void test50() throws Exception { 18 | MinCParent50.BinaryTreeNode A = new MinCParent50.BinaryTreeNode(4); 19 | MinCParent50.BinaryTreeNode B = new MinCParent50.BinaryTreeNode(2); 20 | MinCParent50.BinaryTreeNode C = new MinCParent50.BinaryTreeNode(6); 21 | MinCParent50.BinaryTreeNode D = new MinCParent50.BinaryTreeNode(1); 22 | MinCParent50.BinaryTreeNode E = new MinCParent50.BinaryTreeNode(3); 23 | MinCParent50.BinaryTreeNode F = new MinCParent50.BinaryTreeNode(5); 24 | MinCParent50.BinaryTreeNode G = new MinCParent50.BinaryTreeNode(7); 25 | A.leftNode = B; 26 | A.rightNode = C; 27 | B.leftNode = D; 28 | B.rightNode = E; 29 | C.leftNode = F; 30 | C.rightNode = G; 31 | 32 | MinCParent50.BinaryTreeNode res1 = getLowestCommonAncestor1(null, A, D, E); 33 | MinCParent50.BinaryTreeNode res2 = getLowestCommonAncestor2(A, E, F); 34 | System.out.println("1 和 3 的最低公共祖先是:" + res1.value); 35 | System.out.println("3 和 5 的最低公共祖先是:" + res2.value); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test51.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import static com.so.MinCParent50.*; 6 | 7 | /** 8 | * 第51题 9 | * 在一个长度为n的数组里的所有数字都在0到n-1的范围内,找出数组中任意一个重复的数字 10 | * 11 | * @author qgl 12 | * @date 2019/04/07 13 | */ 14 | public class Test51 { 15 | 16 | @Test 17 | public void test51() throws Exception { 18 | int[] arr = {6, 5, 3, 5, 2, 1, 5}; 19 | System.out.println("解法三,快慢指针:" + Duplicate51.duplicate3(arr)); 20 | System.out.println("解法二,利用HashSet:" + Duplicate51.duplicate2(arr)); 21 | System.out.println("解法一,利用数组的特点:" + Duplicate51.duplicate1(arr)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test52.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 第52题 9 | * 构建乘积数组 10 | * 11 | * @author qgl 12 | * @date 2019/04/08 13 | */ 14 | public class Test52 { 15 | 16 | @Test 17 | public void test52() throws Exception { 18 | int[] arr = {2, 3, 4, 5}; 19 | System.out.println("乘积数组:" + Arrays.toString(MultiplyArray52.multiply(arr))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test53.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 第53题 9 | * 正则表达式匹配字符串,实现一个函数用来匹配包括'.'和'*'的正则表达式 10 | * 其中'*'表示它前面的字符可以出现任意次(包含0次) 11 | * 12 | * @author qgl 13 | * @date 2019/04/09 14 | */ 15 | public class Test53 { 16 | 17 | @Test 18 | public void test53() throws Exception { 19 | String str = "aaa"; 20 | String pattern = "a.a"; 21 | System.out.println("是否匹配:" + RegularMatch53.match(str.toCharArray(),pattern.toCharArray())); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test54.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | /** 7 | * 第54题 8 | * 判断字符串是否表示数值(包括整数和小数) 9 | * 10 | * @author qgl 11 | * @date 2019/04/10 12 | */ 13 | public class Test54 { 14 | 15 | @Test 16 | public void test54() throws Exception { 17 | String str = "3011o63l"; 18 | String str2 = "123.45e+6"; 19 | System.out.println("解法一:逐个字符进行判断 是否表示数值:" + IsNumber54.isNumber1(str.toCharArray())); 20 | System.out.println("解法二:用正则表达式判断 是否表示数值:" + IsNumber54.isNumber2(str.toCharArray())); 21 | 22 | // Assert.assertTrue(IsNumber54.isNumber1(str.toCharArray())); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test55.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第55题 7 | * 请实现一个函数用来找出字符流中第一个只出现一次的字符 8 | * 9 | * @author qgl 10 | * @date 2019/04/11 11 | */ 12 | public class Test55 { 13 | 14 | @Test 15 | public void test55() throws Exception { 16 | String str = "3A15t63e"; 17 | String str2 = "3A61e5A613e5"; 18 | FirstAppearingOnce55.insertChars(str.toCharArray()); 19 | System.out.println("字符流中第一个只出现一次的字符是:" + FirstAppearingOnce55.getFirstAppearingOnce()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test56.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第56题 7 | * 找出环链表的入口结点 8 | * 9 | * @author qgl 10 | * @date 2019/04/12 11 | */ 12 | public class Test56 { 13 | 14 | @Test 15 | public void test56() throws Exception { 16 | EnterLoop56.ListNode root = new EnterLoop56.ListNode(6); 17 | EnterLoop56.ListNode first = new EnterLoop56.ListNode(1); 18 | EnterLoop56.ListNode second = new EnterLoop56.ListNode(2); 19 | EnterLoop56.ListNode three = new EnterLoop56.ListNode(3); 20 | EnterLoop56.ListNode four = new EnterLoop56.ListNode(4); 21 | root.next = first; 22 | first.next = second; 23 | second.next = three; 24 | three.next = four; 25 | four.next = root; 26 | 27 | System.out.println("环链表的入口结点:" + EnterLoop56.enterNodeOfLoop(root).val); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test57.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第57题 7 | * 删除链表的重复节点 8 | * 9 | * @author qgl 10 | * @date 2019/04/13 11 | */ 12 | public class Test57 { 13 | 14 | @Test 15 | public void test57() throws Exception { 16 | DeleteDuplication57.ListNode head = new DeleteDuplication57.ListNode(6); 17 | DeleteDuplication57.ListNode first = new DeleteDuplication57.ListNode(1); 18 | DeleteDuplication57.ListNode second = new DeleteDuplication57.ListNode(3); 19 | DeleteDuplication57.ListNode three = new DeleteDuplication57.ListNode(3); 20 | DeleteDuplication57.ListNode four = new DeleteDuplication57.ListNode(5); 21 | head.next = first; 22 | first.next = second; 23 | second.next = three; 24 | three.next = four; 25 | 26 | System.out.println("原链表:" + printfListNode(head)); 27 | System.out.println("删除链表的重复节点后:" + printfListNode(DeleteDuplication57.deleteDuplication(head))); 28 | } 29 | 30 | /** 31 | * 打印链表 32 | * @param head 33 | * @return 34 | */ 35 | public String printfListNode(DeleteDuplication57.ListNode head) { 36 | StringBuilder sb = new StringBuilder(); 37 | while (head != null) { 38 | sb.append(head.val).append("→"); 39 | head = head.next; 40 | } 41 | return sb.toString().substring(0, sb.length() - 1); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test58.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第58题 7 | * 给定一个二叉树的某个结点,请找出中序遍历顺序的下一个结点并且返回 8 | * 9 | * @author qgl 10 | * @date 2019/04/14 11 | */ 12 | public class Test58 { 13 | 14 | @Test 15 | public void test58() throws Exception { 16 | NextTreeNode58.TreeLinkNode root = new NextTreeNode58.TreeLinkNode(4); 17 | NextTreeNode58.TreeLinkNode first = new NextTreeNode58.TreeLinkNode(2); 18 | NextTreeNode58.TreeLinkNode second = new NextTreeNode58.TreeLinkNode(6); 19 | NextTreeNode58.TreeLinkNode three = new NextTreeNode58.TreeLinkNode(1); 20 | NextTreeNode58.TreeLinkNode four = new NextTreeNode58.TreeLinkNode(3); 21 | root.left = first; 22 | root.right = second; 23 | first.left = three; 24 | first.right = four; 25 | 26 | System.out.println("输入节点的下一个节点值:" + NextTreeNode58.getTreeLinkNextNode(first).val); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test59.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第59题 8 | * 判断二叉树是否是对称的 9 | * 10 | * @author qgl 11 | * @date 2019/04/15 12 | */ 13 | public class Test59 { 14 | 15 | @Test 16 | public void test59() throws Exception { 17 | TreeNode root = new TreeNode(8); 18 | TreeNode node1 = new TreeNode(5); 19 | TreeNode node2 = new TreeNode(5); 20 | TreeNode node3 = new TreeNode(9); 21 | TreeNode node4 = new TreeNode(2); 22 | TreeNode node5 = new TreeNode(2); 23 | TreeNode node6 = new TreeNode(9); 24 | root.left = node1; 25 | root.right = node2; 26 | node1.left = node3; 27 | node1.right = node4; 28 | node2.left = node5; 29 | node2.right = node6; 30 | 31 | System.out.println("二叉树是否对称:" + IsSymmetrical59.isSymmetrical(root)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test6.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第6题 8 | * 输入二叉树的前序遍历和中序遍历结果,重建该二叉树. 9 | * 10 | * @author qgl 11 | * @date 2019/02/20 12 | */ 13 | public class Test6 { 14 | @Test 15 | public void test6() { 16 | // 前序遍历结果 17 | int[] pre = {1, 2, 4, 7, 3, 5, 6, 8}; 18 | // 中序遍历结果 19 | int[] in = {4, 7, 2, 1, 5, 3, 8, 6}; 20 | TreeNode root = BinaryTreeSearch6.reConstructBinaryTree(pre, in); 21 | System.out.print("重建后的二叉树(层序输出):" + new PrintFromTopToBottom23().PrintFromTopToBottom(root)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test60.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第60题 8 | * 之字形打印二叉树 9 | * 10 | * @author qgl 11 | * @date 2019/04/16 12 | */ 13 | public class Test60 { 14 | 15 | @Test 16 | public void test60() throws Exception { 17 | TreeNode root = new TreeNode(7); 18 | TreeNode node1 = new TreeNode(5); 19 | TreeNode node2 = new TreeNode(8); 20 | TreeNode node3 = new TreeNode(3); 21 | TreeNode node4 = new TreeNode(6); 22 | TreeNode node5 = new TreeNode(9); 23 | TreeNode node6 = new TreeNode(11); 24 | root.left = node1; 25 | root.right = node2; 26 | node1.left = node3; 27 | node1.right = node4; 28 | node2.left = node5; 29 | node2.right = node6; 30 | 31 | System.out.println("之字形打印二叉树:" + ZTreePrint60.Print(root)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test61.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | import com.so.Common.TreeNode; 5 | 6 | /** 7 | * 第61题 8 | * 把二叉树打印成多行,从上到下按层打印二叉树,同一层结点从左至右输出。 9 | * 10 | * @author qgl 11 | * @date 2019/04/17 12 | */ 13 | public class Test61 { 14 | 15 | @Test 16 | public void test61() throws Exception { 17 | TreeNode root = new TreeNode(7); 18 | TreeNode node1 = new TreeNode(5); 19 | TreeNode node2 = new TreeNode(8); 20 | TreeNode node3 = new TreeNode(3); 21 | TreeNode node4 = new TreeNode(6); 22 | TreeNode node5 = new TreeNode(9); 23 | TreeNode node6 = new TreeNode(11); 24 | root.left = node1; 25 | root.right = node2; 26 | node1.left = node3; 27 | node1.right = node4; 28 | node2.left = node5; 29 | node2.right = node6; 30 | 31 | System.out.println("从左至右打印每行二叉树:" + LevelPrintTree61.printTreeNodeByLeftToRight(root)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test62.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.TreeNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * 第62题 8 | * 二叉树的序列化与反序列化 9 | * 10 | * @author qgl 11 | * @date 2019/04/18 12 | */ 13 | public class Test62 { 14 | 15 | @Test 16 | public void test62() throws Exception { 17 | TreeNode root = new TreeNode(7); 18 | TreeNode node1 = new TreeNode(5); 19 | TreeNode node2 = new TreeNode(8); 20 | TreeNode node3 = new TreeNode(3); 21 | TreeNode node4 = new TreeNode(6); 22 | TreeNode node5 = new TreeNode(9); 23 | TreeNode node6 = new TreeNode(11); 24 | root.left = node1; 25 | root.right = node2; 26 | node1.left = node3; 27 | node1.right = node4; 28 | node2.left = node5; 29 | node2.right = node6; 30 | 31 | String serializerTree = Serializer62.serialize(root); 32 | System.out.println("序列化二叉树:" + serializerTree); 33 | System.out.println("反序列化二叉树后,从左至右输出:" + LevelPrintTree61.printTreeNodeByLeftToRight(Serializer62.deserialize(serializerTree))); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test63.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import com.so.Common.TreeNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * 第63题 8 | * 给定一棵二叉搜索树,请找出其中的第k小的结点 9 | * 10 | * @author qgl 11 | * @date 2019/04/19 12 | */ 13 | public class Test63 { 14 | 15 | @Test 16 | public void test63() throws Exception { 17 | TreeNode root = new TreeNode(7); 18 | TreeNode node1 = new TreeNode(5); 19 | TreeNode node2 = new TreeNode(9); 20 | TreeNode node3 = new TreeNode(3); 21 | TreeNode node4 = new TreeNode(6); 22 | TreeNode node5 = new TreeNode(8); 23 | TreeNode node6 = new TreeNode(11); 24 | root.left = node1; 25 | root.right = node2; 26 | node1.left = node3; 27 | node1.right = node4; 28 | node2.left = node5; 29 | node2.right = node6; 30 | 31 | KthNode63 kthNode63 = new KthNode63(); 32 | int k = 3; 33 | System.out.println("解法一:递归查找:" + kthNode63.KthNode(root, k).val); 34 | System.out.println("解法二:非递归,借用栈查找:" + kthNode63.getKthNode2(root, k).val); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test64.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第64题 7 | * 求数据流中的中位数 8 | * 9 | * @author qgl 10 | * @date 2019/04/20 11 | */ 12 | public class Test64 { 13 | 14 | @Test 15 | public void test64() throws Exception { 16 | int[] arr = {2, 4, 5, 8, 15, 10, 7, 9}; 17 | GetMedian64.insertArray(arr); 18 | System.out.println("解法一:利用集合类的归并排序获取中位数:" + GetMedian64.getMedian1()); 19 | System.out.println("解法二:利用优先级队列构建堆进行排序后获取中位数:" + GetMedian64.getMedian2()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test65.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第65题 7 | * 求滑动窗口的最大值 8 | * 9 | * @author qgl 10 | * @date 2019/04/21 11 | */ 12 | public class Test65 { 13 | 14 | @Test 15 | public void test65() throws Exception { 16 | int[] arr = {2, 3, 4, 2, 6, 2, 5, 1}; 17 | int windowsSize = 3; 18 | System.out.println("解法一:两个for循环,获取滑动窗口的最大值:" + MaxInWindows65.maxInWindows1(arr, windowsSize)); 19 | System.out.println("解法二:双端队列,获取滑动窗口的最大值:" + MaxInWindows65.maxInWindows2(arr, windowsSize)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test66.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第66题 7 | * 判断在一个矩阵中是否存在一条包含某字符串所有字符的路径 8 | * 9 | * @author qgl 10 | * @date 2019/04/22 11 | */ 12 | public class Test66 { 13 | 14 | @Test 15 | public void test66() throws Exception { 16 | char[] arr = {'a', 'b', 'c', 'e', 's', 'f', 'c', 's', 'a', 'd', 'e', 'e'}; 17 | int rows = 3; 18 | int columns = 4; 19 | char[] str = {'b', 'c', 'c', 'e', 'd'}; 20 | char[] str2 = {'a', 'b', 'c', 'b'}; 21 | System.out.println("矩阵中是否存在该路径:" + HasPath66.hasPath(arr, rows, columns, str)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test67.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第67题 7 | * 机器人的运动范围,一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格, 8 | * 但是不能进入行坐标和列坐标的数位之和大于k的格子。求机器人能够达到多少个格子 9 | * 10 | * @author qgl 11 | * @date 2019/04/23 12 | */ 13 | public class Test67 { 14 | 15 | @Test 16 | public void test67() throws Exception { 17 | int rows = 3; 18 | int columns = 4; 19 | int k = 18; 20 | System.out.println("机器人能够达到多少个格子:" + MovingCount67.movingCount(rows, columns, k)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test7.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第7题 7 | * 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 8 | * 9 | * @author qgl 10 | * @date 2019/02/21 11 | */ 12 | public class Test7 { 13 | @Test 14 | public void test7() throws Exception { 15 | DoubleSQueue7 doubleSQueue7 = new DoubleSQueue7(); 16 | doubleSQueue7.push(2); 17 | doubleSQueue7.push(5); 18 | doubleSQueue7.push(8); 19 | System.out.println("出队列:" + doubleSQueue7.pop()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test8.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第8题 7 | * 输入一个非递减排序数组的一个旋转,输出旋转数组的最小元素。 8 | * 9 | * @author qgl 10 | * @date 2019/02/22 11 | */ 12 | public class Test8 { 13 | @Test 14 | public void test8() throws Exception { 15 | int[] array = {6, 7, 9, 1, 3, 5, 5}; 16 | System.out.println("旋转数组的最小元素:" + MinNumber8.minInReversingList(array)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/so/Test9.java: -------------------------------------------------------------------------------- 1 | package com.so; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * 第9题 7 | * 输入一个整数n,求斐波那契数列的第n项。 8 | * 9 | * @author qgl 10 | * @date 2019/02/23 11 | */ 12 | public class Test9 { 13 | @Test 14 | public void test9() throws Exception { 15 | int n = 9; 16 | System.out.println("解法一:三个局部变量,斐波那契数列的第 " + n + " 项是:" + Fibonacci9.getFibonacci1(n)); 17 | System.out.println("解法二:两个局部变量,斐波那契数列的第 " + n + " 项是:" + Fibonacci9.getFibonacci2(n)); 18 | System.out.println("解法三: 使用递归,斐波那契数列的第 " + n + " 项是:" + Fibonacci9.getFibonacci3(n)); 19 | } 20 | } 21 | --------------------------------------------------------------------------------