├── .idea ├── copyright │ └── profiles_settings.xml ├── vcs.xml ├── kotlinc.xml ├── modules.xml ├── compiler.xml ├── misc.xml ├── uiDesigner.xml └── workspace.xml ├── out └── production │ └── SwordToOffer │ ├── ADT │ ├── Alias.class │ ├── ListNode.class │ └── TreeNode.class │ ├── Part2 │ ├── Merge.class │ ├── HasSubtree.class │ ├── Mergesort.class │ ├── FindStackMin.class │ ├── ReverseList.class │ ├── reOrderArray.class │ ├── FindKthToTail.class │ ├── FindFirstCommonNode.class │ ├── PrintFromTopToBottom.class │ └── GetLeastNumbers_Solution.class │ ├── Part1 │ ├── Mirror.class │ ├── Fibonacci.class │ ├── JumpFloor.class │ ├── RectCover.class │ ├── GetNumberOfK.class │ ├── EntryNodeOfLoop.class │ ├── ReverseSentence.class │ ├── LeftRotateString.class │ ├── deleteDuplication.class │ └── FindNumbersWithSum.class │ └── Part3 │ ├── InversePairs.class │ ├── isSymmetrical.class │ └── FindGreatestSumOfSubArray.class ├── src ├── ADT │ ├── ListNode.java │ ├── TreeNode.java │ └── Alias.java ├── Part1 │ ├── JumpFloor2.java │ ├── RotateArray.java │ ├── Fibonacci.java │ ├── RectCover.java │ ├── IntToBin.java │ ├── JumpFloor.java │ ├── FindNumbersWithSum.java │ ├── Power.java │ ├── LeftRotateString.java │ ├── Mirror.java │ ├── ReplaceSpace.java │ ├── SecondArrayFind.java │ ├── deleteDuplication.java │ ├── EntryNodeOfLoop.java │ ├── GetNumberOfK.java │ └── ReverseSentence.java ├── Part3 │ ├── 整数中1出现的次数.java │ ├── 不用加减乘除做加法.java │ ├── 丑数.java │ ├── 字符串转为整数.java │ ├── 数组里重复的数字.java │ ├── 数组中只出现一次的数字.java │ ├── 构建乘积数组.java │ ├── 出现次数超过数组一半的数字.java │ ├── 连续数字序列的最大和.java │ ├── 第一次只出现一次的字符.java │ ├── 把数组排成最小整数.java │ ├── 和为S的连续正数序列.java │ ├── isSymmetrical.java │ └── 逆序对.java └── Part2 │ ├── 寻找链表中倒数第k个元素.java │ ├── 树的层次遍历.java │ ├── 栈的压入和弹出序列.java │ ├── FindStackMin.java │ ├── 两个链表找出它们的第一个公共结点.java │ ├── 找出其中最小的K个数.java │ ├── 链表第一个公共节点.java │ ├── ReverseList.java │ ├── 判断B是不是A的子结构.java │ ├── 两个单调递增的链表合并.java │ ├── 奇数在前偶数在后.java │ └── 归并排序.java ├── .gitattributes ├── SwordToOffer.iml ├── .gitignore └── README.md /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /out/production/SwordToOffer/ADT/Alias.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/ADT/Alias.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/Merge.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/Merge.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/ADT/ListNode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/ADT/ListNode.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/ADT/TreeNode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/ADT/TreeNode.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/Mirror.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/Mirror.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/Fibonacci.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/Fibonacci.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/JumpFloor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/JumpFloor.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/RectCover.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/RectCover.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/HasSubtree.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/HasSubtree.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/Mergesort.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/Mergesort.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/GetNumberOfK.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/GetNumberOfK.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/FindStackMin.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/FindStackMin.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/ReverseList.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/ReverseList.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/reOrderArray.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/reOrderArray.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part3/InversePairs.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part3/InversePairs.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/EntryNodeOfLoop.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/EntryNodeOfLoop.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/ReverseSentence.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/ReverseSentence.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/FindKthToTail.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/FindKthToTail.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part3/isSymmetrical.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part3/isSymmetrical.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/LeftRotateString.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/LeftRotateString.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/deleteDuplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/deleteDuplication.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part1/FindNumbersWithSum.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part1/FindNumbersWithSum.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/FindFirstCommonNode.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/FindFirstCommonNode.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/PrintFromTopToBottom.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/PrintFromTopToBottom.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part2/GetLeastNumbers_Solution.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part2/GetLeastNumbers_Solution.class -------------------------------------------------------------------------------- /out/production/SwordToOffer/Part3/FindGreatestSumOfSubArray.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/h2pl/SwordToOffer/HEAD/out/production/SwordToOffer/Part3/FindGreatestSumOfSubArray.class -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /src/ADT/ListNode.java: -------------------------------------------------------------------------------- 1 | package ADT; 2 | 3 | /** 4 | * Created by 周杰伦 on 2017/3/19. 5 | */ 6 | public class ListNode { 7 | public int val; 8 | public ListNode next = null; 9 | 10 | public ListNode(int val) { 11 | this.val = val; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/ADT/TreeNode.java: -------------------------------------------------------------------------------- 1 | package ADT; 2 | 3 | /** 4 | * Created by 周杰伦 on 2017/3/19. 5 | */ 6 | public class TreeNode { 7 | public int val = 0; 8 | public TreeNode left = null; 9 | public TreeNode right = null; 10 | 11 | public TreeNode(int val) { 12 | this.val = val; 13 | 14 | } 15 | 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/ADT/Alias.java: -------------------------------------------------------------------------------- 1 | package ADT; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by 周杰伦 on 2017/3/21. 7 | */ 8 | public class Alias { 9 | @Test 10 | public void test(){ 11 | ListNode p=new ListNode(0); 12 | ListNode c=p; 13 | p=new ListNode(9); 14 | System.out.println(c.val); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Part1/JumpFloor2.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import static java.lang.Math.pow; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/2/25.题目描述 7 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。 8 | 求该青蛙跳上一个n级的台阶总共有多少种跳法。 9 | */ 10 | public class JumpFloor2 { 11 | public int JumpFloorII(int target) { 12 | return (int) pow(2,target-1); 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /src/Part1/RotateArray.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/2/25. 5 | */ 6 | public class RotateArray { 7 | public int minNumberInRotateArray(int [] array) { 8 | if (array.length == 0) return 0; 9 | if (array.length == 1) return array[0]; 10 | int min = array[0]; 11 | for(int i = 1;i arrayList = new ArrayList<>(); 24 | System.out.println(Add(1,2)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Part1/RectCover.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by 周杰伦 on 2017/3/19. 7 | * 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 8 | */ 9 | public class RectCover { 10 | public int RectCover(int target) { 11 | if(target<=0) return 0; 12 | if(target==1 || target==2)return target; 13 | int []arr=new int[target]; 14 | arr[0]=1; 15 | arr[1]=2; 16 | for(int i=2;i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 1.8 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Part1/IntToBin.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/2/26. 7 | */ 8 | public class IntToBin { 9 | public static int NumberOf1(int n) { 10 | if (n == 0) return 0; 11 | int count = 0; 12 | for (int i = 0;i <=31; i++) { 13 | int temp = n; 14 | temp >>>= i; 15 | if ((temp & 1) == 1) { 16 | count ++; 17 | } 18 | } 19 | return count; 20 | } 21 | 22 | public static void main(String[] args) { 23 | StringBuffer sb = new StringBuffer(); 24 | sb.toString().contains("dadas"); 25 | System.out.println(Integer.toBinaryString(-10)); 26 | System.out.println(NumberOf1(-10)); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/Part3/丑数.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | /** 4 | * Created by 周杰伦 on 2018/3/23. 5 | */ 6 | public class 丑数 { 7 | public static void main(String[] args) { 8 | System.out.println(GetUglyNumber_Solution(6)); 9 | } 10 | public static int GetUglyNumber_Solution(int index) { 11 | if (index == 0) return 0; 12 | int []res = new int[index]; 13 | res[0] = 1; 14 | int i2,i3,i5; 15 | i2 = i3 = i5 = 0; 16 | for (int i = 1;i < index;i ++) { 17 | res[i] = Math.min(res[i2] * 2, Math.min(res[i3] * 3, res[i5] * 5)); 18 | if (res[i] == res[i2] * 2) i2 ++; 19 | if (res[i] == res[i3] * 3) i3 ++; 20 | if (res[i] == res[i5] * 5) i5 ++; 21 | } 22 | return res[index - 1]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Part3/字符串转为整数.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/3/20. 7 | */ 8 | public class 字符串转为整数 { 9 | public static int StrToInt(String str) { 10 | ArrayList list = new ArrayList<>(); 11 | for(int i = 0;i < str.length();i ++) { 12 | if ('0' <= str.charAt(i) && str.charAt(i) <= '9') { 13 | list.add(str.charAt(i)-48); 14 | } 15 | else return 0; 16 | } 17 | int num = 0; 18 | int add = 1; 19 | for(int i = list.size()-1; i >= 0;i --) { 20 | num += list.get(i)*add; 21 | add = add*10; 22 | } 23 | return num; 24 | } 25 | 26 | public static void main(String[] args) { 27 | System.out.println(StrToInt("123")); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SwordToOffer.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Part3/数组里重复的数字.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | import java.util.HashMap; 4 | import java.util.Set; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/3/20. 8 | */ 9 | public class 数组里重复的数字 { 10 | public boolean duplicate(int numbers[],int length,int [] duplication) { 11 | HashMap hashMap = new HashMap<>(); 12 | for(int i = 0;i < length;i ++) { 13 | if (hashMap.containsKey(numbers[i])) { 14 | hashMap.put(numbers[i], hashMap.get(numbers[i]) + 1); 15 | } 16 | else hashMap.put(numbers[i], 1); 17 | } 18 | Set set = hashMap.keySet(); 19 | for(int i : set) { 20 | if (hashMap.get(i) >= 2 ) { 21 | duplication[0] = i; 22 | return true; 23 | } 24 | } 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /src/Part2/树的层次遍历.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import ADT.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | import java.util.Queue; 8 | 9 | /** 10 | * 树的层次遍历 11 | * Created by 周杰伦 on 2017/3/22. 12 | */ 13 | public class 树的层次遍历 { 14 | public ArrayList PrintFromTopToBottom(TreeNode root) { 15 | ArrayList arrayList=new ArrayList<>(); 16 | if(root==null)return arrayList; 17 | 18 | Queue queue=new LinkedList<>(); 19 | 20 | queue.offer(root); 21 | while(!queue.isEmpty()){ 22 | TreeNode p=queue.poll(); 23 | arrayList.add(p.val); 24 | if(p.left!=null) 25 | queue.offer(p.left); 26 | if(p.right!=null) 27 | queue.offer(p.right); 28 | } 29 | return arrayList; 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Part1/JumpFloor.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by 周杰伦 on 2017/3/19. 7 | * 题目描述 8 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。 9 | */ 10 | public class JumpFloor { 11 | public int JumpFloor(int target) { 12 | if(target<=0) return 0; 13 | if(target==1 || target==2)return target; 14 | else return JumpFloor(target-1)+JumpFloor(target-2); 15 | } 16 | 17 | public int JumpFloorHD(int target) { 18 | if(target<=0) return 0; 19 | if(target==1 || target==2)return target; 20 | int []arr=new int[target]; 21 | arr[0]=1; 22 | arr[1]=2; 23 | for(int i=2;i FindNumbersWithSum(int [] array, int sum) { 11 | ArrayList arrayList=new ArrayList<>(); 12 | if(array==null)return null; 13 | 14 | int left=0,right=array.length-1; 15 | while (leftarray[left]+array[right]) 18 | left++; 19 | else if (sum0){ 17 | exponent = n; 18 | }else if(n<0){ 19 | if(base==0) 20 | throw new RuntimeException("分母不能为0"); 21 | exponent = -n; 22 | }else{// n==0 23 | return 1;// 0的0次方 24 | } 25 | while(exponent!=0){ 26 | if((exponent&1)==1) 27 | res*=curr; 28 | curr*=curr;// 翻倍 29 | exponent>>=1;// 右移一位 30 | } 31 | return n>=0?res:(1/res); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Part1/LeftRotateString.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by 周杰伦 on 2017/3/20. 7 | * 题目描述 8 | 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。 9 | 是不是很简单?OK,搞定它! 10 | */ 11 | public class LeftRotateString { 12 | public String LeftRotateString(String str,int n) { 13 | if(str == null || n<=0 ||str.length()==0) return str; 14 | 15 | n=n%str.length(); 16 | 17 | String left=str.substring(0,n); 18 | System.out.println(left); 19 | String right=str.substring(n,str.length()); 20 | System.out.println(right); 21 | StringBuffer sb=new StringBuffer(right); 22 | sb=sb.append(left); 23 | return sb.toString(); 24 | 25 | } 26 | 27 | @Test 28 | public void test(){ 29 | System.out.println(LeftRotateString("",3)); ; 30 | } 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/Part3/数组中只出现一次的数字.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | import java.util.HashMap; 4 | import java.util.Set; 5 | 6 | /** 7 | * Created by 周杰伦 on 2018/3/23. 8 | */ 9 | public class 数组中只出现一次的数字 { 10 | public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { 11 | HashMap map = new HashMap<>(); 12 | for (int i = 0;i < array.length; i ++) { 13 | if (map.containsKey(array[i])) { 14 | map.put(array[i], map.get(array[i]) + 1); 15 | } 16 | else map.put(array[i], 1); 17 | } 18 | Set set = map.keySet(); 19 | int a1 = 0; 20 | for (int i : set) { 21 | if (map.get(i) == 1) { 22 | num1[0] = i; 23 | a1 = i; 24 | } 25 | } 26 | for (int i : set) { 27 | if (map.get(i) == 1 && i != a1) { 28 | num2[0] = i; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Part3/构建乘积数组.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/3/23. 7 | */ 8 | public class 构建乘积数组 { 9 | public int[] multiply(int[] A) { 10 | int []b = new int[A.length]; 11 | int sum = 1; 12 | int flag = 0; 13 | int index = 0; 14 | for (int i = 0;i < A.length;i ++) { 15 | if (A[i] == 0 && flag ==1) { 16 | Arrays.fill(b, 0); 17 | return b; 18 | } 19 | if (A[i] == 0) { 20 | flag = 1; 21 | index = i; 22 | continue; 23 | } 24 | sum *= A[i]; 25 | } 26 | if (flag == 1) { 27 | Arrays.fill(b,0); 28 | b[index] = sum; 29 | return b; 30 | } 31 | for (int i = 0;i < A.length;i ++) { 32 | b[i] = (int) (sum * Math.pow(A[i], -1)); 33 | } 34 | return b; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Part2/栈的压入和弹出序列.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/3/26. 7 | */ 8 | public class 栈的压入和弹出序列 { 9 | public static void main(String[] args) { 10 | int[] a = {1, 2, 3, 4, 5}; 11 | int[] b = {4, 5, 3, 2, 1}; 12 | System.out.println(IsPopOrder(a, b)); 13 | } 14 | 15 | public static boolean IsPopOrder(int[] pushA, int[] popA) { 16 | Stack stack = new Stack<>(); 17 | int j = 0; 18 | int i = 0; 19 | while (i < pushA.length) { 20 | stack.push(pushA[i]); 21 | i ++; 22 | while (!stack.empty() && stack.peek() == popA[j]) { 23 | stack.pop(); 24 | j++; 25 | } 26 | if (i == pushA.length) { 27 | if (!stack.empty()) { 28 | return false; 29 | } else return true; 30 | } 31 | } 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Part3/出现次数超过数组一半的数字.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | import java.util.*; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/3/19. 7 | * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 8 | * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 9 | * 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 10 | */ 11 | public class 出现次数超过数组一半的数字 { 12 | public static int MoreThanHalfNum(int [] array) { 13 | 14 | HashMap map = new HashMap<>(); 15 | for(int i = 0;i < array.length;i ++){ 16 | int num = array[i]; 17 | if(map.containsKey(num)){ 18 | map.put(num,map.get(num) +1); 19 | }else map.put(num, 1); 20 | } 21 | Set set = map.keySet(); 22 | for (Integer i : set) { 23 | if(map.get(i) > array.length/2) { 24 | return i; 25 | } 26 | } 27 | return 0; 28 | } 29 | 30 | public static void main(String[] args) { 31 | int []arr = {1,2,3,2,2,2,5,4,2}; 32 | System.out.println(MoreThanHalfNum(arr)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Part1/Mirror.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import ADT.TreeNode; 4 | import org.junit.Test; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * Created by 周杰伦 on 2017/3/19.操作给定的二叉树,将其变换为源二叉树的镜像。 10 | 输入描述: 11 | 二叉树的镜像定义:源二叉树 12 | 8 13 | / \ 14 | 6 10 15 | / \ / \ 16 | 5 7 9 11 17 | 镜像二叉树 18 | 8 19 | / \ 20 | 10 6 21 | / \ / \ 22 | 11 9 7 5 23 | */ 24 | 25 | /** 26 | public class TreeNode { 27 | int val = 0; 28 | TreeNode left = null; 29 | TreeNode right = null; 30 | 31 | public TreeNode(int val) { 32 | this.val = val; 33 | 34 | } 35 | 36 | } 37 | */ 38 | public class Mirror { 39 | public void Mirror(TreeNode root) { 40 | if(root == null)return; 41 | if(root.left!=null || root.right!=null) 42 | { 43 | TreeNode temp=root.left; 44 | root.left=root.right; 45 | root.right=temp; 46 | } 47 | Mirror(root.left); 48 | Mirror(root.right); 49 | 50 | } 51 | 52 | @Test 53 | public void test(){ 54 | Mirror(new TreeNode(0)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Part3/连续数字序列的最大和.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * Created by 周杰伦 on 2017/3/23. 7 | * 题目描述 8 | HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。 9 | 今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。 10 | 但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢? 11 | 例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。 12 | 你会不会被他忽悠住?(子向量的长度至少是1) 13 | */ 14 | public class 连续数字序列的最大和 { 15 | public int FindGreatestSumOfSubArray(int[] array) { 16 | if(array==null || array.length==0)return 0; 17 | int sum=0;int max=array[0]; 18 | 19 | for(int i=0;i list = new ArrayList<>(); 16 | if (arr[0] != arr[1])list.add(arr[0]); 17 | if (arr[arr.length - 1] != arr[arr.length - 2])list.add(arr[arr.length - 1]); 18 | for (int i = 0;i < arr.length - 1;i ++) { 19 | if (arr[i] == arr[i + 1])continue; 20 | else if(i + 2 < arr.length && arr[i + 1] != arr[i + 2]) { 21 | list.add(arr[i + 1]); 22 | } 23 | } 24 | int index = arr.length - 1; 25 | for (char c : list) { 26 | if (str.indexOf(c) < index) { 27 | index = str.indexOf(c); 28 | } 29 | } 30 | return index; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Part2/FindStackMin.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | import java.util.Stack; 3 | /** 4 | * 设计一个返回最小值的栈 5 | * Created by 周杰伦 on 2017/3/22. 6 | */ 7 | 8 | public class FindStackMin { 9 | Stack stack=new Stack<>(); 10 | Stack minstack=new Stack<>(); 11 | 12 | public void push(int node) { 13 | if(stack.isEmpty()) 14 | { 15 | stack.push(node); 16 | minstack.push(node); 17 | } 18 | else if(node list = new ArrayList<>(); 19 | for (int i = 0; i < numbers.length; i++) { 20 | list.add(numbers[i]); 21 | } 22 | Collections.sort(list, new Comparator() { 23 | @Override 24 | public int compare(Integer o1, Integer o2) { 25 | String a = String.valueOf(o1); 26 | String b = String.valueOf(o2); 27 | return (a + b).compareTo(b + a); 28 | } 29 | }); 30 | StringBuffer sb = new StringBuffer(); 31 | for (int i : list) { 32 | sb.append(i); 33 | } 34 | 35 | return sb.toString(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Part2/两个链表找出它们的第一个公共结点.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import ADT.ListNode; 4 | 5 | 6 | import java.util.Stack; 7 | 8 | /** 9 | * Created by 周杰伦 on 2017/3/22. 10 | * 题目描述 11 | 输入两个链表,找出它们的第一个公共结点。 12 | */ 13 | public class 两个链表找出它们的第一个公共结点 { 14 | public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { 15 | if(pHead1==null ||pHead2==null)return null; 16 | Stack stack1=new Stack<>(); 17 | Stack stack2=new Stack<>(); 18 | while (pHead1!=null) 19 | { 20 | stack1.push(pHead1); 21 | pHead1=pHead1.next; 22 | } 23 | while (pHead2!=null){ 24 | stack2.push(pHead2); 25 | pHead2=pHead2.next; 26 | } 27 | ListNode p1=stack1.peek(); 28 | ListNode p2=stack2.peek(); 29 | ListNode common=null; 30 | while (p1==p2 &&!stack1.isEmpty() &&!stack2.isEmpty()){ 31 | if(p1==p2)common=p1; 32 | stack1.pop(); 33 | stack2.pop(); 34 | p1=stack1.peek(); 35 | p2=stack2.peek(); 36 | 37 | } 38 | if(p1!=p2) 39 | return common; 40 | else return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Part3/和为S的连续正数序列.java: -------------------------------------------------------------------------------- 1 | package Part3; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/3/23. 7 | */ 8 | public class 和为S的连续正数序列 { 9 | public static void main(String[] args) { 10 | System.out.println(FindContinuousSequence(9)); 11 | } 12 | public static ArrayList> FindContinuousSequence(int sum) { 13 | int []num = new int[(int) Math.ceil(sum/2.0)]; 14 | ArrayList> list = new ArrayList<>(); 15 | for (int i = 0;i < num.length;i ++) { 16 | num[i] = i + 1; 17 | } 18 | int temp = 0; 19 | int i = 0,j = i + 1; 20 | while (i < num.length && j < num.length) { 21 | temp = 0; 22 | for (int k = i;k <= j;k ++) { 23 | temp += num[k]; 24 | } 25 | if (temp < sum) j ++; 26 | else if (temp > sum) i++; 27 | else { 28 | ArrayList sublist = new ArrayList<>(); 29 | for (int k = i;k <= j;k ++) { 30 | sublist.add(num[k]); 31 | } 32 | list.add(sublist); 33 | i ++; 34 | j ++; 35 | } 36 | } 37 | return list; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Part2/找出其中最小的K个数.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import org.junit.Test; 4 | import java.util.TreeSet; 5 | import java.util.ArrayList; 6 | import java.util.Iterator; 7 | 8 | 9 | /** 10 | * Created by 周杰伦 on 2017/3/22. 11 | * 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 12 | */ 13 | public class 找出其中最小的K个数 { 14 | public ArrayList GetLeastNumbers_Solution(int [] input, int k) { 15 | 16 | ArrayListarrayList=new ArrayList<>(); 17 | if(input==null || input.length==0 ||k==0 ||k>input.length)return arrayList; 18 | 19 | TreeSet treeSet=new TreeSet<>(); 20 | 21 | 22 | for(int i=0;i l2 ?(l1 - l2):(l2 - l1); 26 | if (l1 < l2) { 27 | while (len > 0) { 28 | p1 = p1.next; 29 | len --; 30 | } 31 | } 32 | else if (l1 > l2) { 33 | while (len > 0) { 34 | p2 = p2.next; 35 | len --; 36 | } 37 | } 38 | while (p1 != null && p2 != null) { 39 | if (p1 == p2) { 40 | return p1; 41 | } 42 | p1 = p1.next; 43 | p2 = p2.next; 44 | } 45 | return null; 46 | } 47 | class ListNode { 48 | int val; 49 | ListNode next = null; 50 | 51 | ListNode(int val) { 52 | this.val = val; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Part2/ReverseList.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import ADT.ListNode; 4 | import org.junit.Test; 5 | 6 | import java.util.Arrays; 7 | 8 | /** 9 | * Created by 周杰伦 on 2017/3/21. 10 | * 题目描述 11 | 输入一个链表,反转链表后,输出链表的所有元素。 12 | */ 13 | public class ReverseList { 14 | public ListNode ReverseList(ListNode head) { 15 | if(head==null || head.next==null)return head; 16 | 17 | ListNode pre,next; 18 | pre=null; 19 | next=null; 20 | 21 | 22 | while(head!=null){ 23 | //保存下一个结点 24 | next=head.next; 25 | //连接下一个结点 26 | head.next=pre; 27 | pre=head; 28 | head=next; 29 | } 30 | return pre; 31 | 32 | 33 | } 34 | @Test 35 | public void test(){ 36 | ListNode node1=new ListNode(1); 37 | ListNode node2=new ListNode(2); 38 | ListNode node3=new ListNode(3); 39 | ListNode node4=new ListNode(3); 40 | ListNode node5=new ListNode(4); 41 | ListNode node6=new ListNode(4); 42 | ListNode node7=new ListNode(5); 43 | node1.next=node2; 44 | node2.next=node3; 45 | node3.next=node4; 46 | node4.next=node5; 47 | node5.next=node6; 48 | node6.next=node7; 49 | ListNode node=ReverseList(node1); 50 | while(node!=null){ 51 | System.out.println(node.val); 52 | node=node.next; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Part1/SecondArrayFind.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Created by 周杰伦 on 2018/2/25. 7 | * 题目描述 8 | 在一个二维数组中,每一行都按照从左到右递增的顺序排序, 9 | 每一列都按照从上到下递增的顺序排序。请完成一个函数, 10 | 输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 11 | 1 2 3 12 | 2 3 4 13 | 3 4 5 14 | */ 15 | public class SecondArrayFind { 16 | public static boolean Find(int target, int[][] array) { 17 | 18 | if(array[0][0] > target) { 19 | return false; 20 | } 21 | 22 | int row = 0; 23 | int col = 0; 24 | System.out.println(array.length); 25 | System.out.println(array[0].length); 26 | while (row < array.length && col >0) { 27 | if (target == array[row][col]) { 28 | return true; 29 | } 30 | else if (target array[row][col]) { 34 | col ++; 35 | } 36 | else row++; 37 | } 38 | return false; 39 | } 40 | 41 | public static void main(String[] args) { 42 | int [][] arr = new int[3][3]; 43 | arr[0][0] = 1; 44 | arr[0][1] = 2; 45 | arr[0][2] = 3; 46 | arr[1][0] = 2; 47 | arr[1][1] = 3; 48 | arr[1][2] = 4; 49 | arr[2][0] = 3; 50 | arr[2][1] = 4; 51 | arr[2][2] = 5; 52 | System.out.println(Find(2,arr)); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/Part2/判断B是不是A的子结构.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import ADT.TreeNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * Created by 周杰伦 on 2017/3/21. 8 | * 题目描述 9 | 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 10 | */ 11 | public class 判断B是不是A的子结构 { 12 | public boolean HasSubtree(TreeNode root1, TreeNode root2) { 13 | boolean hasleft=true; 14 | boolean hasright=true; 15 | 16 | if(root2==null &&root1!=null)return true; 17 | if(root2!=null &&root1==null)return false; 18 | 19 | if(root1.val==root2.val){ 20 | if(root2.left!=null) 21 | hasleft=HasSubtree(root1.left,root2.left); 22 | if(root2.right!=null) 23 | hasright=HasSubtree(root1.right,root2.right); 24 | 25 | if(hasleft && hasright)return true; 26 | 27 | } 28 | 29 | boolean left = HasSubtree(root1.left, root2); 30 | boolean right = HasSubtree(root1.right, root2); 31 | 32 | return left || right; 33 | 34 | 35 | } 36 | @Test 37 | public void test(){ 38 | TreeNode roota1=new TreeNode(8); 39 | TreeNode roota2=new TreeNode(8); 40 | TreeNode roota3=new TreeNode(7); 41 | TreeNode roota4=new TreeNode(9); 42 | TreeNode roota5=new TreeNode(2); 43 | TreeNode roota6=new TreeNode(4); 44 | TreeNode rootb1=new TreeNode(8); 45 | TreeNode rootb2=new TreeNode(9); 46 | TreeNode rootb3=new TreeNode(2); 47 | 48 | 49 | roota1.left=roota2; 50 | roota3.left=roota4; 51 | 52 | roota5.left=roota6; 53 | 54 | roota3.right=roota5; 55 | roota1.right=roota3; 56 | 57 | rootb1.left=rootb2; 58 | rootb1.right=rootb3; 59 | 60 | System.out.println(HasSubtree(roota1,rootb1)); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Part2/两个单调递增的链表合并.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import ADT.ListNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * Created by 周杰伦 on 2017/3/21. 8 | * 题目描述 9 | 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。 10 | */ 11 | public class 两个单调递增的链表合并 { 12 | public ListNode Merge(ListNode list1, ListNode list2) { 13 | if(list1==null)return list2; 14 | if(list2==null)return list1; 15 | ListNode head=new ListNode(-1); 16 | ListNode p=new ListNode(0),p1,p2; 17 | head=p; 18 | p1=list1; 19 | p2=list2; 20 | 21 | //p代表头结点,p1,p2分别遍历两个链表,接入较小值。 22 | //最后将p.next置为null,若还有链表剩余,直接连接其剩余部分即可。 23 | while(p1!=null && p2!=null){ 24 | if(p1.val<=p2.val){ 25 | p.next=p1; 26 | p1=p1.next; 27 | p=p.next; 28 | } 29 | else { 30 | p.next=p2; 31 | p2=p2.next; 32 | p=p.next; 33 | } 34 | p.next=null; 35 | if(p1!=null)p.next=p1; 36 | if(p2!=null)p.next=p2; 37 | 38 | } 39 | return head.next; 40 | } 41 | @Test 42 | public void test(){ 43 | ListNode node1=new ListNode(1); 44 | ListNode node2=new ListNode(2); 45 | ListNode node3=new ListNode(3); 46 | ListNode node4=new ListNode(3); 47 | ListNode node5=new ListNode(4); 48 | ListNode node6=new ListNode(4); 49 | ListNode node7=new ListNode(5); 50 | node1.next=node2; 51 | node2.next=node3; 52 | node3.next=node4; 53 | 54 | node5.next=node6; 55 | node6.next=node7; 56 | ListNode node=Merge(node1,node5); 57 | while(node!=null){ 58 | System.out.println(node.val); 59 | node=node.next; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Part2/奇数在前偶数在后.java: -------------------------------------------------------------------------------- 1 | package Part2; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.AbstractCollection; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * Created by 周杰伦 on 2017/3/20. 11 | * 题目描述 12 | 输入一个整数数组,实现一个函数来调整该数组中数字的顺序, 13 | 使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分, 14 | 并保证奇数和奇数,偶数和偶数之间的相对位置不变。 15 | */ 16 | public class 奇数在前偶数在后 { 17 | public void reOrderArray(int[] array) { 18 | ArrayList arrayList1=new ArrayList<>(); 19 | ArrayList arrayList2=new ArrayList<>(); 20 | for(int i=0;i=arrayList1.size()) 30 | array[i]= arrayList2.get(i-arrayList1.size()); 31 | } 32 | 33 | 34 | } 35 | @Test 36 | public void test(){ 37 | int []a={3,4,1,6,8,2,5}; 38 | reOrderArray(a); 39 | System.out.println(Arrays.toString(a)); 40 | } 41 | // public void reOrderArray(int[] array) { 42 | // 43 | // if(array==null || array.length==0)return; 44 | // 45 | // int left=0,right=array.length-1; 46 | // int temp; 47 | // while (left2->3->3->4->4->5 处理后为 1->2->5 14 | */ 15 | public class deleteDuplication { 16 | public static ListNode deleteDuplication(ListNode pHead) { 17 | ListNode first = new ListNode(-1);//设置一个trick   18 | first.next = pHead;//可能删除链表中的每个节点,需要使用头结点。 19 | ListNode p = pHead;//用p遍历链表。 20 | ListNode last = first;//用last串联链表 21 | while (p != null && p.next != null) { 22 | if (p.val == p.next.val) { 23 | int val = p.val; 24 | while (p != null && p.val == val) 25 | p = p.next;//删除重复元素 26 | last.next = p;//指向一个新元素。 27 | } else { 28 | last = p;//若不重复,则last指向当前结点,再与后面结点进行串联。 29 | p = p.next; 30 | } 31 | 32 | } 33 | return first.next; 34 | } 35 | 36 | 37 | 38 | 39 | @Test 40 | public void test(){ 41 | ListNode node1=new ListNode(1); 42 | ListNode node2=new ListNode(2); 43 | ListNode node3=new ListNode(3); 44 | ListNode node4=new ListNode(3); 45 | ListNode node5=new ListNode(4); 46 | ListNode node6=new ListNode(4); 47 | ListNode node7=new ListNode(5); 48 | node1.next=node2; 49 | node2.next=node3; 50 | node3.next=node4; 51 | node4.next=node5; 52 | node5.next=node6; 53 | node6.next=node7; 54 | 55 | ListNode node= deleteDuplication(node1); 56 | 57 | while(node!=null) 58 | { 59 | System.out.println(node.val); 60 | node=node.next; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Part1/EntryNodeOfLoop.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import ADT.ListNode; 4 | import org.junit.Test; 5 | 6 | /** 7 | * Created by 周杰伦 on 2017/3/20. 8 | * 一个链表中包含环,请找出该链表的环的入口结点。 9 | * 先算出环中结点个数,让两个指针一起前进,一个先走环的结点个数的步长,当他们相遇时就是入口。 10 | */ 11 | public class EntryNodeOfLoop { 12 | public ListNode EntryNodeOfLoop(ListNode pHead) 13 | { 14 | if(pHead==null || pHead.next==null)return null; 15 | 16 | ListNode meetingNode=getMeetingNode(pHead); 17 | if(meetingNode==null)return null; 18 | else { 19 | int count=1; 20 | ListNode slow=meetingNode.next; 21 | ListNode fast=pHead; 22 | while (slow!=meetingNode) 23 | { 24 | slow=slow.next; 25 | ++count; 26 | } 27 | slow=pHead; 28 | for (int i = 1; i <= count; i++) { 29 | slow=slow.next; 30 | } 31 | 32 | while (fast!=slow) { 33 | if(slow!=null) 34 | slow = slow.next; 35 | if(fast!=null) 36 | fast = fast.next; 37 | } 38 | if(fast==null || slow==null)return null; 39 | else return fast; 40 | 41 | } 42 | } 43 | 44 | public ListNode getMeetingNode(ListNode pHead){ 45 | 46 | if(pHead==null)return null; 47 | 48 | ListNode slow=pHead.next; 49 | if(slow==null)return null; 50 | ListNode fast=slow.next; 51 | 52 | while(fast!=null && slow!=null){ 53 | if(fast==slow)return slow; 54 | 55 | slow=slow.next; 56 | fast=fast.next; 57 | 58 | if(fast!=null){ 59 | fast=fast.next; 60 | } 61 | } 62 | return null; 63 | 64 | } 65 | 66 | @Test 67 | public void test(){ 68 | EntryNodeOfLoop(new ListNode(0)); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/Part1/GetNumberOfK.java: -------------------------------------------------------------------------------- 1 | package Part1; 2 | 3 | import java.util.Arrays; 4 | import java.util.HashMap; 5 | 6 | /** 7 | * Created by 周杰伦 on 2017/3/20. 8 | * 题目描述 9 | 统计一个数字在排序数组中出现的次数。 10 | */ 11 | public class GetNumberOfK { 12 | public int GetNumberOfK(int [] array , int k) { 13 | int count=0; 14 | for(int i=0;ik){ 32 | leftarr= Arrays.copyOfRange(array,0,len/2-1); 33 | count=GetNumberOfK(leftarr,k); 34 | } 35 | //k>中间数时,说明k在数组左半边。于是统计左半边数组的k的个数。 36 | if(num=0;i--){ 18 | o.append(a[i]); 19 | if(i>0)o.append(" "); 20 | } 21 | return o.toString(); 22 | // 23 | // Stack stack=new Stack<>(); 24 | // int start=0; 25 | // int flag=0; 26 | // char []chararr=str.toCharArray(); 27 | // System.out.println(chararr[0]); 28 | // for(int i=0;i=right) 28 | return ; 29 | int p=left,q=mid+1,k=0; 30 | 31 | int []temp=new int[right-left+1]; 32 | 33 | while (p<=mid && q<=right){ 34 | if(array[p]>array[q]){ 35 | temp[k++]=array[q++]; 36 | //当前半数组中有一个数p比后半个数组中的一个数q大时,由于两个数组 37 | //已经分别有序,所以说明p到中间数之间的所有数都比q大。 38 | Pairs+=mid-p+1; 39 | } 40 | else temp[k++]=array[p++]; 41 | } 42 | 43 | while (p<=mid){ 44 | temp[k++]=array[p++];} 45 | while (q<=right){ 46 | temp[k++]=array[q++];} 47 | 48 | 49 | 50 | for (int m = 0; m < temp.length; m++) 51 | array[left + m] = temp[m]; 52 | 53 | } 54 | 55 | public void mergesort(int []arr,int left,int right){ 56 | if (arr.length==0 ||arr==null) 57 | return ; 58 | int mid=(right+left)/2; 59 | if(left 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 节选剑指offer比较经典和巧妙的一些题目,以便复习使用。一部分题目给出了完整代码,一部分题目比较简单直接给出思路。但是不保证我说的思路都是正确的,个人对算法也不是特别在行,只不过这本书的算法多看了几遍多做了几遍多了点心得体会。于是想总结一下。如果有错误也希望能指出,谢谢。 2 | ## 具体代码可以参考我的GitHub仓库: 3 | ## https://github.com/h2pl/SwordToOffer 4 | 5 | 节选剑指offer比较经典和巧妙的一些题目,以便复习使用。 6 | 7 | # 数论和数字规律 8 | 9 | ## 从1到n整数中1出现的次数 10 | 11 | 题目描述 12 | 求出1-13的整数中1出现的次数,并算出100-1300的整数中1出现的次数?为此他特别数了一下1-13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。 13 | 14 | 1暴力办法,把整数转为字符串,依次枚举相加。复杂度是O(N * k)k为数字长度。 15 | 16 | 2第二种办法看不懂,需要数学推导,太长不看 17 | 18 | ## 排数组排成最小的数 19 | 20 | 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。 21 | 22 | 解析:本题的关键是,两个数如何排成最小的,答案是,如果把数字看成字符串a,b那么如果a+b>b+a,则a应该放在b后面。 23 | 例如 3和32 3 + 32 = 332,32 + 3 = 323,332>323,所以32要放在前面。 24 | 25 | 根据这个规律,构造一个比较器,使用排序方法即可。 26 | 27 | ## 丑数 28 | 29 | 题目描述 30 | 把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 31 | 32 | 解析 33 | 34 | 1 暴力枚举每个丑数,找出第N个即可。 35 | 36 | 2 这个思路比较巧妙,由于丑数一定是由2,3,5三个因子构成的,所以我们每次构造出一个比前面丑数大但是比后面小的丑数,构造N次即可。 37 | public class Solution { 38 | public static int GetUglyNumber_Solution(int index) { 39 | if (index == 0) return 0; 40 | int []res = new int[index]; 41 | res[0] = 1; 42 | int i2,i3,i5; 43 | i2 = i3 = i5 = 0; 44 | for (int i = 1;i < index;i ++) { 45 | res[i] = Math.min(res[i2] * 2, Math.min(res[i3] * 3, res[i5] * 5)); 46 | if (res[i] == res[i2] * 2) i2 ++; 47 | if (res[i] == res[i3] * 3) i3 ++; 48 | if (res[i] == res[i5] * 5) i5 ++; 49 | } 50 | return res[index - 1]; 51 | } 52 | } 53 | } 54 | 55 | i2,i3,i5分别代表目前有几个2,3,5的因子,每次选一个最小的丑数,然后开始找下一个。当然i2,i3,i5也要跟着变。 56 | # 数组和矩阵 57 | 58 | 59 | ## 二维数组的查找 60 | 61 | /** 62 | * Created by 周杰伦 on 2018/2/25. 63 | * 题目描述 64 | 在一个二维数组中,每一行都按照从左到右递增的顺序排序, 65 | 每一列都按照从上到下递增的顺序排序。请完成一个函数, 66 | 输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 67 | 1 2 3 68 | 2 3 4 69 | 3 4 5 70 | */ 71 | 72 | 解析:比较经典的一题,解法也比较巧妙,由于数组从左向右和从上到下的都是递增的,所以找一个数可以先从最右开始找。 73 | 假设最右值为a,待查数为x,那么如果x < a说明x在a的左边,往左找即可,如果x > a,说明x 在 a的下面一行,到下面一行继续按照该规则查找,就可以遍历所有数。 74 | 75 | 算法的时间复杂度是O(M * N) 76 | 77 | public class 二维数组中的查找 { 78 | public static boolean Find(int target, int[][] array) { 79 | 80 | if(array[0][0] > target) { 81 | return false; 82 | } 83 | 84 | int row = 0; 85 | int col = 0; 86 | while (row < array.length && col >0) { 87 | if (target == array[row][col]) { 88 | return true; 89 | } 90 | else if (target array[row][col]) { 94 | col ++; 95 | } 96 | else row++; 97 | } 98 | return false; 99 | } 100 | } 101 | ## 顺时针打印矩阵。 102 | 103 | 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10. 104 | 105 | 这题还是有点麻烦的,因为要顺时针打印,所以实际上是由外向内打印,边界的处理和递归调用需要谨慎。 106 | 107 | 这题我自己没写出标准答案。参考一个答案吧。关键在于四个循环中的分界点设置。 108 | 109 | //主体循环部分才5行。其实是有规律可循的。将每一层的四个边角搞清楚就可以打印出来了 110 | 111 | import java.util.ArrayList; 112 | public class Solution { 113 |     public ArrayList printMatrix(int [][] array) { 114 |         ArrayList result = new ArrayList (); 115 |         if(array.length==0) return result; 116 |         int n = array.length,m = array[0].length; 117 |         if(m==0) return result; 118 |         int layers = (Math.min(n,m)-1)/2+1;//这个是层数 119 |         for(int i=0;i=i)&&(n-i-1!=i);k--) result.add(array[n-i-1][k]);//右至左 123 |             for(int j=n-i-2;(j>i)&&(m-i-1!=i);j--) result.add(array[j][i]);//左下至左上 124 |         } 125 |         return result;        126 |     } 127 | } 128 | 129 | ## 调整数组中数字的顺序,使正数在负数的前面 130 | 131 | 双指针即可以解决,变式有正负,奇偶等等。 132 | 133 | ## 数组中出现次数超过一半的数字 134 | 135 | 本题有很多种解法。 136 | 137 | 1 最笨的解法,统计每个数的出现次数,O(n2) 138 | 139 | 2 使用hashmap,空间换时间O(n) 140 | 141 | 3 由于出现超过一半的数字一定也是中位数,所以可以先排序,再找到第n/2位置上的节点。 142 | 143 | 4 使用快速排序的复杂度是O(nlogn),基于快排的特性,每一轮的过程都会把一个数放到最终位置,所以我们可以判断一下这个数的位置是不是n/2,如果是的话,那么就直接返回即可。这样就优化了快排的步骤。 144 | 145 | 4.5事实上,上述办法的复杂度仍然是O(nlogn) 146 | 147 | 快速排序的partition函数将一个数组分为左右两边,并且我们可以知道,如果flag值在k位置左边,那么往左找,如果在k位置右边,那么往左找。 148 | 149 | 这里科普一下经典快排中的一个方法partition,剑指offer书中直接跳过了这部分,让我摸不着头脑。 150 | 151 | 虽然快排用到了经典的分而治之的思想,但是快排实现的前提还是在于 partition 函数。正是有了 partition 的存在,才使得可以将整个大问题进行划分,进而分别进行处理。 152 | 153 | 除了用来进行快速排序,partition 还可以用 O(N) 的平均时间复杂度从无序数组中寻找第K大的值。和快排一样,这里也用到了分而治之的思想。首先用 partition 将数组分为两部分,得到分界点下标 pos,然后分三种情况: 154 | 155 | pos == k-1,则找到第 K 大的值,arr[pos]; 156 | pos > k-1,则第 K 大的值在左边部分的数组。 157 | pos < k-1,则第 K 大的值在右边部分的数组。 158 | 下面给出基于迭代的实现(用来寻找第 K 小的数): 159 | 160 | 161 | int find_kth_number(vector &arr, int k){ 162 | int begin = 0, end = arr.size(); 163 | assert(k>0 && k<=end); 164 | int target_num = 0; 165 | while (begin < end){ 166 | int pos = partition(arr, begin, end); 167 | if(pos == k-1){ 168 | target_num = arr[pos]; 169 | break; 170 | } 171 | else if(pos > k-1){ 172 | end = pos; 173 | } 174 | else{ 175 | begin = pos + 1; 176 | } 177 | } 178 | return target_num; 179 | } 180 | 181 | 182 | 该算法的时间复杂度是多少呢?考虑最坏情况下,每次 partition 将数组分为长度为 N-1 和 1 的两部分,然后在长的一边继续寻找第 K 大,此时时间复杂度为 O(N^2 )。不过如果在开始之前将数组进行随机打乱,那么可以尽量避免最坏情况的出现。而在最好情况下,每次将数组均分为长度相同的两半,运行时间 T(N) = N + T(N/2),时间复杂度是 O(N)。 183 | 184 | 所以也就是说,本题用这个方法解的话,复杂度只需要O(n),因为第一次交换需要N/2,j接下来的交换的次数越来越少,最后加起来就是O(N)了。 185 | 186 | 5 由于数字出现次数超过长度的一半,也就是平均每两个数字就有一个该数字,但他们不一定连续,所以变量time保存一个数的出现次数,然后变量x代表目前选择的数字,遍历中,如果x与后一位不相等则time--,time=0时x改为后一位,time重新变为1。最终x指向的数字就是出现次数最多的。 187 | 188 | 举两个例子,比如1,2,3,4,5,6,6,6,6,6,6。明显符合。1,6,2,6,3,6,4,6,5,6,6 遍历到最后得到x=6,以此类推,可以满足要求。 189 | 190 | ## 找出前k小的数 191 | * 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 192 | */ 193 | 194 | 解析: 195 | 196 | 1如果允许改变数组,那么则可以继承上一题的思想。,使用快速排序中的partition方法,只需要O(N)的复杂度 197 | 198 | 2使用堆排序 199 | 200 | 解析:用前k个数构造一个大小为k的大顶堆,然后遍历余下数字,如果比堆顶大,则跳过,如果比堆顶小,则替换掉堆顶元素,然后执行一次堆排序(即根节点向下调整)。此时的堆顶元素已被替换, 201 | 202 | 然后遍历完所有元素,堆中的元素就是最小的k个元素了。 203 | 204 | 如果要求最大的k个元素,则构造小顶堆就可以了。 205 | 206 | 构造堆的方法是,数组的第N/2号元素到0号元素依次向下调整,此时数组就构成了堆。 207 | 208 | 实际上我们可以使用现成的集合类,红黑树是一棵搜索树,他是排序的,所以可以得到最大和最小值,那么我们每次和最小值比较,符合条件就进行替换即可。复杂度是O(nlogn) 209 | 210 | 211 | public ArrayList GetLeastNumbers_Solution(int [] input, int k) { 212 | 213 | ArrayListarrayList=new ArrayList<>(); 214 | if(input==null || input.length==0 ||k==0 ||k>input.length)return arrayList; 215 | 216 | TreeSet treeSet=new TreeSet<>(); 217 | 218 | 219 | for(int i=0;i 0) 287 | 288 | 289 | ## 逆序对 290 | 291 | /** 292 | * Created by 周杰伦 on 2017/3/23. 293 | * 题目描述 294 | 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。 295 | 输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 296 | 即输出P%1000000007 297 | */ 298 | 299 | 解析:本题采用归并排序的框架,只是在归并的时候做出逆序对查找,具体参见下面代码。 300 | 核心点是,在归并两个有序数组时,如果a数组的元素a1比b数组的元素b1大时,说明有mid - i + 1个数都比b1大。i为a1元素的位置。 301 | 这样子我们就可以统计逆序对的个数了。经典巧妙。! 302 | 303 | public class 逆序对 { 304 | public double Pairs = 0; 305 | public int InversePairs(int [] array) { 306 | if (array.length==0 ||array==null) 307 | return 0; 308 | mergesort(array,0,array.length-1); 309 | Pairs = Pairs + 1000000007; 310 | return (int) (Pairs % 1000000007); 311 | } 312 | public void merge(int []array,int left,int mid,int right){ 313 | //有一点很重要的是,归并分成两部分,其中一段是left到mid,第二段是mid+1到right。 314 | //不能从0到mid-1,然后mid到right。因为这样左右不均分,会出错。千万注意。 315 | //mid=(left+right)/2 316 | if (array.length==0 ||array==null ||left>=right) 317 | return ; 318 | int p=left,q=mid+1,k=0; 319 | 320 | int []temp=new int[right-left+1]; 321 | 322 | while (p<=mid && q<=right){ 323 | if(array[p]>array[q]){ 324 | temp[k++]=array[q++]; 325 | //当前半数组中有一个数p比后半个数组中的一个数q大时,由于两个数组 326 | //已经分别有序,所以说明p到中间数之间的所有数都比q大。 327 | Pairs+=mid-p+1; 328 | } 329 | else temp[k++]=array[p++]; 330 | } 331 | 332 | while (p<=mid){ 333 | temp[k++]=array[p++];} 334 | while (q<=right){ 335 | temp[k++]=array[q++];} 336 | 337 | 338 | 339 | for (int m = 0; m < temp.length; m++) 340 | array[left + m] = temp[m]; 341 | 342 | } 343 | 344 | public void mergesort(int []arr,int left,int right){ 345 | if (arr.length==0 ||arr==null) 346 | return ; 347 | int mid=(right+left)/2; 348 | if(left list = new ArrayList<>(); 462 | public static void Insert(Integer num) { 463 | list.add(num); 464 | Collections.sort(list); 465 | } 466 | 467 | public static Double GetMedian() { 468 | if (list.size() % 2 == 0) { 469 | int l = list.get(list.size()/2); 470 | int r = list.get(list.size()/2 - 1); 471 | return (l + r)/2.0; 472 | } 473 | else { 474 | return list.get(list.size()/2)/1.0; 475 | } 476 | } 477 | 478 | 479 | } 480 | 481 | ## 滑动窗口中的最大值 482 | 483 | 给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。 484 | 485 | 解析: 486 | 1 保持窗口为3进行右移,每次计算出一个最大值即可。 487 | 488 | 2 使用两个栈实现一个队列,复杂度O(N),使用两个栈实现最大值栈,复杂度O(1)。两者结合可以完成本题。但是太麻烦了。 489 | 490 | 3 使用双端队列解决该问题。 491 | 492 | import java.util.*; 493 | /** 494 | 用一个双端队列,队列第一个位置(队头)保存当前窗口的最大值,当窗口滑动一次 495 | 1.判断当前最大值是否过期(如果最大值所在的下标已经不在窗口范围内,则过期) 496 | 2.对于一个新加入的值,首先一定要先放入队列,即使他比队头元素小,因为队头元素可能过期。 497 | 3.新增加的值从队尾开始比较,把所有比他小的值丢掉(因为队列只存最大值,所以之前比他小的可以丢掉) 498 | 499 | */ 500 | public class Solution { 501 |    public ArrayList maxInWindows(int [] num, int size) 502 |     { 503 |         ArrayList res = new ArrayList<>(); 504 |         if(size == 0) return res; 505 |         int begin;  506 |         ArrayDeque q = new ArrayDeque<>(); 507 |         for(int i = 0; i < num.length; i++){ 508 |             begin = i - size + 1; 509 |             if(q.isEmpty()) 510 |                 q.add(i); 511 |             else if(begin > q.peekFirst()) 512 |                 q.pollFirst(); 513 |           514 |             while((!q.isEmpty()) && num[q.peekLast()] <= num[i]) 515 |                 q.pollLast(); 516 |             q.add(i);   517 |             if(begin >= 0) 518 |                 res.add(num[q.peekFirst()]); 519 |         } 520 |         return res; 521 |     } 522 | } 523 | 524 | # 字符串 525 | 526 | ## 字符串的排列 527 | 528 | 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 529 | 530 | 解析:这是一个全排列问题,也就是N个不同的数排成所有不同的序列,只不过把数换成了字符串。 531 | 全排列的过程就是,第一个元素与后续的某个元素交换,然后第二个元素也这么做,直到最后一个元素为之,过程是一个递归的过程,也是一个dfs的过程。 532 | 533 | 注意元素也要和自己做一次交换,要不然会漏掉自己作为头部的情况。 534 | 535 | 然后再进行一次字典序的排序即可。 536 | 537 | public static ArrayList Permutation(String str) { 538 | char []arr = str.toCharArray(); 539 | List list = new ArrayList<>(); 540 | all(arr, 0, arr.length - 1, list); 541 | Collections.sort(list, (o1, o2) -> String.valueOf(o1).compareTo(String.valueOf(o2))); 542 | ArrayList res = new ArrayList<>(); 543 | for (char[] c : list) { 544 | if (!res.contains(String.valueOf(c))) 545 | res.add(String.valueOf(c)); 546 | } 547 | return res; 548 | } 549 | 550 | //注意要换完为之,因为每换一次可以去掉头部一个数字,这样可以避免重复 551 | public static void all(char []arr, int cur, int end, List list) { 552 | if (cur == end) { 553 | // System.out.println(Arrays.toString(arr)); 554 | list.add(Arrays.copyOf(arr, arr.length)); 555 | } 556 | for (int i = cur;i <= end;i ++) { 557 | //这里的交换包括跟自己换,所以只有一轮换完才能确定一个结果 558 | swap(arr, cur, i); 559 | all(arr, cur + 1, end, list); 560 | swap(arr, cur, i); 561 | } 562 | } 563 | public static void swap(char []arr, int i, int j) { 564 | if (i > arr.length || j > arr.length || i >= j)return; 565 | char temp = arr[i]; 566 | arr[i] = arr[j]; 567 | arr[j] = temp; 568 | } 569 | 570 | ## 替换空格 571 | 572 | /** 573 | * Created by 周杰伦 on 2018/2/25. 574 | * 请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 575 | */ 576 | 577 | 解析:如果单纯地按顺序替换空格,每次替换完还要将数组扩容,再右移,这部操作的时间复杂度就是O(2*N)=O(N),所以总的复杂度是O(n^2),所以应该采取先扩容的办法,统计出空格数,然后扩容,接下来按顺序添加字符,遇到空格直接改成添加%20即可,这样避免了右移操作和多次扩容,复杂度是O(N) 578 | 579 | 580 | public class 替换空格 { 581 | public static String replaceSpace(StringBuffer str) { 582 | int newlen = 0; 583 | for(int i = 0; i < str.length(); i++) { 584 | if(str.charAt(i) == ' ') { 585 | newlen = newlen + 3; 586 | } 587 | else { 588 | newlen ++; 589 | } 590 | } 591 | char []newstr = new char[newlen]; 592 | int j = 0; 593 | for(int i = 0 ; i < str.length(); i++) { 594 | if (str.charAt(i) == ' ') { 595 | newstr[j++] = '%'; 596 | newstr[j++] = '2'; 597 | newstr[j++] = '0'; 598 | }else { 599 | newstr[j++] = str.charAt(i); 600 | } 601 | } 602 | return String.valueOf(newstr); 603 | } 604 | 605 | 606 | ## 第一次只出现一次的字符 607 | 608 | 哈希表可解 609 | 610 | ## 翻转单词顺序和左旋转字符串 611 | 612 | 1 613 | 题目描述 614 | 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么? 615 | 616 | 这个解法很经典,先把每个单词逆序,再把整个字符串逆序,结果就是把每个单词都进行了翻转。 617 | 618 | 2 619 | 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它! 620 | 621 | 字符串循环左移N位的处理方法也很经典,先把前N位逆序,再把剩余字符串逆序,最后整体逆序。 622 | 623 | abcXYZdef -> cbafedZYX -> XYZdefabc 624 | 625 | ## 把字符串转换为整数 626 | 627 | 题目描述 628 | 将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0 629 | 630 | 解析:首先需要判断正负号,然后判断每一位是否是数字,然后判断是否溢出,判断溢出可以通过加完第n位的和与未加第n位的和进行比较。最后可以得出结果。所以需要3-4步判断。 631 | 632 | 633 | ## 表示数值的字符串 634 | 635 | 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。 636 | 637 | 不得不说这种题型太恶心了,就是需要一直判断边界条件 638 | 639 | 参考一个答案。比较完整 640 | 641 |     bool isNumeric(char* str) { 642 |         // 标记符号、小数点、e是否出现过 643 |         bool sign = false, decimal = false, hasE = false; 644 |         for (int i = 0; i < strlen(str); i++) { 645 |             if (str[i] == 'e' || str[i] == 'E') { 646 |                 if (i == strlen(str)-1) return false; // e后面一定要接数字 647 |                 if (hasE) return false;  // 不能同时存在两个e 648 |                 hasE = true; 649 |             } else if (str[i] == '+' || str[i] == '-') { 650 |                 // 第二次出现+-符号,则必须紧接在e之后 651 |                 if (sign && str[i-1] != 'e' && str[i-1] != 'E') return false; 652 |                 // 第一次出现+-符号,且不是在字符串开头,则也必须紧接在e之后 653 |                 if (!sign && i > 0 && str[i-1] != 'e' && str[i-1] != 'E') return false; 654 |                 sign = true; 655 |             } else if (str[i] == '.') { 656 |               // e后面不能接小数点,小数点不能出现两次 657 |                 if (hasE || decimal) return false; 658 |                 decimal = true; 659 |             } else if (str[i] < '0' || str[i] > '9') // 不合法字符 660 |                 return false; 661 |         } 662 |         return true; 663 |     } 664 | 665 | ## 字符流中第一个不重复的字符 666 | 667 | 题目描述 668 | 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。 669 | 670 | 本题主要要注意的是流。也就是说每次输入一个字符就要做一次判断。比如输入aaaabbbcd,输出就是a###b##cd 671 | 672 | StringBuilder sb = new StringBuilder(); 673 | int []map = new int[256]; 674 | public void Insert(char ch) 675 | { 676 | sb.append(ch); 677 | if (map[ch] == 0) { 678 | map[ch] = 1; 679 | }else { 680 | map[ch] ++; 681 | } 682 | System.out.println(FirstAppearingOnce()); 683 | 684 | } 685 | //return the first appearence once char in current stringstream 686 | public char FirstAppearingOnce() 687 | { 688 | for (int i = 0;i < sb.length();i ++) { 689 | if (map[sb.charAt(i)] == 1) { 690 | return sb.charAt(i); 691 | } 692 | } 693 | return '#'; 694 | } 695 | 696 | # 链表 697 | 698 | ## 从尾到头打印链表 699 | 700 | 考查递归,递归可以使输出的顺序倒置 701 | 702 | public static void printReverse(Node node) { 703 | if (node.next != null) { 704 | printReverse(node.next); 705 | } 706 | System.out.print(node.val + " "); 707 | } 708 | 709 | 710 | ## 链表倒数第k个节点 711 | 712 | 使用两个指针,一个先走k步。然后一起走即可。 713 | 714 | ## 反转链表 715 | 716 | 老生常谈,但是容易写错。 717 | 718 | public ListNode ReverseList(ListNode head) { 719 | if(head==null || head.next==null)return head; 720 | ListNode pre,next; 721 | pre=null; 722 | next=null; 723 | while(head!=null){ 724 | //保存下一个结点 725 | next=head.next; 726 | //连接下一个结点 727 | head.next=pre; 728 | pre=head; 729 | head=next; 730 | } 731 | return pre; 732 | } 733 | } 734 | 735 | ## 合并两个排序链表 736 | 737 | 与归并排序的合并类似 738 | 739 | ## 复杂链表的复制 740 | 741 | 题目描述 742 | 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 743 | 744 | 这题比较恶心。 745 | 746 | 解析: 747 | 748 | 1 直接复制链表,然后再去复制特殊指针,复杂度是O(n2) 749 | 750 | 2 使用hash表保存特殊指针的映射关系,第二步简化操作,复杂度是O(n) 751 | 752 | 3 复制每个节点并且连成一个大链表A-A'-B-B',然后从头到尾判断特殊指针,如果有特殊指针,则让后续节点的特殊指针指向原节点特殊指针指向的节点的后置节点,晕了吧,其实就是原来是A指向B,现在是A’指向B‘。 753 | 754 | 最后我们根据奇偶序号把链表拆开,复杂度是O(N)且不用额外空间。 755 | 756 | ## 两个链表的第一个公共节点 757 | 758 | 1 逆置链表,反向找第一个不同节点,前一个就是公共节点 759 | 760 | 2 求长度并相减得n,短的链表先走n步,然后一起走即可。 761 | 762 | ## 孩子们的游戏(圆圈中最后剩下的数) 763 | 764 | 这是一个约瑟夫环问题。 765 | 766 | 1 使用循环链表求解,每次走n步摘取一个节点,然后继续,直到最后一个节点就是剩下的数,空间复杂度为O(n) 767 | 768 | 2 使用数组来做 769 | public static int LastRemaining_Solution(int n, int m) { 770 | int []arr = new int[n]; 771 | for (int i = 0;i < n;i ++) { 772 | arr[i] = i; 773 | } 774 | 775 | int cnt = 0; 776 | int sum = 0; 777 | for (int i = 0;i < n;i = (i + 1) % n) { 778 | if (arr[i] == -1) { 779 | continue; 780 | } 781 | cnt ++; 782 | if (cnt == m) { 783 | arr[i] = -1; 784 | cnt = 0; 785 | sum ++; 786 | } 787 | if (sum == n) { 788 | return i; 789 | } 790 | } 791 | return n - 1; 792 | } 793 | 794 | 3 使用余数法求解 795 | 796 | 797 | int LastRemaining_Solution(int n, int m) { 798 |         if (m == 0 || n == 0) { 799 |             return -1; 800 |         } 801 |         ArrayList data = new ArrayList(); 802 |         for (int i = 0; i < n; i++) { 803 |             data.add(i); 804 |         } 805 |         int index = -1; 806 |         while (data.size() > 1) { 807 | //          System.out.println(data); 808 |             index = (index + m) % data.size(); 809 | //          System.out.println(data.get(index)); 810 |             data.remove(index); 811 |             index--; 812 |         } 813 |         return data.get(0); 814 |     } 815 | 816 | ## 链表的环的入口结点 817 | 818 | 一个链表中包含环,请找出该链表的环的入口结点。 819 | 820 | 解析: 821 | 822 | 1 指定两个指针,一个一次走两步,一个一次走一步,然后当两个节点相遇时,这个节点必定在环中。既然这个节点在环中,那么让这个节点走一圈直到与自己相等为之,可以得到环的长度n。 823 | 824 | 2 得到了环的长度以后,根据数学推导的结果,我们可以指定两个指针,一个先走n步,然后两者同时走,这样的话,当慢节点到达入口节点时,快节点也转了一圈刚好又到达入口节点,所以也就是他们相等的时候就是入口节点了。 825 | 826 | ## 删除链表中重复的节点 827 | 828 | 题目描述 829 | 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 830 | 831 | 保留头结点,然后找到下一个不重复的节点,与他相连,重复的节点直接跳过即可。 832 | 833 | #二叉树 834 | 835 | ## 二叉搜索树转换为双向链表 836 | 837 | 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 838 | 839 | 二叉搜索树要转换成有序的双向链表,实际上就是使用中序遍历把节点连入链表中,并且题目要求在原来节点上进行操作,也就是使用左指针和右指针表示链表的前置节点和后置节点。 840 | 841 | 使用栈实现中序遍历的非递归算法,便可以找出节点的先后关系,依次连接即可。 842 | 843 | public TreeNode Convert(TreeNode root) { 844 | if(root==null) 845 | return null; 846 | Stack stack = new Stack(); 847 | TreeNode p = root; 848 | TreeNode pre = null;// 用于保存中序遍历序列的上一节点 849 | boolean isFirst = true; 850 | while(p!=null||!stack.isEmpty()){ 851 | while(p!=null){ 852 | stack.push(p); 853 | p = p.left; 854 | } 855 | p = stack.pop(); 856 | if(isFirst){ 857 | root = p;// 将中序遍历序列中的第一个节点记为root 858 | pre = root; 859 | isFirst = false; 860 | }else{ 861 | pre.right = p; 862 | p.left = pre; 863 | pre = p; 864 | } 865 | p = p.right; 866 | } 867 | return root; 868 | } 869 | } 870 | 871 | ## 重建二叉树 872 | 873 | * 题目描述 874 | 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 875 | */ 876 | 877 | 解析:首先,头结点一定是先序遍历的首位,并且该节点把中序分为左右子树,根据这个规则,左子树由左边数组来完成,右子树由右边数组来完成,根节点由中间节点来构建,于是便有了如下的递归代码。该题的难点就在于边界的判断。 878 | 879 | public TreeNode reConstructBinaryTree(int [] pre, int [] in) { 880 | if(pre.length == 0||in.length == 0){ 881 | return null; 882 | } 883 | TreeNode node = new TreeNode(pre[0]); 884 | for(int i = 0; i < in.length; i++){ 885 | if(pre[0] == in[i]){ 886 | node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0, i));//为什么不是i和i-1呢,因为要避免出错,中序找的元素需要再用一次。 887 | node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1,in.length)); 888 | } 889 | } 890 | return node; 891 | } 892 | 893 | ## 树的子结构 894 | 895 | /** 896 | * Created by 周杰伦 on 2018/3/27. 897 | * 输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构) 898 | */ 899 | 900 | 解析:本题还是有点难度的,子结构要求节点完全相同,所以先判断节点是否相同,然后使用先序遍历进行递判断,判断的依据是如果子树为空,则说明节点都找到了,如果原树节点为空,说明找不到对应节点,接着递归地判断该节点的左右子树是否符合要求. 901 | 902 | public class 树的子结构 { 903 | 904 | public boolean HasSubtree(TreeNode root1, TreeNode root2) { 905 | boolean res = false; 906 | if (root1 != null && root2 != null) { 907 | if (root1.val == root2.val) { 908 | res = aHasb(root1, root2); 909 | } 910 | if (res == false) { 911 | res = HasSubtree(root1.left,root2); 912 | } 913 | if (res == false) { 914 | res = HasSubtree(root1.right,root2); 915 | } 916 | return res; 917 | } 918 | else return false; 919 | } 920 | public boolean aHasb(TreeNode t1, TreeNode t2){ 921 | if (t2 == null) return true; 922 | if (t1 == null) return false; 923 | if (t1.val != t2.val) return false; 924 | 925 | return aHasb(t1.left,t2.left) && aHasb(t1.right,t2.right); 926 | } 927 | } 928 | 929 | 930 | ## 镜像二叉树 931 | 932 | /** 933 | * Created by 周杰伦 on 2017/3/19.操作给定的二叉树,将其变换为源二叉树的镜像。 934 | 输入描述: 935 | 二叉树的镜像定义:源二叉树 936 | 8 937 | / \ 938 | 6 10 939 | / \ / \ 940 | 5 7 9 11 941 | 镜像二叉树 942 | 8 943 | / \ 944 | 10 6 945 | / \ / \ 946 | 11 9 7 5 947 | */ 948 | 949 | 950 | 解析:其实镜像二叉树就是交换所有节点的左右子树,所以使用遍历并且进行交换即可。 951 | 952 | /** 953 | public class TreeNode { 954 | int val = 0; 955 | TreeNode left = null; 956 | TreeNode right = null; 957 | 958 | public TreeNode(int val) { 959 | this.val = val; 960 | 961 | } 962 | 963 | } 964 | */ 965 | public class 镜像二叉树 { 966 | public void Mirror(TreeNode root) { 967 | if(root == null)return; 968 | if(root.left!=null || root.right!=null) 969 | { 970 | TreeNode temp=root.left; 971 | root.left=root.right; 972 | root.right=temp; 973 | } 974 | Mirror(root.left); 975 | Mirror(root.right); 976 | 977 | } 978 | 979 | 980 | ## 树的层次遍历 981 | 982 | 也就是从上到下打印节点,使用队列即可完成。 983 | 984 | ## 二叉树的深度 985 | 986 | 经典遍历。 987 | 988 | ## 判断是否平衡二叉树 989 | 990 | 判断左右子树的高度差是否 <= 1即可。 991 | 992 | ## 二叉搜索树的后序遍历 993 | 994 | 题目描述 995 | 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。 996 | 997 | 解析:这题其实也非常巧妙。二叉搜索树的特点就是他的左子树都比根节点小,右子树都比跟节点大。而后序遍历的根节点在最后,所以后续遍历的第1到N-1个节点应该是左右子树的节点(不一定左右子树都存在)。 998 | 999 | 后续遍历的序列是先左子树,再右子树,最后根节点,那么就要求,左半部分比根节点小,右半部分比根节点大,当然,左右部分不一定都存在。 1000 | 1001 | 所以,找出根节点后,首先找出左半部分,要求小于根节点,然后找出右半部分,要求大于根节点,如果符合,则递归地判断左右子树到的根节点(本步骤已经将左右部分划分,割据中间节点进行递归),如果不符合,直接返回false。 1002 | 1003 | 同理也可以判断前序遍历和中序遍历。 1004 | 1005 | public class 二叉搜索树的后序遍历序列 { 1006 | public static void main(String[] args) { 1007 | int []a = {7,4,6,5}; 1008 | System.out.println(VerifySquenceOfBST(a)); 1009 | } 1010 | public static boolean VerifySquenceOfBST(int [] sequence) { 1011 | if (sequence == null || sequence.length == 0) { 1012 | return false; 1013 | } 1014 | return isBST(sequence, 0, sequence.length - 1); 1015 | } 1016 | public static boolean isBST(int []arr, int start, int end) { 1017 | if (start >= end) return true; 1018 | int root = arr[end]; 1019 | int mid = start; 1020 | for (mid = start;mid < end && arr[mid] < root;mid ++) { 1021 | 1022 | } 1023 | for (int i = mid;i < end; i ++) { 1024 | if (arr[i] < root)return false; 1025 | } 1026 | return isBST(arr, start, mid - 1) && isBST(arr, mid, end - 1); 1027 | } 1028 | } 1029 | 1030 | ## 二叉树中和为某一值的路径 1031 | 1032 | /** 1033 | * Created by 周杰伦 on 2018/3/29. 1034 | * 题目描述 1035 | 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。 1036 | */ 1037 | 1038 | 解析:由于要求从根节点到达叶子节点,并且要打印出所有路径,所以实际上用到了回溯的思想。 1039 | 1040 | 通过target跟踪当前和,进行先序遍历,当和满足要求时,加入集合,由于有多种结果,所以需要回溯,将访问过的节点弹出访问序列,才能继续访问下一个节点。 1041 | 1042 | 终止条件是和满足要求,并且节点是叶节点,或者已经访问到空节点也会返回。 1043 | 1044 | 1045 | public class 二叉树中和为某一值的路径 { 1046 | private ArrayList> listAll = new ArrayList>(); 1047 | private ArrayList list = new ArrayList(); 1048 | public ArrayList> FindPath(TreeNode root,int target) { 1049 | if(root == null) return listAll; 1050 | list.add(root.val); 1051 | target -= root.val; 1052 | if(target == 0 && root.left == null && root.right == null) 1053 | listAll.add(new ArrayList(list)); 1054 | FindPath(root.left, target); 1055 | FindPath(root.right, target); 1056 | list.remove(list.size()-1); 1057 | return listAll; 1058 | } 1059 | 1060 | static int count = 0; 1061 | static Stack path = new Stack<>(); 1062 | static Stack stack = new Stack<>(); 1063 | static ArrayList> lists = new ArrayList<>(); 1064 | } 1065 | 1066 | ## 二叉树的下一个节点 1067 | 1068 | 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 1069 | 1070 | 解析:给出一个比较好懂的解法,中序遍历的结果存在集合中,找到根节点,进行中序遍历,然后找到该节点,下一个节点就是集合后一位 1071 | 1072 | public TreeLinkNode GetNext(TreeLinkNode TreeLinkNode) 1073 | { 1074 | return findNextNode(TreeLinkNode); 1075 | } 1076 | public TreeLinkNode findNextNode(TreeLinkNode anynode) { 1077 | if (anynode == null) return null; 1078 | TreeLinkNode p = anynode; 1079 | while (p.next != null) { 1080 | p = p.next; 1081 | } 1082 | ArrayList list = inOrderSeq(p); 1083 | for (int i = 0;i < list.size();i ++) { 1084 | if (list.get(i) == anynode) { 1085 | if (i + 1 < list.size()) { 1086 | return list.get(i + 1); 1087 | } 1088 | else return null; 1089 | } 1090 | } 1091 | return null; 1092 | 1093 | } 1094 | static ArrayList list = new ArrayList<>(); 1095 | public static ArrayList inOrderSeq(TreeLinkNode TreeLinkNode) { 1096 | if (TreeLinkNode == null) return null; 1097 | inOrderSeq(TreeLinkNode.left); 1098 | list.add(TreeLinkNode); 1099 | inOrderSeq(TreeLinkNode.right); 1100 | return list; 1101 | } 1102 | 1103 | ## 对称的二叉树 1104 | 1105 | 请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。 1106 | 1107 | 解析,之前有一题是二叉树的镜像,递归交换左右子树即可求出镜像,然后递归比较两个树的每一个节点,则可以判断是否对称。 1108 | 1109 | boolean isSymmetrical(TreeNode pRoot) 1110 | { 1111 | TreeNode temp = copyTree(pRoot); 1112 | Mirror(pRoot); 1113 | return isSameTree(temp, pRoot); 1114 | } 1115 | 1116 | 1117 | void Mirror(TreeNode root) { 1118 | if(root == null)return; 1119 | Mirror(root.left); 1120 | Mirror(root.right); 1121 | if(root.left!=null || root.right!=null) 1122 | { 1123 | TreeNode temp=root.left; 1124 | root.left=root.right; 1125 | root.right=temp; 1126 | } 1127 | 1128 | 1129 | } 1130 | boolean isSameTree(TreeNode t1,TreeNode t2){ 1131 | if(t1==null && t2==null)return true; 1132 | else if(t1!=null && t2!=null && t1.val==t2.val) { 1133 | boolean left = isSameTree(t1.left, t2.left); 1134 | boolean right = isSameTree(t1.right, t2.right); 1135 | return left && right; 1136 | } 1137 | else return false; 1138 | } 1139 | 1140 | TreeNode copyTree (TreeNode root) { 1141 | if (root == null) return null; 1142 | TreeNode t = new TreeNode(root.val); 1143 | t.left = copyTree(root.left); 1144 | t.right = copyTree(root.right); 1145 | return t; 1146 | } 1147 | ## 把二叉树打印成多行 1148 | 1149 | 题目描述 1150 | 从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。 1151 | 1152 | 解析:1 首先要知道到本题的基础思想,层次遍历。 1153 | 1154 | 2 然后是进阶的思想,按行打印二叉树并输出行号,方法是,一个节点last指向当前行的最后一个节点,一个节点nlast指向下一行最后一个节点。使用t表示现在遍历的节点,当t = last时,表示本行结束。此时last = nlast,开始下一行遍历。 1155 | 1156 | 同时,当t的左右子树不为空时,令nlast = t的左子树和右子树。每当last 赋值为nlast时,行号加一即可。 1157 | 1158 | ## 按之字形顺序打印二叉树 1159 | 1160 | 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。 1161 | 1162 | 解析:1 首先要知道到本题的基础思想,层次遍历。 1163 | 1164 | 2 然后是进阶的思想,按行打印二叉树并输出行号,方法是,一个节点last指向当前行的最后一个节点,一个节点nlast指向下一行最后一个节点。使用t表示现在遍历的节点,当t = last时,表示本行结束。此时last = nlast,开始下一行遍历。 1165 | 1166 | 同时,当t的左右子树不为空时,令nlast = t的左子树和右子树。每当last 赋值为nlast时,行号加一即可。 1167 | 1168 | 3 基于第2步的思想,现在要z字型打印,只需把偶数行逆序即可。所以把每一行的数存起来,然后偶数行逆置即可。 1169 | 1170 | ArrayList > Print(TreeNode pRoot) { 1171 | LinkedList queue = new LinkedList<>(); 1172 | TreeNode root = pRoot; 1173 | if(root == null) { 1174 | return new ArrayList<>(); 1175 | } 1176 | TreeNode last = root; 1177 | TreeNode nlast = root; 1178 | queue.offer(root); 1179 | ArrayList list = new ArrayList<>(); 1180 | list.add(root.val); 1181 | ArrayList one = new ArrayList<>(); 1182 | one.addAll(list); 1183 | ArrayList> lists = new ArrayList<>(); 1184 | lists.add(one); 1185 | list.clear(); 1186 | 1187 | int row = 1; 1188 | while (!queue.isEmpty()){ 1189 | 1190 | TreeNode t = queue.poll(); 1191 | 1192 | if(t.left != null) { 1193 | queue.offer(t.left); 1194 | list.add(t.left.val); 1195 | nlast = t.left; 1196 | } 1197 | if(t.right != null) { 1198 | queue.offer(t.right); 1199 | list.add(t.right.val); 1200 | nlast = t.right; 1201 | } 1202 | if(t == last) { 1203 | if(!queue.isEmpty()) { 1204 | last = nlast; 1205 | row ++; 1206 | ArrayList temp = new ArrayList<>(); 1207 | temp.addAll(list); 1208 | list.clear(); 1209 | if (row % 2 == 0) { 1210 | Collections.reverse(temp); 1211 | } 1212 | lists.add(temp); 1213 | 1214 | } 1215 | } 1216 | } 1217 | 1218 | return lists; 1219 | } 1220 | 1221 | ## 序列化和反序列化二叉树 1222 | 1223 | 解析:序列化和反序列化关键是要确定序列化方式。我么使用字符串来序列化。 1224 | 1225 | 用#代表空,用!分隔左右子树。 1226 | 1227 | 比如 1 1228 | 2 3 1229 | 4 5 1230 | 1231 | 使用先序遍历 1232 | 序列化结果是1!2!4!###3!#5!## 1233 | 1234 | 反序列化先让根节点指向第一位字符,然后左子树递归进行连接,右子树 1235 | 1236 | public class Solution { 1237 | public int index = -1; 1238 | StringBuffer sb = new StringBuffer(); 1239 | 1240 | String Serialize(TreeNode root) { 1241 | if(root == null) { 1242 | sb.append("#!") ; 1243 | } 1244 | else { 1245 | sb.append(root.val + "!"); 1246 | Serialize(root.left); 1247 | Serialize(root.right); 1248 | } 1249 | 1250 | return sb.toString(); 1251 | } 1252 | TreeNode Deserialize(String str) { 1253 | index ++; 1254 | int len = str.length(); 1255 | if(index >= len) { 1256 | return null; 1257 | } 1258 | String[] strr = str.split("!"); 1259 | TreeNode node = null; 1260 | if(!strr[index].equals("#")) { 1261 | node = new TreeNode(Integer.valueOf(strr[index])); 1262 | node.left = Deserialize(str); 1263 | node.right = Deserialize(str); 1264 | } 1265 | return node; 1266 | } 1267 | } 1268 | 1269 | ## 二叉搜索树的第k个结点 1270 | 1271 | 解析:二叉搜索树的中序遍历是有序的,只需要在中序中判断数字是否在第k个位置即可。 1272 | 如果在左子树中发现了,那么递归返回该节点,如果在右子树出现,也递归返回该节点。注意必须要返回,否则结果会被递归抛弃掉。 1273 | 1274 | TreeNode KthNode(TreeNode pRoot, int k) 1275 | { 1276 | count = 0; 1277 | return inOrderSeq(pRoot, k); 1278 | } 1279 | static int count = 0; 1280 | public TreeNode inOrderSeq(TreeNode treeNode, int k) { 1281 | if (treeNode == null) return null; 1282 | TreeNode left = inOrderSeq(treeNode.left, k); 1283 | if (left != null) return left; 1284 | if (++ count == k) return treeNode; 1285 | TreeNode right = inOrderSeq(treeNode.right, k); 1286 | if (right != null) return right; 1287 | return null; 1288 | } 1289 | 1290 | # 栈和队列 1291 | 1292 | ## 用两个队列实现栈,用两个栈实现队列。 1293 | 1294 | 1295 | 简单说下思路 1296 | 1297 | 1 两个栈实现队列,要求先进先出,入队时节点先进入栈A,如果栈A满并且栈B空则把全部节点压入栈B。 1298 | 1299 | 出队时,如果栈B为空,那么直接把栈A节点全部压入栈B,再从栈B出栈,如果栈B不为空,则从栈B出栈。 1300 | 1301 | 2 两个队列实现栈,要求后进先出。入栈时,节点先加入队列A,出栈时,如果队列B不为空,则把头结点以后的节点出队并加入到队列B,然后自己出队。 1302 | 1303 | 如果出栈时队列B不为空,则把B头结点以后的节点移到队列A,然后出队头结点,以此类推。 1304 | 1305 | ## 包含min函数的栈 1306 | 1307 | /** 1308 | * 设计一个返回最小值的栈 1309 | * 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。 1310 | * Created by 周杰伦 on 2017/3/22. 1311 | */ 1312 | 1313 | 解析:这道题的解法也是非常巧妙的。因为每次进栈和出栈都有可能导致最小值发生改变。而我们要维护的是整个栈的最小值。 1314 | 1315 | 如果单纯使用一个数来保存最小值,会出现一种情况,最小值出栈时,你此时的最小值只能改成栈顶元素,但这个元素不一定时最小值。 1316 | 1317 | 所以需要一个数组来存放最小值,或者是一个栈。 1318 | 1319 | 使用另一个栈B存放最小值,每次压栈时比较节点值和栈B顶端节点值,如果比它小则压栈,否则不压栈,这样就可以从b的栈顶到栈顶依次访问最小值,次小值。以此类推。 1320 | 1321 | 当最小值节点出栈时,判断栈B顶部的节点和出栈节点是否相同,相同则栈B也出栈。 1322 | 1323 | 这样就可以维护一个最小值的函数了。 1324 | 1325 | 同理,最大值也是这样。 1326 | 1327 | 1328 | public class 包含min函数的栈 { 1329 | Stack stack=new Stack<>(); 1330 | Stack minstack=new Stack<>(); 1331 | 1332 | public void push(int node) { 1333 | if(stack.isEmpty()) 1334 | { 1335 | stack.push(node); 1336 | minstack.push(node); 1337 | } 1338 | else if(node stack = new Stack<>(); 1381 | int j = 0; 1382 | int i = 0; 1383 | while (i < pushA.length) { 1384 | stack.push(pushA[i]); 1385 | i++; 1386 | while (!stack.empty() && stack.peek() == popA[j]) { 1387 | stack.pop(); 1388 | j++; 1389 | } 1390 | if (i == pushA.length) { 1391 | if (!stack.empty()) { 1392 | return false; 1393 | } else return true; 1394 | } 1395 | } 1396 | return false; 1397 | } 1398 | 1399 | 1400 | # 排序和查找 1401 | 1402 | ## 旋转数组的最小数字 1403 | 1404 | 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。 1405 | 1406 | 解析:这题的思路很巧妙,如果直接遍历复杂度为O(N),但是使用二分查找可以加快速度,因为两边的数组都是递增的最小值一定在两边数组的边缘,于是通过二分查找,逐渐缩短左右指针的距离,知道左指针和右指针只差一步,那么右指针所在的数就是最小值了。 1407 | 复杂度是O(logN) 1408 | 1409 | //这段代码忽略了三者相等的情况 1410 | public int minNumberInRotateArray(int [] array) { 1411 | if (array.length == 0) return 0; 1412 | if (array.length == 1) return array[0]; 1413 | int min = 0; 1414 | 1415 | int left = 0, right = array.length - 1; 1416 | //只有左边值大于右边值时,最小值才可能出现在中间 1417 | while (array[left] > array[right]) { 1418 | int mid = (left + right)/2; 1419 | if (right - left == 1) { 1420 | min = array[right]; 1421 | break; 1422 | } 1423 | //如果左半部分递增,则最小值在右侧 1424 | if (array[left] < array[mid]) { 1425 | left = mid; 1426 | } 1427 | //如果右半部分递增,则最小值在左侧。 1428 | //由于左边值比右边值大,所以两种情况不会同时发生 1429 | else if (array[right] > array[mid]) { 1430 | right = mid ; 1431 | } 1432 | } 1433 | return array[min]; 1434 | 1435 | } 1436 | 1437 | 1438 | 注意:但是当arr[left] = arr[right] = arr[min]时。三个数都相等无法确定最小值,此时只能遍历。 1439 | 1440 | # 递归 1441 | 1442 | ## 斐波那契数列 1443 | 1444 | 1递归做法 1445 | 1446 | 2记忆搜索,用数组存放使用过的元素。 1447 | 1448 | 3DP,本题中dp就是记忆化搜索 1449 | 1450 | ## 青蛙跳台阶 1451 | 1452 | 一次跳两步或者跳一步,问一共多少种跳法到达n级,所以和斐波那契数列是一样的。 1453 | 1454 | ## 变态跳台阶 1455 | 1456 | 一次跳1到n步,问一共几种跳法,这题是找数字规律的,一共有2^(n-1)种方法 1457 | 1458 | ## 矩形覆盖 1459 | 1460 | 和上题一样,也是找规律,答案也是2^(n-1) 1461 | 1462 | # 位运算 1463 | 1464 | ## 二进制中1的个数 1465 | 1466 | * Created by 周杰伦 on 2018/6/29. 1467 | * 题目描述 1468 | * 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。 1469 | 1470 | 解析: 1471 | 1 循环右移数字n,每次判断最低位是否为1,但是可能会导致死循环。 1472 | 1473 | 2 使用数字a = 1和n相与,a每次左移一位,再与n相与得到次低位,最多循环32次,当数字1左移32次也会等于0,所以结束循环。 1474 | 1475 | 3 非常奇葩的做法,把一个整数减去1,再与原整数相与,会把最右边的一个1变成0,于是统计可以完成该操作的次数即可知道有多少1了。 1476 | 1477 | public class 二进制中1的个数 { 1478 | public static int NumberOf1(int n) { 1479 | int count = 0; 1480 | while (n != 0) { 1481 | ++count; 1482 | n = (n - 1) & n; 1483 | } 1484 | return count; 1485 | } 1486 | } 1487 | 1488 | ## 数组中只出现一次的数字 1489 | 1490 | 题目描述 1491 | 一个整型数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这一个只出现一次的数字。 1492 | 1493 | 解析:左神称之为神仙题。 1494 | 1495 | 利用位运算的异或操作^。 1496 | 由于a^a = 0,0^b=b,所以。所有数执行异或操作,结果就是只出现一次的数。 1497 | 1498 | ## 不用加减乘除做加法 1499 | 1500 | 解析:不用加减乘,那么只能用二进制了。 1501 | 1502 | 两个数a和b,如果不考虑进位,则0 + 1 = 1,1 + 1 = 0,0 + 0 = 0,这就相当于异或操作。 1503 | 如果考虑进位,则只有1 + 1有进位,所以使用相与左移的方法得到每一位的进位值,再通过异或操作和原来的数相加。当没有进位值的时候,运算结束。 1504 | public static int Add(int num1,int num2) { 1505 | if( num2 == 0 )return num1; 1506 | if( num1 == 0 )return num2; 1507 | 1508 | int temp = num2; 1509 | while(num2!=0) { 1510 | temp = num1 ^num2; 1511 | num2 = (num1 & num2)<<1; 1512 | num1 = temp; 1513 | } 1514 | return num1; 1515 | } 1516 | 1517 | # 回溯和DFS 1518 | 1519 | ## 矩阵中的路径 1520 | 1521 | 题目描述 1522 | 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。 1523 | 1524 | 解析:回溯法也就是特殊的dfs,需要找到所有的路径,所以每当到达边界条件或抵达目标时,递归返回,由于需要保存路径中的字母,所以递归返回时需要删除路径最后的节点,来保证路径合法。不过本题只有一个解,所以找到即可返回。 1525 | 1526 | public class 矩阵中的路径 { 1527 | public static void main(String[] args) { 1528 | char[][]arr = {{'a','b','c','e'},{'s','f','c','s'},{'a','d','e','e'}}; 1529 | char []str = {'b','c','c','e','d'}; 1530 | System.out.println(hasPath(arr, arr.length, arr[0].length, str)); 1531 | } 1532 | static int flag = 0; 1533 | public static boolean hasPath(char[][] matrix, int rows, int cols, char[] str) 1534 | { 1535 | int [][]visit = new int[rows][cols]; 1536 | StringBuilder sb = new StringBuilder(); 1537 | for (int i = 0;i < rows;i ++) { 1538 | for (int j = 0;j < cols;j ++) { 1539 | if (matrix[i][j] == str[0]) { 1540 | visit[i][j] = 1; 1541 | sb.append(str[0]); 1542 | dfs(matrix, i, j, visit, str, 1, sb); 1543 | visit[i][j] = 0; 1544 | sb.deleteCharAt(sb.length() - 1); 1545 | } 1546 | } 1547 | } 1548 | return flag == 1; 1549 | } 1550 | public static void dfs(char [][]matrix, int row, int col, int [][]visit, char []str, int cur, StringBuilder sb) { 1551 | if (sb.length() == str.length) { 1552 | // System.out.println(sb.toString()); 1553 | flag = 1; 1554 | return; 1555 | } 1556 | 1557 | int [][]pos = {{1,0},{-1,0},{0,1},{0,-1}}; 1558 | for (int i = 0;i < pos.length;i ++) { 1559 | int x = row + pos[i][0]; 1560 | int y = col + pos[i][1]; 1561 | if (x >= matrix.length || x < 0 || y >= matrix[0].length || y < 0) { 1562 | continue; 1563 | } 1564 | if (visit[x][y] == 0 && matrix[x][y] == str[cur]) { 1565 | sb.append(matrix[x][y]); 1566 | visit[x][y] = 1; 1567 | dfs(matrix, x, y, visit, str, cur + 1, sb); 1568 | sb.deleteCharAt(sb.length() - 1); 1569 | visit[x][y] = 0; 1570 | } 1571 | } 1572 | } 1573 | 1574 | 1575 | ## 机器人的运动范围 1576 | 1577 | 题目描述 1578 | 地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子? 1579 | 1580 | 解析:这是一个可达性问题,使用dfs方法,走到的每一格标记为走过,走到无路可走时就是最终的结果。每次都有四个方向可以选择,所以写四个递归即可。 1581 | 1582 | public class Solution { 1583 | static int count = 0; 1584 | public static int movingCount(int threshold, int rows, int cols) 1585 | { 1586 | count = 0; 1587 | int [][]visit = new int[rows][cols]; 1588 | dfs(0, 0, visit, threshold); 1589 | return count; 1590 | } 1591 | 1592 | public static void dfs(int row, int col, int[][]visit, int k) { 1593 | if (row >= visit.length || row < 0 || col >= visit[0].length || col < 0) { 1594 | return; 1595 | } 1596 | if (sum(row) + sum(col) > k) { 1597 | return; 1598 | } 1599 | 1600 | if (visit[row][col] == 1){ 1601 | return; 1602 | } 1603 | 1604 | visit[row][col] = 1; 1605 | count ++; 1606 | dfs(row + 1,col,visit, k); 1607 | dfs(row - 1,col,visit, k); 1608 | dfs(row,col + 1,visit, k); 1609 | dfs(row,col - 1,visit, k); 1610 | 1611 | } 1612 | 1613 | public static int sum(int num) { 1614 | String s = String.valueOf(num); 1615 | int sum = 0; 1616 | for (int i = 0;i < s.length();i ++) { 1617 | sum += Integer.valueOf(s.substring(i, i + 1)); 1618 | } 1619 | return sum; 1620 | } 1621 | } 1622 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 147 | 148 | 149 | 150 | e 151 | 152 | 153 | 154 | 156 | 157 | 160 | 161 | 162 | 208 | 209 | 210 | 211 | 212 | true 213 | DEFINITION_ORDER 214 | 215 | 216 | 221 | 222 | 223 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 249 | 250 | 253 | 254 | 255 | 256 | 259 | 260 | 263 | 264 | 267 | 268 | 269 | 270 | 273 | 274 | 277 | 278 | 281 | 282 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 317 | 318 | 319 | 320 | 321 | 322 | 325 | 326 | 339 | 340 | 341 | 342 | 345 | 346 | 359 | 360 | 361 | 362 | 365 | 366 | 379 | 380 | 381 | 382 | 385 | 386 | 399 | 400 | 401 | 402 | 405 | 406 | 419 | 420 | 421 | 426 | 427 | 428 | 454 | 455 | 456 | 481 | 482 | 489 | 490 | 491 | 504 | 505 | 506 | 507 | 512 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 538 | 556 | 563 | 564 | 565 | 566 | 567 | 568 | 585 | 586 | 607 | 620 | 621 | 630 | 634 | 635 | 636 | 643 | 646 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 730 | 731 | 732 | 742 | 743 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 777 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | project 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 855 | 856 | 857 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 1489925457664 866 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 953 | 954 | 957 | 960 | 961 | 962 | 964 | 965 | 966 | 967 | 968 | file://$PROJECT_DIR$/src/Part2/reOrderArray.java 969 | 29 970 | 971 | 973 | 974 | file://$PROJECT_DIR$/src/Part2/reOrderArray.java 975 | 27 976 | 977 | 979 | 980 | file://$PROJECT_DIR$/src/mianshi/toutiao/getTheRightBiggerNum.java 981 | 17 982 | 983 | 985 | 986 | 987 | 988 | 989 | 991 | 992 | 993 | 994 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | 1269 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 1330 | 1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1351 | 1352 | 1353 | 1354 | 1355 | 1356 | 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | --------------------------------------------------------------------------------