├── .gitignore ├── README.md ├── algorithms ├── algorithms.iml └── src │ ├── array │ ├── BinarySearch.java │ ├── BinarySearchTest.java │ ├── GenericArray.java │ ├── MinNumberInRotatedArray.java │ └── MinNumberInRotatedArrayTest.java │ ├── joseph │ └── Joseph.java │ ├── linkedlist │ ├── FindMidNode.java │ ├── FindMidNodeTest.java │ ├── SingleLinkedList.java │ └── SingleLinkedListTest.java │ ├── lru │ ├── LRU.java │ └── LRUTest.java │ ├── queue │ ├── ArrayQueue.java │ ├── CircularQueue.java │ ├── ListQueue.java │ └── Queue.java │ └── stack │ ├── ArrayStack.java │ ├── DynamicArrayStack.java │ ├── ListStack.java │ ├── SampleBrowser.java │ └── Stack.java ├── appendix ├── instructions.md └── 刷题笔记.md ├── leetcode ├── leetcode.iml └── src │ ├── linkedlistcycle_141 │ └── LinkedListCycle.java │ ├── lrucache_146 │ └── LRUCache.java │ ├── mergetwosortedlist_21 │ └── Merge2SortedLists.java │ ├── middleofthelinkedlist_876 │ └── MiddleNode.java │ ├── palindromelinkedlist_234 │ └── PalindromeLinkedList.java │ ├── removenthnodefromendoflist_19 │ └── RemoveNthNodeFromEndOfList.java │ ├── reverselinkedlist_206 │ └── ReverseList.java │ ├── threesum_015 │ └── ThreeSum.java │ └── twosum_001 │ └── TwoSum.java ├── offer ├── offer.iml └── src │ └── com │ └── ex │ ├── offer │ ├── Attention.txt │ ├── Ex_03_FindDuplicatedNumInArray.java │ ├── Ex_03_FindDuplicatedNumInWithoutChangeArray.java │ ├── Ex_04_FindNumIn2VArray.java │ ├── Ex_05_ReplaceSpace.java │ ├── Ex_06_PrintListFromTailToHead.java │ ├── Ex_07_ReConstructBT.java │ ├── Ex_08_DescendantNode.java │ ├── Ex_08_GetNextNodeInBT.java │ ├── Ex_09_QueueWithTwoStack.java │ ├── Ex_09_StackWithTwoQueue.java │ ├── Ex_10_Fibonacci.java │ ├── Ex_10_JumpFloor.java │ ├── Ex_10_JumpFloorII.java │ ├── Ex_10_RectCover.java │ ├── Ex_11_MinNumOfRotatingArray.java │ ├── Ex_11_SortAges.java │ ├── Ex_12_HasPathInMatrix.java │ ├── Ex_13_MovingCount.java │ ├── Ex_14_MaxProductionAfterCutting.java │ ├── Ex_15_Count1.java │ ├── Ex_15_CountDifferInMN.java │ ├── Ex_15_IsPowerOf2.java │ ├── Ex_16_Power.java │ ├── Ex_17_AddTwoBigNumber.java │ ├── Ex_17_Print1ToMaxNDigits.java │ ├── Ex_18_DeleteDuplicatedNode.java │ ├── Ex_18_DeleteNodeInSList.java │ ├── Ex_19_Match.java │ ├── Ex_20_IsNumber.java │ ├── Ex_21_ReOrderArray.java │ ├── Ex_22_FindKthNodeToTail.java │ ├── Ex_22_FindMedianNodeInList.java │ ├── Ex_23_EntryNodeInList.java │ ├── Ex_24_ReverseSList.java │ ├── Ex_25_MergeList.java │ ├── Ex_26_IsSubTree.java │ ├── Ex_27_MirrorOfTree.java │ ├── Ex_28_SymmetricalTree.java │ ├── Ex_29_PrintMatrixWithClockWise.java │ ├── Ex_30_StackWithMinFunction.java │ ├── Ex_31_IsPopOrder.java │ ├── Ex_32_PrintTreeByLayer.java │ ├── Ex_32_PrintTreeWithZhi.java │ ├── Ex_32_TraverseTreeByLayer.java │ ├── Ex_33_VerifySequenceOfBST.java │ ├── Ex_34_FindPathInBT.java │ ├── Ex_34_FindPathInBT_1.java │ ├── Ex_34_FindPathInBT_2.java │ ├── Ex_35_CloneList.java │ ├── Ex_36_ConvertBetweenBSTAndDList.java │ ├── Ex_37_SerializeBT.java │ ├── Ex_38_EightQueen.java │ ├── Ex_38_StringCombination.java │ ├── Ex_38_StringPermutation.java │ ├── Ex_39_KthSmallestNumInArrayWithoutSort.java │ ├── Ex_39_MoreThanHalfNum.java │ ├── Ex_40_GetLeastKNumbers.java │ ├── Ex_41_MedianInDataFlow.java │ ├── Ex_42_MaxSumOfSubArray.java │ ├── Ex_43_NumberOf1Between1AndN.java │ ├── Ex_44_ANumInArray.java │ ├── Ex_45_MinNumByConcatArray.java │ ├── Ex_46_ConvertStringToIP.java │ ├── Ex_46_TranslationFromIntToString.java │ ├── Ex_47_MaxGiftValue.java │ ├── Ex_48_LongestSubStringWithDuplication.java │ ├── Ex_49_UglyNumber.java │ ├── Ex_50_FirstNotRepeatedChar.java │ ├── Ex_50_FirstNotRepeatedCharInDataFlow.java │ ├── Ex_50_StringUtilsSolutions.java │ ├── Ex_51_InversePairs.java │ ├── Ex_51_InversePairs_BigData.java │ ├── Ex_52_FirstCommonNode.java │ ├── Ex_53_GetMissingNumber.java │ ├── Ex_53_GetNumberOfK.java │ ├── Ex_53_GetNumberSameAsIndex.java │ ├── Ex_54_KthNodeInBST.java │ ├── Ex_55_BalancedBT.java │ ├── Ex_55_DepthOfBT.java │ ├── Ex_56_AppearanceOnce.java │ ├── Ex_56_AppearanceOnce_Continued.java │ ├── Ex_57_FindContinuousSequence.java │ ├── Ex_57_FindNumbersWithSum.java │ ├── Ex_58_ROL.java │ ├── Ex_58_ReverseSentence.java │ ├── Ex_59_MaxNumOfSlidingWindow.java │ ├── Ex_59_QueueWithMax.java │ ├── Ex_60_ProbabilityOfS.java │ ├── Ex_61_ContinuousSequence.java │ ├── Ex_62_Josephus.java │ ├── Ex_63_MaxProfits.java │ ├── Ex_64_SumFrom1ToN.java │ ├── Ex_65_AddWithoutCarry.java │ ├── Ex_65_SwapNumWithoutTemp.java │ ├── Ex_66_ConstructMultiplyArray.java │ ├── Ex_67_StringToInt.java │ ├── Ex_68_LowestCommonAncestor.java │ ├── ListNode.java │ ├── Node.java │ ├── RandomListNode.java │ ├── TestUtils.java │ ├── TreeLinkNode.java │ └── TreeNode.java │ └── singleton │ ├── Singleton1.java │ ├── Singleton2.java │ ├── Singleton3.java │ ├── Singleton4.java │ ├── Singleton5.java │ └── singleton.md ├── pictures └── algo.jpg ├── practice ├── Final.md ├── README.md └── src │ └── io │ └── gkd │ ├── ListNode.java │ ├── Node.java │ ├── TreeNode.java │ ├── lectures │ ├── lecture04 │ │ ├── Lc077_Combine.java │ │ └── Lc078_SubSets.java │ └── lecture05 │ │ ├── Lc094_InOrderTraversal.java │ │ ├── Lc105_BuildTree.java │ │ ├── Lc236_LCA.java │ │ ├── Lc297_Codec.java │ │ ├── Lc429_LevelOrderNTree.java │ │ └── Lc589_PreOrderNTree.java │ ├── week01 │ ├── Lc021_MergeTwoLists.java │ └── Lc066_PlusOne.java │ ├── week02 │ ├── Lc146_LRUCache.java │ └── Lc697_FindShortestSubArray.java │ └── week03 │ ├── Lc106_BuildTree.java │ ├── Lc210_FindOrder2.java │ └── NOTES.md ├── questions └── questions.md ├── solutions └── 剑指offer 题解.md └── summary └── algorithm.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # idea 26 | *.idea 27 | *.iml 28 | 29 | target/ 30 | *.mvn 31 | *db 32 | 33 | # others 34 | *.extract 35 | .DS_Store 36 | -------------------------------------------------------------------------------- /algorithms/algorithms.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /algorithms/src/array/MinNumberInRotatedArray.java: -------------------------------------------------------------------------------- 1 | package array; 2 | 3 | public class MinNumberInRotatedArray { 4 | 5 | public static int getMinNumber(int[] arr) { 6 | if (arr == null || arr.length < 1) { 7 | throw new IllegalArgumentException("Invalid Array!"); 8 | } 9 | 10 | // 循环不变条件 [左侧递增数组 | 右侧递增数组] 11 | int l = 0; // l始终指向左侧递增数组 12 | int r = arr.length-1; // r始终指向右侧递增数组 13 | 14 | while (arr[l] >= arr[r]) { 15 | if (r - l == 1) { 16 | return arr[r]; 17 | } 18 | 19 | int mid = l + ((r-l) >> 1); 20 | 21 | // 若 arr[l] == arr[r] && arr[l] == arr[mid], 22 | // arr[mid]无法判定属于左侧递增数组还是右侧递增数组,因此只能顺序查找 23 | if (arr[l] == arr[r] && arr[l] == arr[mid]) { 24 | return getMinInOrder(arr, l, r); 25 | } 26 | 27 | if (arr[mid] >= arr[l]) { 28 | l = mid; 29 | } else if (arr[mid] <= arr[r]) { 30 | r = mid; 31 | } 32 | } 33 | 34 | return arr[l]; // 若数组是已经排序的数组(从小到大),min = arr[l]。 35 | } 36 | 37 | private static int getMinInOrder(int[] arr, int l, int r) { 38 | int min = arr[l]; 39 | for (int i = l+1 ; i <= r; i++) { 40 | if (arr[i] < min) { 41 | min = arr[i]; 42 | } 43 | } 44 | 45 | return min; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /algorithms/src/array/MinNumberInRotatedArrayTest.java: -------------------------------------------------------------------------------- 1 | package array; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class MinNumberInRotatedArrayTest { 7 | 8 | @Test 9 | public void testGetMinNumber() { 10 | int[] arr = new int[] {3,4,5,1,2}; 11 | int expected = 1; 12 | Assert.assertEquals(expected, MinNumberInRotatedArray.getMinNumber(arr)); 13 | 14 | int[] arr1 = new int[] {1,2,3,4,5}; 15 | Assert.assertEquals(expected, MinNumberInRotatedArray.getMinNumber(arr1)); 16 | 17 | int[] arr2 = new int[] {1,0,1,1,1}; 18 | int expected1 = 0; 19 | Assert.assertEquals(expected1, MinNumberInRotatedArray.getMinNumber(arr2)); 20 | 21 | int[] arr3 = new int[] {1,1,1,0,1}; 22 | Assert.assertEquals(expected1, MinNumberInRotatedArray.getMinNumber(arr3)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /algorithms/src/joseph/Joseph.java: -------------------------------------------------------------------------------- 1 | package joseph; 2 | 3 | /** 4 | * Joseph Question 5 | * 6 | * Solution: 圆圈长度为n时的解f(n,m)可以看成是圆圈长度为n-1时的解f(n-1,m)加m。 7 | * 但是因为是循环的(圆圈),因此需要对相应的长度取余。 8 | * f(n,m) = (f(n-1,m) + m) % n n > 1 9 | * f(n,m) = 0 n = 1 10 | * 11 | * 如:要解决n = 5, m = 3的情形: 12 | * n = 1: 0 0 13 | * n = 2: 0,1 (0+3)%2 = 1; 14 | * n = 3: 0,1,2 (1+3)%3 = 1; 15 | * n = 4: 0,1,2,3 (1+3)%4 = 0; 16 | * n = 5: 0,1,2,3,4 (0+3)%5 = 3; 17 | */ 18 | public class Joseph { 19 | public int lastRemain(int n, int m) { 20 | if (n < 1 || m < 1) { 21 | return -1; 22 | } 23 | 24 | if (n == 1) { 25 | return 0; 26 | } 27 | 28 | return (lastRemain(n-1, m) + m) % n; 29 | } 30 | 31 | public int lastRemainIter(int n, int m) { 32 | if (n < 1 || m < 1) { 33 | return -1; 34 | } 35 | 36 | int last = 0; 37 | for (int i = 2; i <= n; i++) { 38 | last = (last + m) % i; 39 | } 40 | 41 | return last; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /algorithms/src/linkedlist/FindMidNode.java: -------------------------------------------------------------------------------- 1 | package linkedlist; 2 | 3 | public class FindMidNode { 4 | 5 | // 1. T(n) = O(2*n) 遍历2次 6 | public static Node findMidNode(Node head) { 7 | if (head == null) { 8 | return null; 9 | } 10 | 11 | int len = 0; 12 | Node p = head; 13 | 14 | while(p != null) { 15 | len++; 16 | p = p.next; 17 | } 18 | 19 | p = head; 20 | for (int i = 0; i < len/2; i++) { 21 | p = p.next; 22 | } 23 | 24 | return p; 25 | } 26 | 27 | // 2. T(n) = O(n) 遍历1次 28 | // 快慢指针法 29 | public static Node findMidNodeFast(Node head) { 30 | if (head == null) { 31 | return null; 32 | } 33 | 34 | Node fast = head; 35 | Node slow = head; 36 | 37 | while (fast != null && fast.next != null) { 38 | fast = fast.next.next; 39 | slow = slow.next; 40 | } 41 | 42 | return slow; 43 | } 44 | 45 | 46 | public static Node createNode(int value) { 47 | return new Node(value, null); 48 | } 49 | 50 | public static class Node { 51 | public int data; 52 | public Node next; 53 | 54 | public Node(int data, Node next) { 55 | this.data = data; 56 | this.next = next; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /algorithms/src/linkedlist/FindMidNodeTest.java: -------------------------------------------------------------------------------- 1 | package linkedlist; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | 7 | public class FindMidNodeTest { 8 | 9 | @Test 10 | public void testFindMidNode() { 11 | FindMidNode.Node head = FindMidNode.createNode(0); 12 | head.next = FindMidNode.createNode(1); 13 | head.next.next = FindMidNode.createNode(2); 14 | head.next.next.next = FindMidNode.createNode(3); 15 | head.next.next.next.next = FindMidNode.createNode(4); //[0,1,2,3,4] 16 | FindMidNode.Node node1 = FindMidNode.findMidNode(head); 17 | head.next.next.next.next.next = FindMidNode.createNode(5); //[0,1,2,3,4,5] 18 | FindMidNode.Node node2 = FindMidNode.findMidNode(head); 19 | 20 | int expected1 = 2; 21 | int expected2 = 3; 22 | Assert.assertEquals(expected1, node1.data); 23 | Assert.assertEquals(expected2, node2.data); 24 | } 25 | 26 | @Test 27 | public void testFindMidNodeFast() { 28 | FindMidNode.Node head = FindMidNode.createNode(0); 29 | head.next = FindMidNode.createNode(1); 30 | head.next.next = FindMidNode.createNode(2); 31 | head.next.next.next = FindMidNode.createNode(3); 32 | head.next.next.next.next = FindMidNode.createNode(4); //[0,1,2,3,4] 33 | FindMidNode.Node node1 = FindMidNode.findMidNodeFast(head); 34 | head.next.next.next.next.next = FindMidNode.createNode(5); //[0,1,2,3,4,5] 35 | FindMidNode.Node node2 = FindMidNode.findMidNodeFast(head); 36 | 37 | int expected1 = 2; 38 | int expected2 = 3; 39 | Assert.assertEquals(expected1, node1.data); 40 | Assert.assertEquals(expected2, node2.data); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /algorithms/src/linkedlist/SingleLinkedListTest.java: -------------------------------------------------------------------------------- 1 | package linkedlist; 2 | 3 | import org.junit.Test; 4 | 5 | public class SingleLinkedListTest { 6 | 7 | @Test 8 | public void testSingleLinkedList() { 9 | SingleLinkedList list = new SingleLinkedList(); //[] 10 | list.insertToTail(2); 11 | list.insertToTail(3); 12 | list.insertToTail(4); // [2,3,4] 13 | list.printAll(); 14 | 15 | list.insertToHead(1); 16 | list.insertToHead(0); // [0,1,2,3,4] 17 | list.printAll(); 18 | 19 | SingleLinkedList.Node node = list.findByIndex(2); 20 | list.insertBefore(node, 10); 21 | list.insertAfter(node, 10); // [0,1,10,2,10,3,4] 22 | list.printAll(); 23 | 24 | list.deleteByValue(10); 25 | list.printAll(); // [0,1,2,3,4] 26 | 27 | SingleLinkedList.Node p = list.findByValue(2); 28 | System.out.println(node.getData() == p.getData()); // true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /algorithms/src/lru/LRUTest.java: -------------------------------------------------------------------------------- 1 | package lru; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | public class LRUTest { 7 | @Test 8 | public void testLRU() { 9 | LRU lru = new LRU<>(5); 10 | Assert.assertEquals(null, lru.get(1)); 11 | 12 | lru.put(1,1); 13 | Assert.assertEquals(Integer.valueOf(1), lru.get(1)); 14 | lru.put(2,2); 15 | lru.put(3,3); 16 | lru.put(4,4); 17 | lru.put(5,5); 18 | for (Integer integer : lru) { 19 | System.out.print(integer + " "); 20 | } 21 | 22 | System.out.println(); 23 | 24 | Assert.assertEquals(Integer.valueOf(2), lru.get(2)); 25 | for (Integer integer : lru) { 26 | System.out.print(integer + " "); 27 | } 28 | 29 | System.out.println(); 30 | 31 | lru.put(6,6); 32 | for (Integer integer : lru) { 33 | System.out.print(integer + " "); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /algorithms/src/queue/ArrayQueue.java: -------------------------------------------------------------------------------- 1 | package queue; 2 | 3 | public class ArrayQueue implements Queue { 4 | private T[] items; 5 | private int capacity; 6 | private int head; 7 | private int tail; 8 | 9 | public ArrayQueue(int capacity) { 10 | this.capacity = capacity; 11 | this.items = (T[]) new Object[capacity]; 12 | this.head = 0; 13 | this.tail = 0; 14 | } 15 | 16 | // T(N)=O(1) 17 | @Override 18 | public boolean enqueue(T item) { 19 | if (tail == capacity) { 20 | // head == 0 && tail == capacity, queue is full. 21 | if (head == 0) { 22 | return false; 23 | } 24 | 25 | // 数据搬移,空出位置 26 | for (int i = head; i < tail; i++) { 27 | items[i-head] = items[i]; 28 | } 29 | 30 | // 搬移完之后,更新head和tail 31 | tail -= head; 32 | head = 0; 33 | } 34 | 35 | items[tail] = item; 36 | tail++; 37 | 38 | return true; 39 | } 40 | 41 | // T(N)=O(1) 42 | @Override 43 | public T dequeue() { 44 | if (head == tail) { 45 | return null; 46 | } 47 | 48 | T tmp = items[head]; 49 | head++; 50 | 51 | return tmp; 52 | } 53 | 54 | // for test 55 | public void printAll() { 56 | System.out.print("["); 57 | for (int i = head; i < tail; i++) { 58 | System.out.print(items[i] + " "); 59 | } 60 | System.out.print("]"); 61 | System.out.println(); 62 | } 63 | 64 | public static void main(String[] args) { 65 | ArrayQueue queue = new ArrayQueue<>(4); 66 | queue.printAll(); 67 | queue.enqueue("A"); 68 | queue.printAll(); 69 | queue.enqueue("B"); 70 | queue.enqueue("C"); 71 | queue.enqueue("D"); 72 | queue.printAll(); 73 | queue.enqueue("E"); 74 | queue.printAll(); 75 | 76 | queue.dequeue(); 77 | queue.dequeue(); 78 | queue.dequeue(); 79 | queue.printAll(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /algorithms/src/queue/CircularQueue.java: -------------------------------------------------------------------------------- 1 | package queue; 2 | 3 | public class CircularQueue { 4 | private T[] items; 5 | private int capacity; 6 | private int head; 7 | private int tail; 8 | 9 | public CircularQueue(int capacity) { 10 | this.capacity = capacity; 11 | this.items = (T[]) new Object[capacity]; 12 | this.head = 0; 13 | this.tail = 0; 14 | } 15 | 16 | // T(N)=O(1) 17 | public boolean enqueue(T item) { 18 | // 队满条件 19 | if ((tail + 1) % capacity == head) { 20 | return false; 21 | } 22 | 23 | items[tail] = item; 24 | tail = (tail + 1) % capacity; 25 | return true; 26 | } 27 | 28 | // T(N)=O(1) 29 | public T dequeue() { 30 | // 队空条件 31 | if (head == tail) { 32 | return null; 33 | } 34 | 35 | T tmp = items[head]; 36 | items[head] = null; // 这里可以选择置为nulL,也可以不置为null. 37 | head = (head + 1) % capacity; 38 | 39 | return tmp; 40 | } 41 | 42 | // for test 43 | public void printAll() { 44 | System.out.print("["); 45 | for (int i = 0; i < capacity; i++) { 46 | System.out.print(items[i] + " "); 47 | } 48 | System.out.print("]"); 49 | System.out.println(); 50 | } 51 | 52 | public static void main(String[] args) { 53 | CircularQueue queue = new CircularQueue<>(4); 54 | queue.printAll(); 55 | queue.enqueue("A"); 56 | queue.printAll(); 57 | queue.enqueue("B"); 58 | queue.enqueue("C"); 59 | queue.enqueue("D"); 60 | queue.printAll(); 61 | queue.enqueue("E"); 62 | queue.printAll(); 63 | 64 | queue.dequeue(); 65 | queue.dequeue(); 66 | queue.enqueue("E"); 67 | queue.printAll(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /algorithms/src/queue/ListQueue.java: -------------------------------------------------------------------------------- 1 | package queue; 2 | 3 | public class ListQueue implements Queue { 4 | 5 | Node head = null; 6 | Node tail = null; 7 | 8 | // T(N)=O(1) 9 | @Override 10 | public boolean enqueue(T item) { 11 | Node newNode = new Node(item, null); 12 | if (tail == null) { 13 | tail = newNode; 14 | head = newNode; 15 | return true; 16 | } 17 | 18 | tail.next = newNode; 19 | tail = tail.next; 20 | 21 | return true; 22 | } 23 | 24 | // T(N)=O(1) 25 | @Override 26 | public T dequeue() { 27 | if (head == null) { 28 | return null; 29 | } 30 | 31 | Node tmp = head; 32 | head = head.next; 33 | tmp.next = null; 34 | 35 | return (T) tmp.getData(); 36 | } 37 | 38 | // for test 39 | public void printAll() { 40 | System.out.print("["); 41 | for (Node p = head; p != null; p = p.next) { 42 | System.out.print(p.getData() + " "); 43 | } 44 | System.out.print("]"); 45 | System.out.println(); 46 | } 47 | 48 | private static class Node{ 49 | private T data; 50 | private Node next; 51 | 52 | public Node(T data, Node next) { 53 | this.data = data; 54 | this.next = next; 55 | } 56 | 57 | public T getData() { 58 | return this.data; 59 | } 60 | } 61 | 62 | public static void main(String[] args) { 63 | ListQueue queue = new ListQueue<>(); 64 | queue.printAll(); 65 | queue.enqueue("A"); 66 | queue.printAll(); 67 | queue.enqueue("B"); 68 | queue.enqueue("C"); 69 | queue.enqueue("D"); 70 | queue.printAll(); 71 | queue.enqueue("E"); 72 | queue.printAll(); 73 | 74 | queue.dequeue(); 75 | queue.dequeue(); 76 | queue.dequeue(); 77 | queue.printAll(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /algorithms/src/queue/Queue.java: -------------------------------------------------------------------------------- 1 | package queue; 2 | 3 | public interface Queue { 4 | boolean enqueue(T item); 5 | T dequeue(); 6 | } 7 | -------------------------------------------------------------------------------- /algorithms/src/stack/ArrayStack.java: -------------------------------------------------------------------------------- 1 | package stack; 2 | 3 | public class ArrayStack implements Stack { 4 | private T[] items; // 数组 5 | private int top; // 栈中元素的个数(或者说是栈顶指针) 6 | private int capacity; // 栈的容量 7 | 8 | 9 | public ArrayStack(int capacity) { 10 | this.capacity = capacity; 11 | this.items = (T[]) new Object[capacity]; 12 | this.top = 0; 13 | } 14 | 15 | // T(N)=O(1) 16 | @Override 17 | public boolean push(T item) { 18 | // 数组空间不足,无法push 19 | if (top == capacity) { 20 | return false; 21 | } 22 | 23 | // size为待push的位置 24 | items[top] = item; 25 | top++; 26 | 27 | return true; 28 | } 29 | 30 | // T(N)=O(1) 31 | @Override 32 | public T pop() { 33 | // 数组为空,无法pop 34 | if (top == 0) { 35 | return null; 36 | } 37 | 38 | T item = items[top -1]; 39 | top--; 40 | 41 | return item; 42 | } 43 | 44 | // T(N)=O(1) 45 | @Override 46 | public T peek() { 47 | if (top == 0) { 48 | return null; 49 | } 50 | return items[top -1]; 51 | } 52 | 53 | public static void main(String[] args) { 54 | ArrayStack stack = new ArrayStack<>(4); 55 | stack.push("A"); 56 | stack.push("B"); 57 | stack.push("C"); 58 | stack.push("D"); 59 | System.out.println(stack.peek()); 60 | stack.pop(); 61 | System.out.println(stack.peek()); 62 | stack.pop(); 63 | stack.pop(); 64 | stack.pop(); 65 | stack.pop(); 66 | System.out.println(stack.peek()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /algorithms/src/stack/DynamicArrayStack.java: -------------------------------------------------------------------------------- 1 | package stack; 2 | 3 | /** 4 | * 支持动态扩容的栈 5 | * 6 | * @param 7 | */ 8 | public class DynamicArrayStack implements Stack { 9 | private T[] items; 10 | private int top; 11 | private int capacity; 12 | 13 | public DynamicArrayStack(int capacity) { 14 | this.capacity = capacity; 15 | this.items = (T[]) new Object[capacity]; 16 | this.top = 0; 17 | } 18 | 19 | // T(N)=O(1): 思考一下,这里涉及到了数组的动态扩容, 20 | // 那么时间复杂度为什么仍然是O(1) 21 | @Override 22 | public boolean push(T item) { 23 | if (top == capacity) { 24 | capacity = capacity * 2; 25 | resize(capacity); 26 | } 27 | 28 | items[top] = item; 29 | top++; 30 | 31 | return false; 32 | } 33 | 34 | // T(N)=O(1) 35 | @Override 36 | public T pop() { 37 | if (top == 0) { 38 | return null; 39 | } 40 | 41 | T item = items[top -1]; 42 | top--; 43 | 44 | return item; 45 | } 46 | 47 | // T(N)=O(1) 48 | @Override 49 | public T peek() { 50 | if (top == 0) { 51 | return null; 52 | } 53 | return items[top -1]; 54 | } 55 | 56 | private void resize(int size) { 57 | T[] tmp = (T[]) new Object[size]; 58 | for (int i = 0; i < items.length; i++) { 59 | tmp[i] = this.items[i]; 60 | } 61 | 62 | this.items = tmp; 63 | } 64 | 65 | public static void main(String[] args) { 66 | DynamicArrayStack stack = new DynamicArrayStack<>(4); 67 | stack.push("A"); 68 | stack.push("B"); 69 | stack.push("C"); 70 | stack.push("D"); 71 | System.out.println(stack.peek()); 72 | stack.push("E"); 73 | System.out.println(stack.peek()); 74 | stack.pop(); 75 | System.out.println(stack.peek()); 76 | stack.pop(); 77 | stack.pop(); 78 | stack.pop(); 79 | stack.pop(); 80 | System.out.println(stack.peek()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /algorithms/src/stack/ListStack.java: -------------------------------------------------------------------------------- 1 | package stack; 2 | 3 | public class ListStack implements Stack { 4 | private Node top = null; 5 | 6 | // T(N)=O(1) 7 | @Override 8 | public boolean push(T item) { 9 | Node newNode = new Node(item, null); 10 | 11 | // 需要判断栈是否为空 12 | if (top == null) { 13 | top = newNode; 14 | } else { 15 | newNode.next = top; 16 | top = newNode; 17 | } 18 | return true; 19 | } 20 | 21 | // T(N)=O(1) 22 | @Override 23 | public T pop() { 24 | if (top == null) { 25 | return null; 26 | } 27 | 28 | Node tmp = top; 29 | 30 | top = top.next; 31 | tmp.next = null; // 释放删除的top 32 | 33 | return (T) tmp.getData(); 34 | } 35 | 36 | // T(N)=O(1) 37 | @Override 38 | public T peek() { 39 | if (top == null) { 40 | return null; 41 | } 42 | return (T) top.getData(); 43 | } 44 | 45 | public static class Node { 46 | private T data; 47 | private Node next; 48 | 49 | public Node(T data, Node next) { 50 | this.data = data; 51 | this.next = next; 52 | } 53 | 54 | public T getData() { 55 | return this.data; 56 | } 57 | } 58 | 59 | public static void main(String[] args) { 60 | ListStack stack = new ListStack<>(); 61 | stack.push("A"); 62 | stack.push("B"); 63 | stack.push("C"); 64 | stack.push("D"); 65 | System.out.println(stack.peek()); 66 | stack.pop(); 67 | System.out.println(stack.peek()); 68 | stack.pop(); 69 | stack.pop(); 70 | stack.pop(); 71 | stack.pop(); 72 | System.out.println(stack.peek()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /algorithms/src/stack/SampleBrowser.java: -------------------------------------------------------------------------------- 1 | package stack; 2 | 3 | /** 4 | * 浏览器页面的前进和后退功能 5 | */ 6 | public class SampleBrowser { 7 | 8 | private String currentPage; 9 | // private Stack backwardStack; 10 | private Stac 11 | 12 | } 13 | -------------------------------------------------------------------------------- /algorithms/src/stack/Stack.java: -------------------------------------------------------------------------------- 1 | package stack; 2 | 3 | public interface Stack { 4 | boolean push(T item); 5 | T pop(); 6 | T peek(); 7 | } 8 | -------------------------------------------------------------------------------- /appendix/instructions.md: -------------------------------------------------------------------------------- 1 | # 上传与更新本地代码到Github 2 | 3 | 1. 远程操作: 4 | * Github上创建Repo 5 | 2. 本地操作: 6 | * git clone https://github.com/guokaide/leetcode 7 | * cd leetcode 8 | * git init 9 | * git add . 10 | * git remote add origin https://github.com/guokaide/leetcode (将本地仓库与远程关联) 11 | * git commit -m "update all files" 12 | * git pull origin master (将remote所有的操作更新到本地,避免local与remote冲突) 13 | * git push -u origin master 14 | 3. 注:核心更新操作 15 | * git status 16 | * git add * 17 | * git commit -m "comments" 18 | * git pull origin master 19 | * git push origin master 20 | 21 | -------------------------------------------------------------------------------- /leetcode/leetcode.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /leetcode/src/linkedlistcycle_141/LinkedListCycle.java: -------------------------------------------------------------------------------- 1 | package linkedlistcycle_141; 2 | 3 | /** 4 | * 141. Linked List Cycle 5 | * https://leetcode.com/problems/linked-list-cycle/ 6 | */ 7 | public class LinkedListCycle { 8 | public boolean hasCycle(ListNode head) { 9 | if (head == null || head.next == null) { 10 | return false; 11 | } 12 | 13 | ListNode fast = head; 14 | ListNode slow = head; 15 | 16 | while (fast != null && fast.next != null) { 17 | fast = fast.next.next; 18 | slow = slow.next; 19 | if (fast == slow) return true; 20 | } 21 | 22 | return false; 23 | } 24 | 25 | public static class ListNode { 26 | int val; 27 | ListNode next; 28 | ListNode(int x) { val = x;} 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /leetcode/src/lrucache_146/LRUCache.java: -------------------------------------------------------------------------------- 1 | package lrucache_146; 2 | 3 | 4 | import java.util.HashMap; 5 | 6 | /** 7 | * 146. LRU Cache 8 | * https://leetcode.com/problems/lru-cache/description/ 9 | */ 10 | public class LRUCache { 11 | private Node head; 12 | private Node tail; 13 | private HashMap map; 14 | private int capacity; 15 | 16 | public LRUCache(int capacity) { 17 | this.capacity = capacity; 18 | this.map = new HashMap<>(capacity * 4 / 3); 19 | 20 | head = new Node(-1,-1); 21 | tail = new Node(-1,-1); 22 | 23 | head.next = tail; 24 | tail.pre = head; 25 | } 26 | 27 | public int get(int key) { 28 | // key 不存在 29 | if (!map.containsKey(key)) { 30 | return -1; 31 | } 32 | 33 | // key 存在 34 | Node node = map.get(key); 35 | delete(node); 36 | insertToHead(node); 37 | 38 | return node.value; 39 | } 40 | 41 | public void put(int key, int value) { 42 | // key 存在 43 | if (map.containsKey(key)) { 44 | Node node = map.get(key); 45 | delete(node); 46 | } 47 | // key 不存在 48 | Node node = new Node(key, value); 49 | insertToHead(node); 50 | map.put(key, node); 51 | 52 | if (map.size() > capacity) { 53 | Node remove = deleteTail(); 54 | map.remove(remove.key); 55 | } 56 | } 57 | 58 | private void delete(Node node) { 59 | Node next = node.next; 60 | Node pre = node.pre; 61 | 62 | pre.next = next; 63 | next.pre = pre; 64 | 65 | node.next = null; 66 | node.pre = null; 67 | } 68 | 69 | private void insertToHead(Node node) { 70 | Node next = head.next; 71 | node.next = next; 72 | node.pre = head; 73 | 74 | next.pre = node; 75 | head.next = node; 76 | } 77 | 78 | private Node deleteTail() { 79 | Node node = tail.pre; 80 | 81 | Node pre = node.pre; 82 | tail.pre = pre; 83 | pre.next = tail; 84 | 85 | node.next = null; 86 | node.pre = null; 87 | 88 | return node; 89 | } 90 | 91 | private class Node { 92 | int key; 93 | int value; 94 | Node pre; 95 | Node next; 96 | 97 | public Node (int key, int value) { 98 | this.key = key; 99 | this.value = value; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /leetcode/src/mergetwosortedlist_21/Merge2SortedLists.java: -------------------------------------------------------------------------------- 1 | package mergetwosortedlist_21; 2 | 3 | /** 4 | * 21. Merge Two Sorted Lists 5 | * https://leetcode.com/problems/merge-two-sorted-lists/ 6 | */ 7 | public class Merge2SortedLists { 8 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 9 | if (l1 == null) return l2; 10 | if (l2 == null) return l1; 11 | 12 | // 利用哨兵(前哨节点)简化实现难度 13 | ListNode outpost = new ListNode(-1); 14 | ListNode temp = outpost; 15 | 16 | while (l1 != null && l2 != null) { 17 | if (l1.val <= l2.val) { 18 | temp.next = l1; 19 | l1 = l1.next; 20 | } else { 21 | temp.next = l2; 22 | l2 = l2.next; 23 | } 24 | 25 | temp = temp.next; 26 | } 27 | 28 | if (l1 == null) { 29 | temp.next = l2; 30 | } 31 | 32 | if (l2 == null) { 33 | temp.next = l1; 34 | } 35 | 36 | return outpost.next; 37 | } 38 | 39 | public ListNode mergeTwoListsRecur(ListNode l1, ListNode l2) { 40 | if (l1 == null) return l2; 41 | if (l2 == null) return l1; 42 | if (l1.val < l2.val) { 43 | l1.next = mergeTwoListsRecur(l1.next, l2); 44 | return l1; 45 | } else { 46 | l2.next = mergeTwoListsRecur(l1, l2.next); 47 | return l2; 48 | } 49 | } 50 | 51 | public static class ListNode { 52 | int val; 53 | ListNode next; 54 | ListNode(int x) { val = x;} 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /leetcode/src/middleofthelinkedlist_876/MiddleNode.java: -------------------------------------------------------------------------------- 1 | package middleofthelinkedlist_876; 2 | 3 | /** 4 | * 876. Middle of the Linked List 5 | * https://leetcode.com/problems/middle-of-the-linked-list/ 6 | */ 7 | public class MiddleNode { 8 | public ListNode middleNode(ListNode head) { 9 | ListNode fast = head; 10 | ListNode slow = head; 11 | 12 | while (fast != null && fast.next != null) { 13 | fast = fast.next.next; 14 | slow = slow.next; 15 | } 16 | 17 | return slow; 18 | } 19 | 20 | 21 | public static class ListNode { 22 | int val; 23 | ListNode next; 24 | ListNode(int x) { val = x;} 25 | } 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /leetcode/src/palindromelinkedlist_234/PalindromeLinkedList.java: -------------------------------------------------------------------------------- 1 | package palindromelinkedlist_234; 2 | 3 | /** 4 | * 234. Palindrome Linked List 5 | * https://leetcode.com/problems/palindrome-linked-list/ 6 | * Solution: 7 | * 1. 找到中间节点,将单链表后半段逆置 8 | * 2. 左半段从左到右,右半段从右到左,比较2段链表是否对应相等 9 | * 3. 对比完之后,最好能将右半段逆置,还原链表 10 | * 示例: 11 | * 1->2->2->1 12 | * 1->2->2<-1 (第2个2指向null) 13 | */ 14 | public class PalindromeLinkedList { 15 | public boolean isPalindrome(ListNode head) { 16 | // 1. 找到单链表的中间节点 17 | ListNode fast = head; 18 | ListNode slow = head; 19 | 20 | while (fast != null && fast.next != null) { 21 | fast = fast.next.next; 22 | slow = slow.next; // 此时slow就是中间节点 23 | } 24 | 25 | // 2. 从中间节点开始,将右半段链表逆置 26 | ListNode pre = null; 27 | ListNode next = null; 28 | 29 | while (slow != null) { 30 | next = slow.next; 31 | slow.next = pre; 32 | pre = slow; 33 | slow = next; 34 | } 35 | 36 | // 3. 左半段从左到右,右半段从右到左,比较2段链表是否对应相等 37 | fast = head; 38 | slow = pre; 39 | 40 | while (slow != null) { 41 | if (fast.val != slow.val) { 42 | return false; 43 | } 44 | fast = fast.next; 45 | slow = slow.next; 46 | } 47 | 48 | // 4. 对比完之后,最好能将右半段逆置,还原链表 49 | 50 | return true; 51 | 52 | } 53 | 54 | 55 | public static class ListNode { 56 | int val; 57 | ListNode next; 58 | ListNode(int x) { 59 | this.val = val; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /leetcode/src/removenthnodefromendoflist_19/RemoveNthNodeFromEndOfList.java: -------------------------------------------------------------------------------- 1 | package removenthnodefromendoflist_19; 2 | 3 | /** 4 | * 19. Remove Nth Node From End of List 5 | * https://leetcode.com/problems/remove-nth-node-from-end-of-list/ 6 | */ 7 | public class RemoveNthNodeFromEndOfList { 8 | public ListNode removeNthFromEnd(ListNode head, int n) { 9 | ListNode p1 = head; 10 | 11 | for (int i = 0; i < n; i++) { 12 | p1 = p1.next; 13 | } 14 | 15 | ListNode p2 = head; // 要删除的节点 16 | ListNode pre = null; 17 | 18 | while (p1 != null) { 19 | p1 = p1.next; 20 | pre = p2; 21 | p2 = p2.next; 22 | } 23 | 24 | if (p2 == head) { // 要删除的节点为head,特殊处理 25 | head = head.next; 26 | } else { 27 | pre.next = p2.next; 28 | p2.next = null; 29 | } 30 | 31 | return head; 32 | } 33 | 34 | public static class ListNode { 35 | int val; 36 | ListNode next; 37 | ListNode(int x) { 38 | this.val = val; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /leetcode/src/reverselinkedlist_206/ReverseList.java: -------------------------------------------------------------------------------- 1 | package reverselinkedlist_206; 2 | 3 | /** 4 | * 206. Reverse Linked List 5 | * https://leetcode.com/problems/reverse-linked-list/ 6 | */ 7 | public class ReverseList { 8 | public ListNode reverseList(ListNode head) { 9 | if (head == null || head.next == null) return head; 10 | 11 | ListNode pre = null; 12 | ListNode next = null; 13 | 14 | while (head != null) { 15 | next = head.next; 16 | head.next = pre; 17 | pre = head; 18 | head = next; 19 | } 20 | 21 | return pre; 22 | } 23 | 24 | public static class ListNode { 25 | int val; 26 | ListNode next; 27 | ListNode(int x) { 28 | this.val = val; 29 | } 30 | } 31 | } 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /leetcode/src/threesum_015/ThreeSum.java: -------------------------------------------------------------------------------- 1 | package threesum_015; 2 | 3 | public class ThreeSum { 4 | } 5 | -------------------------------------------------------------------------------- /leetcode/src/twosum_001/TwoSum.java: -------------------------------------------------------------------------------- 1 | package twosum_001; 2 | 3 | public class TwoSum { 4 | public static void main(String[] args) { 5 | 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /offer/offer.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Attention.txt: -------------------------------------------------------------------------------- 1 | - 面试沟通 2 | (1)面试时,要经常和面试官沟通。沟通好题目条件、问题的意图之后再动手coding或者回答问题。 3 | (2)面试中,若面试官提出新的概念,面试者需要和面试官积极沟通,多问几个问题,把概念搞清楚。 4 | (3)面试中,若有多种解法,且多种解法各有优缺点,则需要和面试官沟通,确定问题需要的最合适的解法。 5 | (4)考虑性能的时候,是关注时间还是空间?其复杂度要求是多少? 6 | 考虑实现的时候,是否可以修改原来的结构?是否可以在新的结构中操作? 7 | 8 | - 排序和查找 9 | --查找:顺序查找 二分查找 哈希表查找 二叉排序树(其实就是二叉搜索树)查找 10 | (1) 二分查找:要求在排序或者是部分排序的数组中查找一个数字或者统计某个数字出现的次数,可以尝试二分查找。 11 | (2) 哈希表&二叉排序树:重点在于考察数据结构本身,不在于算法 12 | (3) 哈希表:优点是能够在O(1)内找到某一个元素,是效率最高的查找方式。缺点是需要额外空间实现哈希表。 13 | 14 | -- 排序:插入排序 冒泡排序 归并排序 快速排序 15 | 关注其实现,性能,场景等 16 | 17 | - 回溯法: 18 | (1)类似于暴力解答 19 | (2)常常使用递归,回溯法很适合递归实现。递归可以用栈来模拟。 20 | 注:二维数组或者迷宫问题,可以尝试回溯法。 21 | 22 | - 递归与循环: 23 | (1)递归:由于递归实现更加简洁,若没有特殊要求,可以优先选用递归实现。 24 | 效率问题:递归可能存在大量的重复运算,因此性能可能弱于循环。如:Ex_10_Fibonacci 25 | 栈溢出问题:递归还可能引起调用栈溢出的问题。 26 | 27 | (2)思考:一般用递归的方式思考答案,用循环的方式实现代码。 28 | 29 | - 动态规划 30 | (1)动态规划多可以用递归解决; 31 | (2)但是递归中有很多需要重复计算的项,如Ex_10_Fibonacci 32 | (3)动态规划从下到上,将重复的子问题的答案存储起来,减少了重复计算的时间浪费,但是增加了空间的消耗。 33 | 34 | - 贪心算法 35 | 36 | - 说明 37 | (1) 若求某个问题的最优解,且该问题可以分解为多个子问题,则可以尝试动态规划。 38 | 递归操作是自上而下,动态规划则是自下而上,避免不必要的重复计算。 39 | 若是某个问题有特殊的选择,那么这个问题的最优解可能就是贪婪算法得出的。 40 | (2) 思考路线:递归->动态规划->贪婪算法 41 | 42 | - 位运算 43 | (1) 基本运算:与、或、异或、左移、右移 44 | (2) 把一个整数减1之后再和原来的整数做位与运算,相当于将整数的二进制表示中的最右边的1变成0: 45 | x = (x - 1) & x : 将x的二进制最右边的1变成了0 46 | 47 | - 高质量的代码 48 | -- 代码的规范性 49 | (1)书写清晰 50 | (2)布局清晰 51 | (3)命名合理 52 | -- 代码的完整性 53 | (1)功能测试:基本功能 54 | (2)边界测试:边界值 55 | (3)负面测试:非法值 56 | 57 | -- 代码的鲁棒性:程序对输入的合法性判断以及对非法输入的处理 58 | --- 容错性 59 | --- 防御性编程 60 | 61 | --注:在处理链表问题时,当我们用一个指针遍历链表无法解决问题时,可以尝试用2个指针解决问题。 62 | 可以让一个指针遍历的速度快一点(一次走2步,或者先走若干步),让另外一个指针遍历的速度慢一点 63 | 64 | --注: 65 | (1)若面试题是关于n位的整数且没有限定n的取值范围,或者输入任意大小的整数,则此题目可能需要考虑大数问题。 66 | (2)大数问题如何处理?字符串是一种有效的地表示大数地方法。 67 | (3)例:Ex_17_AddTwoBigNumber 68 | 69 | - 解决面试题的思路 70 | -- 在解决笔试或者面试题目之前,应该思考清楚题目的解决思路,然后再进行编码。 71 | 72 | -- 画图 73 | -- 举例 74 | -- 分解 75 | 76 | -- 注: 77 | 1. 二叉树遍历 78 | -- 先序 Stack T26:树的子结构; T7:重建二叉树 T37:树的序列化和反序列化 79 | -- 中序 Stack T7:重建二叉树 80 | -- 后序 Stack T33:判断一个序列是否是BST的后序(先序)遍历序列; 81 | -- Morris遍历 Stack 82 | -- 宽度优先遍历:层遍历(也叫广度优先遍历)T32:从上到下打印二叉树 83 | -- 不分行 Queue 84 | -- 分行 Queue + 记录节点 85 | -- 之字形 Stack * 2 86 | -- 深度优先遍历:先序遍历 T34:二叉树中和为某一个值的路径 87 | 88 | 2. 二叉树分类 89 | -- 二叉搜索树 90 | -- 红黑树 91 | -- 二叉堆 92 | 3. 技巧: 93 | -- 若要求处理二叉树的遍历序列,则可以先找到二叉树的根节点, 94 | 然后基于根节点将二叉树的遍历序列分成左子树和右子树对应的子序列 分界:i 95 | 然后递归处理这2个子序列.模式如下 96 | process(sequence, start, end) 97 | -> process(sequence, start, i-1) 98 | -> process(sequence, i, end) 99 | --- 例如:面试题33:判断一个序列是否是BST的后序(先序)遍历序列; 100 | 面试题7:重建二叉树 101 | 102 | - 优化时间和空间效率 103 | 104 | -- 注:若需要判断多个字符是否在某个字符串中出现过或者统计其出现的次数,考虑哈希表,或者考虑基于数组创建一个简单的哈希表, 105 | 这样可以用很小得空间消耗换来时间效率的提升。 106 | 107 | -- 如何降低时间复杂度? 108 | 1. 改用更高效的算法 109 | 2. 空间换时间 110 | 111 | 112 | -- 递归与动态规划 113 | 114 | - 面试考察能力 115 | 116 | --编程能力 117 | --学习能力 118 | --抽象建模能力 119 | --发散思维能力 120 | --知识迁移能力 121 | --沟通能力 122 | 123 | ******************************************************* 124 | - 编写程序时需要考虑的一些问题: 125 | -- 关注鲁棒性:边界条件 特殊输入 错误处理等 126 | -- 编写过程: 127 | 测试用例 128 | -> 找出规律 129 | -> 编程 130 | -> 检验 (基本功能、边界条件、错误处理) 131 | -> 优化 -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_03_FindDuplicatedNumInArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * problem 3: 数组中重复的数字 7 | * 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 8 | * 数组中某些数字是重复的,但不知道有几个数字是重复的。 9 | * 也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 10 | * 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。 11 | */ 12 | public class Ex_03_FindDuplicatedNumInArray { 13 | 14 | public boolean duplicate(int numbers[], int [] duplication) { 15 | if (numbers == null || numbers.length < 2) { 16 | return false; 17 | } 18 | 19 | HashMap map = new HashMap<>(); 20 | for (int i = 0; i < numbers.length; i++) { 21 | if (!map.containsKey(numbers[i])) { 22 | map.put(numbers[i], 1); 23 | } else { 24 | duplication[0] = numbers[i]; 25 | return true; 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | /** 32 | * 由于numbers数组中的元素[0,n-1] 33 | * 若没有重复元素,排序之后i位置为i 34 | * 若有重复元素,则i位置为i,但是其他位置也可能有i 35 | * 思路: 36 | * 遍历数组 37 | * 若i位置为i,i++ 38 | * 若i位置不是i 39 | * (1)m = numbers[i], 则m的正确位置为numbers[m], 若numbers[m] = m,则重复元素就是m,否则 40 | * (2) 交换m到正确的位置上。 41 | * @param numbers 42 | * @param duplication 43 | * @return 44 | */ 45 | public boolean duplicateImprove(int numbers[], int [] duplication) { 46 | if (numbers == null || numbers.length < 2) { 47 | return false; 48 | } 49 | 50 | for (int i = 0; i < numbers.length; i++) { 51 | if (numbers[i] == i) { 52 | i++; 53 | } else { 54 | int m = numbers[i]; 55 | if (numbers[m] == m) { 56 | duplication[0] = m; 57 | return true; 58 | } else { 59 | swap(numbers, i, m); 60 | } 61 | } 62 | } 63 | return false; 64 | } 65 | 66 | private static void swap(int[] arr, int i, int j) { 67 | int tmp = arr[i]; 68 | arr[i] = arr[j]; 69 | arr[j] = tmp; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_03_FindDuplicatedNumInWithoutChangeArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * problem 3: 不修改数组找出重复的数字。 [binary search] 5 | * 6 | * 特性:若数组中没有重复元素,则[x,y]范围内的数字个数为y-x+1,若超出这个个数,则说明有重复的数字。 7 | */ 8 | public class Ex_03_FindDuplicatedNumInWithoutChangeArray { 9 | 10 | public static int duplicate(int numbers[]) { 11 | if (numbers == null || numbers.length < 2) { 12 | return -1; 13 | } 14 | 15 | int start = 1; 16 | int end = numbers.length - 1; 17 | 18 | while(start <= end) { 19 | int mid = start + ((end - start) >> 1); // 这里 >> 一定要放在括号内 20 | int count = countRange(numbers, start, mid); 21 | 22 | if (start == end) { 23 | if (count > 1) { 24 | return start; 25 | } else { 26 | break; 27 | } 28 | } 29 | 30 | if (count > (mid - start + 1)) { 31 | end = mid; 32 | } else { 33 | start = mid + 1; 34 | } 35 | } 36 | 37 | return -1; 38 | } 39 | 40 | private static int countRange(int[] numbers, int start, int end) { 41 | if (numbers == null) { 42 | return 0; 43 | } 44 | 45 | int count = 0; 46 | for (int i = 0; i < numbers.length; i++) { 47 | if (numbers[i] <= end && numbers[i] >= start) { 48 | count++; 49 | } 50 | } 51 | 52 | return count; 53 | } 54 | 55 | public static void main(String[] args) { 56 | int[] numbers = new int[]{2, 3, 5, 4, 3, 2, 6, 7}; 57 | int duplicate = duplicate(numbers); 58 | System.out.println(duplicate); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_04_FindNumIn2VArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 1.在一个二维数组中,每一行都按照从左到右递增的顺序排序, 5 | * 每一列都按照从上到下递增的顺序排序。请完成一个函数, 6 | * 输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 7 | */ 8 | public class Ex_04_FindNumIn2VArray { 9 | 10 | public static boolean Find(int target, int[][] array) { 11 | if (array == null || array.length == 0) { 12 | return false; 13 | } 14 | 15 | //从右上角向左下遍历 16 | int row = 0; 17 | int col = array[0].length - 1; 18 | 19 | while (row < array.length && col > -1) { 20 | if (array[row][col] == target) { 21 | return true; 22 | } else if (array[row][col] < target) { 23 | row++; 24 | } else { 25 | col--; 26 | } 27 | } 28 | return false; 29 | } 30 | 31 | public static void main(String[] args) { 32 | int[][] array = new int[][] { { 0, 1, 2, 3, 4, 5, 6 },// 0 33 | { 10, 12, 13, 15, 16, 17, 18 },// 1 34 | { 23, 24, 25, 26, 27, 28, 29 },// 2 35 | { 44, 45, 46, 47, 48, 49, 50 },// 3 36 | { 65, 66, 67, 68, 69, 70, 71 },// 4 37 | { 96, 97, 98, 99, 100, 111, 122 },// 5 38 | { 166, 176, 186, 187, 190, 195, 200 },// 6 39 | { 233, 243, 321, 341, 356, 370, 380 } // 7 40 | }; 41 | int target = 233; 42 | System.out.println(Find(target, array)); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_05_ReplaceSpace.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 2.请实现一个函数,将一个字符串中的空格替换成“%20”。 5 | * 例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。 6 | */ 7 | public class Ex_05_ReplaceSpace { 8 | public static String replaceSpace(StringBuffer str) { 9 | String s = str.toString(); 10 | String res = s.replaceAll(" ", "%20"); 11 | return res; 12 | } 13 | 14 | /** 15 | * 问题1:替换字符串,是在原来的字符串上做替换,还是新开辟一个字符串做替换! 16 | * 问题2:在当前字符串替换,怎么替换才更有效率(不考虑java里现有的replace方法)。 17 | * 从前往后替换,后面的字符要不断往后移动,要多次移动,所以效率低下 18 | * 从后往前,先计算需要多少空间,然后从后往前移动,则每个字符只移动一次,这样效率更高。 19 | * 20 | * @param str 21 | * @return 22 | */ 23 | public static String replaceBlank(StringBuffer str) { 24 | if (str == null) { 25 | return null; 26 | } 27 | 28 | int spaceNum = 0; 29 | for (int i = 0; i < str.length(); i++) { 30 | if (str.charAt(i) == ' ') { 31 | spaceNum++; 32 | } 33 | } 34 | 35 | int len = str.length() + 2 * spaceNum; 36 | int indexOld = str.length() - 1; 37 | int indexNew = len - 1; 38 | str.setLength(len); 39 | 40 | while (indexOld >= 0) { 41 | if (str.charAt(indexOld) == ' ') { 42 | str.setCharAt(indexNew--, '0'); 43 | str.setCharAt(indexNew--, '2'); 44 | str.setCharAt(indexNew--, '%'); 45 | 46 | } else { 47 | str.setCharAt(indexNew--, str.charAt(indexOld)); 48 | } 49 | 50 | indexOld--; 51 | } 52 | 53 | return str.toString(); 54 | } 55 | 56 | public static void main(String[] args) { 57 | StringBuffer str = new StringBuffer(); 58 | str.append("We Are Happy"); 59 | String s = replaceBlank(str); 60 | System.out.print(s); 61 | 62 | System.out.println(); 63 | 64 | StringBuffer str1 = new StringBuffer(); 65 | str1.append(""); 66 | String s1 = replaceBlank(str1); 67 | System.out.print(s1); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_06_PrintListFromTailToHead.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Stack; 7 | 8 | public class Ex_06_PrintListFromTailToHead { 9 | 10 | public static ArrayList printListFromTailToHead(ListNode listNode) { 11 | if (listNode == null) { 12 | return new ArrayList<>(); 13 | } 14 | 15 | Stack stack = new Stack<>(); 16 | ArrayList list = new ArrayList<>(); 17 | for (ListNode node = listNode; node != null; node = node.next) { 18 | stack.push(node.val); 19 | } 20 | 21 | while(!stack.isEmpty()) { 22 | list.add(stack.pop()); 23 | } 24 | 25 | return list; 26 | } 27 | 28 | public static ArrayList printListFromTailToHeadRecur(ListNode listNode) { 29 | ArrayList list = new ArrayList<>(); 30 | 31 | if (listNode != null) { 32 | 33 | if (listNode.next != null) { 34 | ArrayList temp = new ArrayList<>(); 35 | temp = printListFromTailToHeadRecur(listNode.next); 36 | for (Integer i : temp) { 37 | list.add(i); 38 | } 39 | } 40 | 41 | list.add(listNode.val); 42 | } 43 | 44 | return list; 45 | } 46 | 47 | public static ArrayList printListFromTailToHeadWithCollections(ListNode listNode) { 48 | ArrayList list = new ArrayList<>(); 49 | 50 | for (ListNode p = listNode; p != null; p = p.next) { 51 | list.add(p.val); 52 | } 53 | 54 | Collections.reverse(list); 55 | return list; 56 | } 57 | 58 | public static void main(String[] args) { 59 | ListNode head = new ListNode(1); 60 | head.next = new ListNode(2); 61 | head.next.next = new ListNode(3); 62 | head.next.next.next = new ListNode(4); 63 | 64 | ArrayList list = new ArrayList<>(); 65 | list = printListFromTailToHeadRecur(head); 66 | 67 | } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_07_ReConstructBT.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 4.输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。 5 | * 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 6 | * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}, 7 | * 则重建二叉树并返回。 8 | * 9 | * 思路: 10 | * 1.pre负责确定树的root; 11 | * 2.in负责确定树的root.left,root.right,即左右子树; 12 | * 3.递归1,2 13 | */ 14 | public class Ex_07_ReConstructBT { 15 | 16 | public static TreeNode reConstructBinaryTree(int[] pre, int[] in) { 17 | if (pre == null || in == null || pre.length == 0 || in.length == 0) { 18 | return null; 19 | } 20 | TreeNode root = reConstructBinaryTree(pre, 0, pre.length-1, in, 0, in.length-1); 21 | return root; 22 | } 23 | 24 | private static TreeNode reConstructBinaryTree(int[] pre, int preStart, int preEnd, int[] in, int inStart, int inEnd) { 25 | if (preStart > preEnd || inStart > inEnd) { 26 | return null; 27 | } 28 | 29 | TreeNode root = new TreeNode(pre[preStart]); 30 | for (int i = inStart; i <= inEnd; i++) { 31 | if (in[i] == pre[preStart]) { 32 | root.left = reConstructBinaryTree(pre, preStart+1, preStart+(i-inStart), in, inStart, i-1); 33 | root.right = reConstructBinaryTree(pre, preStart + 1 + (i-inStart), preEnd, in, i+1, inEnd); 34 | break; 35 | } 36 | } 37 | return root; 38 | } 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_08_DescendantNode.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_08_DescendantNode { 4 | 5 | public static class Node { 6 | public int value; 7 | public Node left; 8 | public Node right; 9 | public Node parent; 10 | 11 | public Node(int data) { 12 | this.value = data; 13 | } 14 | } 15 | 16 | public static Node getNextNode(Node node) { 17 | if (node == null) { 18 | return node; 19 | } 20 | if (node.right != null) { 21 | return getLeftMost(node.right); 22 | } else { 23 | Node parent = node.parent; 24 | while (parent != null && parent.left != node) { 25 | node = parent; 26 | parent = node.parent; 27 | } 28 | return parent; 29 | } 30 | } 31 | 32 | public static Node getLeftMost(Node node) { 33 | if (node == null) { 34 | return node; 35 | } 36 | while (node.left != null) { 37 | node = node.left; 38 | } 39 | return node; 40 | } 41 | 42 | public static void main(String[] args) { 43 | Node head = new Node(6); 44 | head.parent = null; 45 | head.left = new Node(3); 46 | head.left.parent = head; 47 | head.left.left = new Node(1); 48 | head.left.left.parent = head.left; 49 | head.left.left.right = new Node(2); 50 | head.left.left.right.parent = head.left.left; 51 | head.left.right = new Node(4); 52 | head.left.right.parent = head.left; 53 | head.left.right.right = new Node(5); 54 | head.left.right.right.parent = head.left.right; 55 | head.right = new Node(9); 56 | head.right.parent = head; 57 | head.right.left = new Node(8); 58 | head.right.left.parent = head.right; 59 | head.right.left.left = new Node(7); 60 | head.right.left.left.parent = head.right.left; 61 | head.right.right = new Node(10); 62 | head.right.right.parent = head.right; 63 | 64 | Node test = head.left.left; 65 | System.out.println(test.value + " next: " + getNextNode(test).value); 66 | test = head.left.left.right; 67 | System.out.println(test.value + " next: " + getNextNode(test).value); 68 | test = head.left; 69 | System.out.println(test.value + " next: " + getNextNode(test).value); 70 | test = head.left.right; 71 | System.out.println(test.value + " next: " + getNextNode(test).value); 72 | test = head.left.right.right; 73 | System.out.println(test.value + " next: " + getNextNode(test).value); 74 | test = head; 75 | System.out.println(test.value + " next: " + getNextNode(test).value); 76 | test = head.right.left.left; 77 | System.out.println(test.value + " next: " + getNextNode(test).value); 78 | test = head.right.left; 79 | System.out.println(test.value + " next: " + getNextNode(test).value); 80 | test = head.right; 81 | System.out.println(test.value + " next: " + getNextNode(test).value); 82 | test = head.right.right; // 10's next is null 83 | System.out.println(test.value + " next: " + getNextNode(test)); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_08_GetNextNodeInBT.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | 4 | /** 5 | * 后继节点 6 | */ 7 | public class Ex_08_GetNextNodeInBT { 8 | public TreeLinkNode GetNext(TreeLinkNode pNode) { 9 | if (pNode == null) { 10 | return null; 11 | } 12 | 13 | if (pNode.right != null) { 14 | return getMostLeft(pNode.right); 15 | } else { 16 | TreeLinkNode parent = pNode.parent; 17 | while (parent != null && parent.left != pNode) { 18 | pNode = parent; 19 | parent = parent.parent; 20 | } 21 | return parent; 22 | } 23 | } 24 | 25 | private TreeLinkNode getMostLeft(TreeLinkNode node) { 26 | while (node.left != null) { 27 | node = node.left; 28 | } 29 | return node; 30 | } 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_09_QueueWithTwoStack.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Stack; 4 | 5 | /** 6 | * problem 9: 用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。 7 | */ 8 | 9 | public class Ex_09_QueueWithTwoStack { 10 | Stack stack1 = new Stack(); 11 | Stack stack2 = new Stack(); 12 | 13 | public void push(int node) { 14 | stack1.push(node); 15 | } 16 | 17 | public int pop() { 18 | int res = 0; 19 | while (!stack1.isEmpty()) { 20 | res = stack1.pop(); 21 | if (!stack1.isEmpty()) { 22 | stack2.push(res); 23 | } 24 | } 25 | 26 | while (!stack2.isEmpty()) { 27 | stack1.push(stack2.pop()); 28 | } 29 | return res; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_09_StackWithTwoQueue.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | public class Ex_09_StackWithTwoQueue { 7 | 8 | Queue queue1 = new LinkedList<>(); 9 | Queue queue2 = new LinkedList<>(); 10 | 11 | public void push(int node) { 12 | queue1.add(node); 13 | } 14 | 15 | public int pop() { 16 | int res = 0; 17 | 18 | while (!queue1.isEmpty()) { 19 | res = queue1.poll(); 20 | 21 | if (!queue1.isEmpty()) { 22 | queue2.add(res); 23 | } 24 | } 25 | 26 | while (!queue2.isEmpty()) { 27 | queue1.add(queue2.poll()); 28 | } 29 | 30 | return res; 31 | } 32 | 33 | public static void main(String[] args) { 34 | Ex_09_StackWithTwoQueue stack = new Ex_09_StackWithTwoQueue(); 35 | stack.push(1); 36 | stack.push(2); 37 | stack.push(3); 38 | stack.push(4); 39 | 40 | System.out.println(stack.pop()); 41 | System.out.println(stack.pop()); 42 | System.out.println(stack.pop()); 43 | System.out.println(stack.pop()); 44 | System.out.println(stack.pop()); 45 | System.out.println(stack.pop()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_10_Fibonacci.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_10_Fibonacci { 4 | 5 | public static int fib1(int n) { 6 | if (n <= 0) { 7 | return 0; 8 | } 9 | if (n == 1) { 10 | return 1; 11 | } 12 | 13 | return fib1(n-1) + fib1(n-2); 14 | } 15 | 16 | /** 17 | * |Fn+1 Fn | |1 1|^n 18 | * |Fn Fn-1 | |1 0| 19 | * @param n 20 | * @return 21 | */ 22 | public static int fib2(int n) { 23 | return -1; 24 | } 25 | 26 | public static int Fibonacci(int n) { 27 | if (n <= 0) { 28 | return 0; 29 | } 30 | 31 | if (n == 1) { 32 | return 1; 33 | } 34 | 35 | int fib1 = 0; 36 | int fib2 = 1; 37 | 38 | int fibN = 0; 39 | 40 | for (int i = 2; i <= n; i++) { 41 | fibN = fib1 + fib2; 42 | 43 | fib1 = fib2; 44 | fib2 = fibN; 45 | } 46 | return fibN; 47 | } 48 | 49 | public static void main(String[] args) { 50 | int n = 5; 51 | System.out.println(fib1(n)); 52 | System.out.println(Fibonacci(n)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_10_JumpFloor.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_10_JumpFloor { 4 | 5 | public int jumpFloor(int target) { 6 | if (target == 1 || target == 2) { 7 | return target; 8 | } 9 | 10 | return jumpFloor(target - 1) + jumpFloor(target - 2); 11 | } 12 | 13 | public int JumpFloor(int target) { 14 | if (target == 1 || target == 2) { 15 | return target; 16 | } 17 | 18 | int jump1 = 1; 19 | int jump2 = 2; 20 | int jumpN = 0; 21 | 22 | for (int i = 3; i <= target; i++) { 23 | jumpN = jump1 + jump2; 24 | 25 | jump1 = jump2; 26 | jump2 = jumpN; 27 | } 28 | 29 | return jumpN; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_10_JumpFloorII.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * f(n) 5 | * f(1) = 1; 6 | * f(2) = f(2-1) + f(2-2) = 1 + 1 = 2; 7 | * f(3) = f(3-1) + f(3-2) + f(3-2) 8 | * = f(0) + f(1) + f(2) 9 | * f(n-1) = f(0) + f(1) + f(2) + ... + f(n-2) 10 | * f(n) = f(0) + f(1) + f(2) + ... + f(n-2) + f(n-1) 11 | * = f(n-1) + f(n-1) 12 | * = 2 * f(n-1) 13 | * = 2 ^ 2 * f(n-2) 14 | * = ... 15 | * = 2 ^ (n-1) * f(1) 16 | * = 2 ^ (n-1) 17 | * 18 | * f(n) = 2 ^ (n-1) 19 | */ 20 | public class Ex_10_JumpFloorII { 21 | 22 | public static int JumpFloorII(int target) { 23 | if (target == 1) { 24 | return 1; 25 | } 26 | int res = 1; 27 | for (int i = 1; i < target; i++) { 28 | res *= 2; 29 | } 30 | 31 | return res; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_10_RectCover.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_10_RectCover { 4 | public int RectCover(int target) { 5 | if (target == 1 || target == 2) { 6 | return target; 7 | } 8 | 9 | int rect1 = 1; 10 | int rect2 = 2; 11 | 12 | int rectN = 0; 13 | 14 | for (int i = 3; i <= target; i++) { 15 | rectN = rect1 + rect2; 16 | 17 | rect1 = rect2; 18 | rect2 = rectN; 19 | } 20 | 21 | return rectN; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_11_MinNumOfRotatingArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 5 | * 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 6 | * 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 7 | * NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。 8 | */ 9 | public class Ex_11_MinNumOfRotatingArray { 10 | 11 | public static int minNumberInRotateArray(int [] array) { 12 | if (array == null || array.length <= 0) { 13 | return 0; 14 | } 15 | 16 | int low = 0; 17 | int high = array.length - 1; 18 | int mid = low; // 若是旋转数组本身,则第一个元素是最小值,直接不进入循环 19 | 20 | // 在这里,假设前面的递增数组第一个元素 > 后面的递增数组最后一个元素 21 | while (array[low] >= array[high]) { 22 | if (high - low == 1) { 23 | mid = high; 24 | break; 25 | } 26 | 27 | mid = low + (high - low) / 2; 28 | 29 | // 如果arr[low] == array[mid] == array[high], 30 | // 则无法用中间和两边比较的方式判断mid属于左边的递增序列还是右边的递增序列 31 | if (array[low] == array[high] && array[low] == array[mid]) { 32 | return minInOrder(array, low, high); 33 | } 34 | 35 | if (array[mid] >= array[low]) { // 此时,mid位于第一个递增数组中,因此min位于第二个递增数组中 36 | low = mid; 37 | } else if (array[mid] <= array[high]){ 38 | high = mid; 39 | } 40 | } 41 | 42 | return array[mid]; 43 | } 44 | 45 | private static int minInOrder(int[] array, int low, int high) { 46 | int min = array[low]; 47 | for (int i = low + 1; i <= high; i++) { 48 | if (array[i] < min) { 49 | min = array[i]; 50 | } 51 | } 52 | return min; 53 | } 54 | 55 | public static void main(String[] args) { 56 | int[] array = new int[]{3,4,5,1,2}; 57 | int[] array1 = new int[]{1,2,3,4,5}; 58 | System.out.println(minNumberInRotateArray(array)); 59 | System.out.println(minNumberInRotateArray(array1)); 60 | 61 | int[] array2 = new int[]{1, 0, 1, 1, 1}; 62 | int[] array3 = new int[]{1, 1, 1, 0, 1}; 63 | System.out.println(minNumberInRotateArray(array2)); 64 | System.out.println(minNumberInRotateArray(array3)); 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_11_SortAges.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_11_SortAges { 4 | 5 | // counting sort 6 | public static void sortAges(int[] ages) { 7 | if (ages == null || ages.length <= 0) { 8 | return; 9 | } 10 | 11 | int maxAge = 99; 12 | int[] countAge = new int[maxAge + 1]; // 0~99 13 | 14 | for (int i = 0; i < ages.length; i++) { 15 | countAge[ages[i]]++; 16 | } 17 | 18 | int index = 0; 19 | for (int i = 0; i <= maxAge; i++) { // i:年龄 20 | for (int j = 0; j < countAge[i]; j++) { // j:年龄的个数 21 | ages[index++] = i; 22 | } 23 | } 24 | 25 | } 26 | 27 | 28 | public static void printArray(int[] arr) { 29 | for (int i : arr) { 30 | System.out.print(i + " "); 31 | } 32 | System.out.println(); 33 | } 34 | 35 | public static void main(String[] args) { 36 | int[] ages = new int[]{2, 8, 99, 6, 20, 99, 88, 77 ,99, 44, 55, 55, 77, 23, 18}; 37 | printArray(ages); 38 | sortAges(ages); 39 | printArray(ages); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_12_HasPathInMatrix.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_12_HasPathInMatrix { 4 | 5 | public static boolean hasPath(char[] matrix, int rows, int cols, char[] str) { 6 | if (matrix == null || matrix.length <= 0 || str == null || str.length <= 0 || 7 | rows <= 0 || cols <= 0 || matrix.length != rows * cols || matrix.length < str.length) { 8 | return false; 9 | } 10 | 11 | boolean[] visited = new boolean[rows * cols]; 12 | int pathLength = 0; 13 | 14 | for (int i = 0; i < rows; i++) { 15 | for (int j = 0; j < cols; j++) { 16 | if (hasPathCore(matrix, rows, cols,str, i, j, visited, pathLength)) { 17 | return true; 18 | } 19 | } 20 | } 21 | 22 | return false; 23 | } 24 | 25 | public static boolean hasPathCore(char[] matrix, int rows, int cols, char[] str, int rowStart, int colStart, 26 | boolean[] visited, int pathLength) { 27 | boolean flag = false; 28 | 29 | if (rowStart >= 0 && rowStart < rows && colStart >= 0 && colStart < cols && 30 | !visited[rowStart*cols+colStart] && matrix[rowStart*cols+colStart] == str[pathLength]) { 31 | pathLength++; 32 | visited[rowStart*cols+colStart] = true; 33 | 34 | if (pathLength == str.length) { 35 | return true; 36 | } 37 | 38 | flag = hasPathCore(matrix, rows, cols, str, rowStart, colStart+1, visited, pathLength) || 39 | hasPathCore(matrix, rows, cols, str, rowStart+1, colStart, visited, pathLength) || 40 | hasPathCore(matrix, rows, cols, str, rowStart, colStart-1, visited, pathLength) || 41 | hasPathCore(matrix, rows, cols, str, rowStart-1, colStart, visited, pathLength); 42 | 43 | if (!flag) { 44 | pathLength--; 45 | visited[rowStart*cols+colStart] = false; 46 | } 47 | } 48 | 49 | return flag; 50 | } 51 | 52 | public static void main(String[] args) { 53 | String m = "ABCESFCSADEE"; 54 | String s = "ABCCED"; 55 | 56 | char[] matrix = m.toCharArray(); 57 | char[] str = s.toCharArray(); 58 | 59 | System.out.println(hasPath(matrix, 3, 4, str)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_13_MovingCount.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_13_MovingCount { 4 | 5 | public int movingCount(int threshold, int rows, int cols) { 6 | if (threshold < 0 || rows <= 0 || cols <= 0) { 7 | return 0; 8 | } 9 | 10 | boolean[] visited = new boolean[rows * cols]; 11 | 12 | int count = helper(threshold, rows, cols, 0, 0, visited); 13 | 14 | return count; 15 | } 16 | 17 | public int helper(int threshold, int rows, int cols, int row, int col, boolean[] visited) { 18 | int count = 0; 19 | 20 | if (check(threshold, rows, cols, row, col, visited)) { 21 | visited[row * cols + col] = true; 22 | 23 | count = 1 + helper(threshold, rows, cols, row, col+1, visited) 24 | + helper(threshold, rows, cols, row+1, col, visited) 25 | + helper(threshold, rows, cols, row, col-1, visited) 26 | + helper(threshold, rows, cols, row-1, col, visited); 27 | } 28 | 29 | return count; 30 | } 31 | 32 | public boolean check(int threshold, int rows, int cols, int row, int col, boolean[] visited) { 33 | if (row >= 0 && row < rows && col >= 0 && col < cols 34 | && !visited[row * cols + col] 35 | && getDigitSum(row) + getDigitSum(col) <= threshold) { 36 | return true; 37 | } 38 | 39 | return false; 40 | } 41 | 42 | public int getDigitSum(int x) { 43 | int sum = 0; 44 | while (x > 0) { 45 | sum += x % 10; 46 | x = x / 10; 47 | } 48 | return sum; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_14_MaxProductionAfterCutting.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_14_MaxProductionAfterCutting { 4 | 5 | public static int maxProduction(int n) { 6 | if (n == 1) { 7 | return 0; 8 | } 9 | 10 | if (n == 2) { 11 | return 1; 12 | } 13 | 14 | if (n == 3) { 15 | return 2; 16 | } 17 | 18 | int[] products = new int[n+1]; 19 | products[0] = 0; 20 | products[1] = 1; 21 | products[2] = 2; 22 | products[3] = 3; 23 | 24 | int max = 0; 25 | for (int i = 4; i <= n; i++) { 26 | max = 0; 27 | for (int j = 0; j <= i/2; j++) { 28 | int product = products[j] * products[i-j]; 29 | if (product > max) { 30 | max = product; 31 | } 32 | products[i] = max; 33 | } 34 | } 35 | max = products[n]; 36 | 37 | return max; 38 | } 39 | 40 | public static int maxProductionWithGreedy(int n) { 41 | if (n == 1) { 42 | return 0; 43 | } 44 | 45 | if (n == 2) { 46 | return 1; 47 | } 48 | 49 | if (n == 3) { 50 | return 2; 51 | } 52 | 53 | int timesOf3 = n/3; // 此时 n < 3 54 | 55 | if (n - timesOf3 * 3 == 1) { 56 | timesOf3--; // 此时 n > 5 57 | } 58 | 59 | int timesOf2 = (n - timesOf3 * 3) / 2; // 此时 n < 2 60 | 61 | return (int) (Math.pow(2, timesOf2) * Math.pow(3, timesOf3)); 62 | } 63 | 64 | public static void main(String[] args) { 65 | int n = 8; 66 | System.out.println(maxProduction(n)); 67 | System.out.println(maxProductionWithGreedy(n)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_15_Count1.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_15_Count1 { 4 | 5 | public static int NumberOf1(int n) { 6 | int count = 0; 7 | int flag = 1; 8 | 9 | while (flag != 0) { 10 | if ((n & flag) != 0) { 11 | count++; 12 | } 13 | flag = flag << 1; 14 | } 15 | 16 | return count; 17 | } 18 | 19 | public static int NumberOf1Optimal(int n) { 20 | int count = 0; 21 | 22 | while (n != 0) { 23 | count++; 24 | n = (n-1) & n; 25 | } 26 | 27 | return count; 28 | } 29 | 30 | public static void main(String[] args) { 31 | System.out.println(NumberOf1(10)); 32 | System.out.println(NumberOf1Optimal(10)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_15_CountDifferInMN.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_15_CountDifferInMN { 4 | 5 | /** 6 | * 计算需要改变m的二进制表示中的多少位才能得到n. 7 | * @param m 8 | * @param n 9 | * @return 10 | */ 11 | public static int countDiffBetweenMN(int m, int n) { 12 | int x = m ^ n; // 1. m ^ n : x中1的个数表示m和n中不同的位数个数 13 | int count = 0; 14 | 15 | while (x != 0) { 16 | count++; 17 | x = (x-1) & x; 18 | } 19 | return count; 20 | } 21 | 22 | public static void main(String[] args) { 23 | int m = 10; 24 | int n = 13; 25 | 26 | System.out.println(countDiffBetweenMN(10, 13)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_15_IsPowerOf2.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_15_IsPowerOf2 { 4 | 5 | /** 6 | * 判断1个数是否是2的整数次幂,例如2 4 8 ... 7 | * 特点:若一个数是2的整数此幂,则这个数的二进制只有一个1 8 | * (n-1) & n 将n中最右边的一个1变成了0 9 | * @param n 10 | * @return 11 | */ 12 | public static boolean isPowerOf2(int n) { 13 | if (n < 2) { 14 | return false; 15 | } 16 | 17 | n = (n - 1) & n; 18 | 19 | if (n == 0) { 20 | return true; 21 | } else { 22 | return false; 23 | } 24 | } 25 | 26 | public static void main(String[] args) { 27 | int n = 100; 28 | for (int i = 0; i <= n; i++) { 29 | if (isPowerOf2(i)) 30 | System.out.println(i); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_16_Power.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_16_Power { 4 | 5 | /** 6 | * f(n) = a ^ n 7 | * 1. a != 0 8 | * 2. n < 0 时, f(n) = 1 / a ^ abs(-n) 9 | * 3. n > 0 时, f(n) = a ^ n 10 | * @param base 11 | * @param exponent 12 | * @return 13 | */ 14 | public static double Power(double base, int exponent) { 15 | boolean InvalidInput_flag = false; // 全局变量标识是否为非法输入 16 | 17 | if (base == 0) { 18 | InvalidInput_flag = true; 19 | return 0.0; 20 | } 21 | 22 | int absExp = Math.abs(exponent); 23 | 24 | double result = PowerWithUnsignedExponent(base, absExp); 25 | 26 | if (exponent < 0) { 27 | return 1 / result; 28 | } else { 29 | return result; 30 | } 31 | } 32 | 33 | public static double PowerWithUnsignedExponent(double base, int exponent) { 34 | double result = 1.0; 35 | 36 | for (int i = 1; i <= exponent; i++) { 37 | result *= base; 38 | } 39 | 40 | return result; 41 | } 42 | 43 | public static double PowerWithUnsignedExponentOptimal(double base, int exponent) { 44 | if (exponent == 0) { 45 | return 1; 46 | } 47 | 48 | if (exponent == 1) { 49 | return base; 50 | } 51 | 52 | double result = PowerWithUnsignedExponentOptimal(base, exponent >> 1); 53 | 54 | result *= result; 55 | 56 | if ((exponent & 0x1) == 1) { 57 | result *= base; 58 | } 59 | 60 | return result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_17_AddTwoBigNumber.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_17_AddTwoBigNumber { 4 | 5 | /** 6 | * 大数相加问题: 7 | * 大数相加不能直接使用基本的int类型,因为int可以表示的整数有限,不能满足大数的要求。 8 | * 可以使用字符串来表示大数,模拟大数相加的过程。 9 | * 10 | * 思路: 11 | * 1. 反转字符串,便于从低位到高位的相加; 12 | * 2. 对齐字符串,短字符串的高位用 ‘0’ 补齐,便于相加; 13 | * 3. 相加。 14 | * @param n1 15 | * @param n2 16 | * @return 17 | */ 18 | public static String add(StringBuffer n1, StringBuffer n2) { 19 | StringBuffer result = new StringBuffer(); 20 | 21 | n1.reverse(); 22 | n2.reverse(); 23 | 24 | int len1 = n1.length(); 25 | int len2 = n2.length(); 26 | 27 | int len = len1 > len2 ? len1 : len2; 28 | 29 | 30 | 31 | boolean nOverFlow = false; 32 | int nTakeOver = 0; 33 | 34 | if (len1 < len2) { 35 | for (int i = len1; i < len2; i++) { 36 | n1.append('0'); 37 | } 38 | } else { 39 | for (int i = len2; i < len1; i++) { 40 | n2.append('0'); 41 | } 42 | } 43 | 44 | for (int i = 0; i < len; i++) { 45 | int nSum = Integer.parseInt(n1.charAt(i)+"") + (n2.charAt(i) - '0'); 46 | nSum += nTakeOver; 47 | 48 | if (nSum >= 10) { 49 | if (i == len - 1) { 50 | nOverFlow = true; 51 | } 52 | 53 | nTakeOver = 1; 54 | result.append(nSum - 10); 55 | } else { 56 | nTakeOver = 0; 57 | result.append(nSum); 58 | } 59 | } 60 | 61 | if (nOverFlow) { 62 | result.append(nTakeOver); 63 | } 64 | 65 | return result.reverse().toString(); 66 | } 67 | 68 | public static void main(String[] args) { 69 | StringBuffer s1 = new StringBuffer("-999"); 70 | StringBuffer s2 = new StringBuffer("99"); 71 | System.out.println(add(s1, s2)); 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_18_DeleteDuplicatedNode.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_18_DeleteDuplicatedNode { 4 | 5 | public static ListNode deleteDuplication (ListNode pHead) { 6 | ListNode first = new ListNode(-1); // 设置一个前哨节点,不用考虑pre为空的情况 7 | 8 | first.next = pHead; 9 | 10 | ListNode last = first; 11 | ListNode p = pHead; 12 | 13 | while (p != null && p.next != null) { 14 | if (p.val == p.next.val) { 15 | int val = p.val; 16 | while (p != null && p.val == val) { 17 | p = p.next; 18 | } 19 | 20 | last.next = p; 21 | } else { 22 | last = p; 23 | p = p.next; 24 | } 25 | } 26 | 27 | return first.next; 28 | } 29 | 30 | public static ListNode deleteDuplication1 (ListNode pHead) { 31 | if (pHead == null || pHead.next == null) { 32 | return pHead; 33 | } 34 | 35 | ListNode pre = null; 36 | ListNode cur = pHead; 37 | 38 | while (cur != null) { 39 | ListNode next = cur.next; 40 | boolean needDelete = false; 41 | 42 | if (next != null && cur.val == next.val) { 43 | needDelete = true; 44 | } 45 | 46 | if (!needDelete) { 47 | pre = cur; 48 | cur = next; 49 | } else { 50 | int val = cur.val; 51 | 52 | while (cur != null && cur.val == val) { 53 | cur = cur.next; 54 | } 55 | 56 | if (pre == null) { 57 | pHead = cur; 58 | } else { 59 | pre.next = cur; 60 | } 61 | } 62 | } 63 | 64 | return pHead; 65 | } 66 | 67 | public static void main(String[] args) { 68 | ListNode head = new ListNode(1); 69 | ListNode node1 = new ListNode(2); 70 | ListNode node2 = new ListNode(3); 71 | ListNode node3 = new ListNode(3); 72 | ListNode node4 = new ListNode(4); 73 | ListNode node5 = new ListNode(4); 74 | ListNode node6 = new ListNode(5); 75 | 76 | 77 | head.next = node1; 78 | node1.next = node2; 79 | node2.next = node3; 80 | node3.next = node4; 81 | node4.next = node5; 82 | node5.next = node6; 83 | 84 | ListNode h1 = deleteDuplication1(head); 85 | 86 | TestUtils.printList_ListNode(h1); 87 | } 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_18_DeleteNodeInSList.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_18_DeleteNodeInSList { 4 | 5 | public static Node deleteNode(Node head, Node toBeDeleted) { 6 | if (head == null || toBeDeleted == null) { 7 | return head; 8 | } 9 | 10 | // toBeDeleted is not tail 11 | if (toBeDeleted.next != null) { 12 | Node temp = toBeDeleted.next; 13 | toBeDeleted.val = temp.val; 14 | toBeDeleted.next = temp.next; 15 | temp = null; 16 | } else if (head == toBeDeleted){ // toBeDeleted is tail and list length = 1 17 | toBeDeleted = null; 18 | head = null; 19 | } else { // // toBeDeleted is tail and list length != 1 20 | Node pNode = head; 21 | while (pNode.next != toBeDeleted) { 22 | pNode = pNode.next; 23 | } 24 | pNode.next = null; 25 | } 26 | 27 | return head; 28 | } 29 | 30 | public static void main(String[] args) { 31 | Node node1 = new Node(1); 32 | node1.next = null; 33 | Node head1 = deleteNode(node1, node1); // case 2:注意 Java中是值传递 34 | TestUtils.printList(head1); 35 | 36 | Node node2 = new Node(2); 37 | Node node3 = new Node(3); 38 | Node node4 = new Node(4); 39 | Node node5 = new Node(5); 40 | node2.next = node3; 41 | node3.next = node4; 42 | node4.next = node5; 43 | node5.next = null; 44 | 45 | Node head2 = deleteNode(node2, node2); // case 1 46 | TestUtils.printList(head2); 47 | 48 | Node head3 = deleteNode(head2, node5); // case 3 49 | TestUtils.printList(head3); 50 | } 51 | 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_19_Match.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 当模式中的第二个字符不是“*”时: 5 | * 1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。 6 | * 2、如果 字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。 7 | * 8 | * 而当模式中的第二个字符是“*”时: 9 | * 如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式: 10 | * 1、模式后移2字符,相当于x*被忽略; 11 | * 2、字符串后移1字符,模式后移2字符; 12 | * 3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位; 13 | */ 14 | public class Ex_19_Match { 15 | 16 | public boolean match(char[] str, char[] pattern) { 17 | if (str == null || pattern == null) { 18 | return false; 19 | } 20 | 21 | return matchCore(str, 0, pattern, 0); 22 | } 23 | 24 | private boolean matchCore(char[] str, int strIndex, char[] pattern, int patIndex) { 25 | // 有效性检验: str 和 pattern都到尾,则匹配成功 26 | if (strIndex == str.length && patIndex == pattern.length) { 27 | return true; 28 | } 29 | 30 | // pattern 先到尾,则匹配失败 31 | if (strIndex != str.length && patIndex == pattern.length) { 32 | return false; 33 | } 34 | 35 | // pattern第2个是*,且str第1个和pattern第1个匹配,分3种情况;若不匹配,则pattern后移2位 36 | if (patIndex + 1 < pattern.length && pattern[patIndex + 1] == '*') { 37 | if (strIndex != str.length && (pattern[patIndex] == str[strIndex] || pattern[patIndex] == '.')) { 38 | return matchCore(str, strIndex, pattern, patIndex+2) // 模式串后移2位,相当于忽略x* 39 | || matchCore(str, strIndex+1, pattern, patIndex+2) // 字符串,模式串都后移1位,相当于忽略* 40 | || matchCore(str, strIndex+1, pattern, patIndex); // 字符串后移1位,相当于*之前扩展了。 41 | } else { 42 | return matchCore(str, strIndex, pattern, patIndex+2); 43 | } 44 | } 45 | 46 | // pattern第2个不是* ,且str 第1个和pattern第1个匹配,则后移一位,否则直接返回false 47 | if (strIndex != str.length && (pattern[patIndex] == str[strIndex] || pattern[patIndex] == '.')) { 48 | return matchCore(str, strIndex+1, pattern, patIndex+1); 49 | } 50 | 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_20_IsNumber.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_20_IsNumber { 6 | /** 7 | * A.B[E|e]C 8 | * A.B: A B任意有其一即可 9 | * XEC: X C 缺一不可 10 | */ 11 | private int index = 0; 12 | 13 | public boolean isNumeric(char[] str) { 14 | if (str == null || str.length == 0) { 15 | return false; 16 | } 17 | 18 | boolean flag = scanInteger(str); 19 | 20 | if (index < str.length && str[index] == '.') { 21 | index++; 22 | flag = scanUnsignedInteger(str) || flag; //若是||的话,必须先执行scan函数,否则index无法更新 23 | } 24 | 25 | if (index < str.length && (str[index] == 'E' || str[index] == 'e')) { 26 | index++; 27 | flag = flag && scanInteger(str); 28 | } 29 | 30 | return flag && index == str.length; 31 | } 32 | 33 | private boolean scanInteger(char[] str) { 34 | if (index < str.length && (str[index] == '+' || str[index] == '-')) { 35 | index++; 36 | } 37 | 38 | return scanUnsignedInteger(str); 39 | } 40 | 41 | private boolean scanUnsignedInteger(char[] str) { 42 | int start = index; 43 | while (index < str.length && str[index] >= '0' && str[index] <= '9') { 44 | index++; 45 | } 46 | 47 | return start < index; 48 | } 49 | 50 | /** 51 | 以下对正则进行解释: 52 | [\\+\\-]?            -> 正或负符号出现与否 53 | \\d*                 -> 整数部分是否出现,如-.34 或 +3.34均符合 54 | (\\.\\d+)?           -> 如果出现小数点,那么小数点后面必须有数字,否则一起不出现 55 | ([eE][\\+\\-]?\\d+)? -> 如果存在指数部分,那么e或E肯定出现,+或-可以不出现, 56 |                         紧接着必须跟着整数;或者整个部分都不出现 57 | */ 58 | public boolean isNumberic1(char[] str) { 59 | String string = String.valueOf(str); 60 | return string.matches("[\\+\\-]?\\d*(\\.\\d+)?([eE][\\+\\-]?\\d+)?"); 61 | } 62 | 63 | @Test 64 | public void test() { 65 | String str = "123.45e+6"; 66 | char[] chars = str.toCharArray(); 67 | System.out.println(isNumeric(chars)); 68 | System.out.println(isNumberic1(chars)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_21_ReOrderArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_21_ReOrderArray { 6 | 7 | public void reOrderArray(int [] array) { 8 | if (array == null || array.length == 0) { 9 | return; 10 | } 11 | 12 | int i = 0; 13 | 14 | while (i < array.length) { 15 | while (i < array.length && (array[i] & 1) == 1) { 16 | i++; 17 | } 18 | 19 | int j = i+1; 20 | 21 | while (j < array.length && (array[j] & 1) != 1) { 22 | j++; 23 | } 24 | 25 | if (j < array.length) { 26 | int tmp = array[j]; 27 | for (int k = j-1; k >= i; k--) { 28 | array[k+1] = array[k]; 29 | } 30 | array[i] = tmp; 31 | i++; 32 | } else { 33 | break; 34 | } 35 | } 36 | } 37 | 38 | public void reOrderArray1(int [] array) { 39 | if (array == null || array.length == 0) { 40 | return; 41 | } 42 | 43 | int i = 0; 44 | int j = array.length-1; 45 | while (i < j) { 46 | while ((array[i] & 1) != 0) { 47 | i++; 48 | } 49 | 50 | while ((array[j] & 1) == 0) { 51 | j--; 52 | } 53 | 54 | if (i > j) break; 55 | 56 | swap(array, i, j); 57 | } 58 | } 59 | 60 | public void reOrderArray2(int [] array) { 61 | if(array == null || array.length == 0) { 62 | return; 63 | } 64 | 65 | for (int i = 0; i < array.length-1; i++) { 66 | for (int j = 0; j < array.length-1-i; j++) { 67 | if (array[j] % 2 == 0 && array[j+1] % 2 == 1) { 68 | swap(array, j, j+1); 69 | } 70 | } 71 | } 72 | } 73 | 74 | private void swap(int[] array, int i, int j) { 75 | int tmp = array[i]; 76 | array[i] = array[j]; 77 | array[j] = tmp; 78 | } 79 | 80 | 81 | @Test 82 | public void test() { 83 | int[] array = new int[] {1,2,3,4,5,6,7}; 84 | reOrderArray1(array); 85 | TestUtils.printArray(array); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_22_FindKthNodeToTail.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_22_FindKthNodeToTail { 6 | /** 7 | * 1. 空链表 8 | * 2. k <= 0 9 | * 3. k > len 10 | * @param head 11 | * @param k 12 | * @return 13 | */ 14 | public ListNode FindKthToTail(ListNode head, int k) { 15 | // 1. 边界条件: head == null k <= 0 16 | if (head == null || k <= 0) return null; 17 | 18 | ListNode before = head; 19 | ListNode after = head; 20 | 21 | for (int i = 0; i < k-1; i++) { 22 | before = before.next; 23 | } 24 | // 2. n < k: 第k个元素before已经到null,则k > n 25 | if (before == null) return null; 26 | 27 | while (before.next != null) { 28 | before = before.next; 29 | after = after.next; 30 | } 31 | 32 | return after; 33 | } 34 | 35 | @Test 36 | public void test() { 37 | ListNode head = new ListNode(1); 38 | head.next = new ListNode(2); 39 | head.next.next = new ListNode(3); 40 | head.next.next.next = new ListNode(4); 41 | head.next.next.next.next = new ListNode(5); 42 | FindKthToTail(head, 5); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_22_FindMedianNodeInList.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_22_FindMedianNodeInList { 6 | 7 | public ListNode findMedian(ListNode head) { 8 | if (head == null) return null; 9 | 10 | ListNode before = head; 11 | ListNode after = head; 12 | 13 | while (before.next != null && before.next.next != null) { 14 | before = before.next.next; 15 | after = after.next; 16 | } 17 | 18 | return after; 19 | } 20 | 21 | @Test 22 | public void test() { 23 | ListNode head = new ListNode(1); 24 | head.next = new ListNode(2); 25 | head.next.next = new ListNode(3); 26 | head.next.next.next = new ListNode(4); 27 | //head.next.next.next.next = new ListNode(5); 28 | System.out.println(findMedian(head).val); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_23_EntryNodeInList.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_23_EntryNodeInList { 4 | 5 | public ListNode EntryNodeOfLoop(ListNode pHead) { 6 | if (pHead == null) { 7 | return null; 8 | } 9 | 10 | ListNode fast = pHead; 11 | ListNode slow = pHead; 12 | 13 | while (fast.next != null && fast.next.next != null) { 14 | fast = fast.next.next; 15 | slow = slow.next; 16 | if (fast == slow) { 17 | break; 18 | } 19 | } 20 | 21 | if (fast.next == null || fast.next.next == null) return null; 22 | 23 | fast = pHead; 24 | while (fast != slow) { 25 | fast = fast.next; 26 | slow = slow.next; 27 | } 28 | 29 | return fast; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_24_ReverseSList.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_24_ReverseSList { 4 | 5 | public ListNode ReverseList(ListNode head) { 6 | if (head == null) return null; 7 | 8 | ListNode pre = null; 9 | ListNode cur = head; 10 | ListNode next = null; // 指向剩余的需要被reverse的链表 11 | 12 | while (cur != null) { 13 | next = cur.next; // 记录:剩余的需要被reverse的链表 14 | cur.next = pre; // 核心:cur -> pre 15 | pre = cur; // 更新pre 16 | cur = next; // 更新cur 17 | } 18 | 19 | head = pre; 20 | return head; 21 | } 22 | 23 | public ListNode reverseList(ListNode head) { 24 | //若是空链表或者tail节点 25 | if (head == null || head.next == null) return head; 26 | 27 | //先反转 head.next -> ... 例如: 1->2->3->4->null 1-> |2<-3<-4| 28 | ListNode reverseHead = reverseList(head.next); 29 | //修改head指向 null <- 1 <- |2<-3<-4| 30 | head.next.next = head; 31 | head.next = null; 32 | return reverseHead; 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_25_MergeList.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_25_MergeList { 6 | 7 | public ListNode Merge(ListNode list1, ListNode list2) { 8 | if (list1 == null) return list2; 9 | if (list2 == null) return list1; 10 | 11 | ListNode head = null; 12 | 13 | if (list1.val < list2.val) { 14 | head = list1; 15 | head.next = Merge(list1.next, list2); 16 | } else { 17 | head = list2; 18 | head.next = Merge(list1, list2.next); 19 | } 20 | 21 | return head; 22 | } 23 | 24 | public ListNode Merge1(ListNode list1, ListNode list2) { 25 | if (list1 == null) return list2; 26 | if (list2 == null) return list1; 27 | 28 | ListNode pre = new ListNode(-1); 29 | 30 | ListNode node = pre; 31 | 32 | ListNode p1 = list1; 33 | ListNode p2 = list2; 34 | 35 | while (p1 != null && p2 != null) { 36 | while (p1 != null && p1.val < p2.val) { 37 | node.next = new ListNode(p1.val); 38 | node = node.next; 39 | p1 = p1.next; 40 | } 41 | 42 | if (p1 == null) { 43 | while (p2 != null) { 44 | node.next = new ListNode(p2.val); 45 | node = node.next; 46 | p2 = p2.next; 47 | } 48 | } 49 | 50 | while (p2 != null && p2.val < p1.val) { 51 | node.next = new ListNode(p2.val); 52 | node = node.next; 53 | p2 = p2.next; 54 | } 55 | 56 | if (p2 == null) { 57 | while (p1 != null) { 58 | node.next = new ListNode(p1.val); 59 | node = node.next; 60 | p1 = p1.next; 61 | } 62 | } 63 | } 64 | 65 | return pre.next; 66 | } 67 | 68 | @Test 69 | public void test() { 70 | ListNode head = new ListNode(1); 71 | head.next = new ListNode(3); 72 | head.next.next = new ListNode(5); 73 | 74 | ListNode head1 = new ListNode(2); 75 | head1.next = new ListNode(4); 76 | head1.next.next = new ListNode(6); 77 | ListNode h = Merge(head, head1); 78 | TestUtils.printList_ListNode(h); 79 | } 80 | 81 | @Test 82 | public void test1() { 83 | ListNode head = new ListNode(1); 84 | head.next = new ListNode(3); 85 | head.next.next = new ListNode(5); 86 | 87 | ListNode head1 = new ListNode(2); 88 | head1.next = new ListNode(4); 89 | head1.next.next = new ListNode(6); 90 | 91 | ListNode h1 = Merge1(head, head1); 92 | TestUtils.printList_ListNode(h1); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_26_IsSubTree.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | // 此题目还可以将Tree A B 序列化,然后看B字符串是否在A字符串中,KMP算法 4 | public class Ex_26_IsSubTree { 5 | 6 | public boolean HasSubtree(TreeNode root1, TreeNode root2) { 7 | if (root1 == null || root2 == null) return false; 8 | 9 | return doesTree1HasTree2(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); 10 | } 11 | 12 | public boolean doesTree1HasTree2(TreeNode root1, TreeNode root2) { 13 | if (root2 == null) { 14 | return true; 15 | } 16 | 17 | if (root1 == null) { 18 | return false; 19 | } 20 | 21 | if (root1.val != root2.val) { 22 | return false; 23 | } 24 | 25 | return doesTree1HasTree2(root1.left, root2.left) && doesTree1HasTree2(root1.right, root2.right); 26 | } 27 | 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_27_MirrorOfTree.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_27_MirrorOfTree { 4 | 5 | public void Mirror(TreeNode root) { 6 | if (root == null) return; 7 | 8 | if (root.left == null && root.right == null) return; 9 | 10 | swapLeftAndRight(root); 11 | 12 | Mirror(root.left); 13 | Mirror(root.right); 14 | 15 | } 16 | 17 | public void swapLeftAndRight(TreeNode root) { 18 | if (root == null) return; 19 | 20 | TreeNode tmp = root.left; 21 | root.left = root.right; 22 | root.right =tmp; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_28_SymmetricalTree.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_28_SymmetricalTree { 4 | boolean isSymmetrical(TreeNode pRoot) { 5 | if (pRoot == null) return true; 6 | 7 | return isSymmetrical(pRoot, pRoot); 8 | } 9 | 10 | // 树的前序遍历和对称前序遍历 11 | boolean isSymmetrical(TreeNode pRoot1, TreeNode pRoot2) { 12 | // 递归结束条件 13 | if (pRoot1 == null && pRoot2 == null) return true; 14 | 15 | if (pRoot1 == null || pRoot2 == null) return false; 16 | 17 | if (pRoot1.val != pRoot2.val) { 18 | return false; 19 | } 20 | 21 | return isSymmetrical(pRoot1.left, pRoot2.right) && isSymmetrical(pRoot1.right, pRoot2.left); 22 | } 23 | 24 | // 树的前序遍历 25 | public boolean doesTree1HasTree2(TreeNode root1, TreeNode root2) { 26 | // 递归结束条件 27 | if (root2 == null) { 28 | return true; 29 | } 30 | 31 | if (root1 == null) { 32 | return false; 33 | } 34 | 35 | if (root1.val != root2.val) { 36 | return false; 37 | } 38 | 39 | return doesTree1HasTree2(root1.left, root2.left) && doesTree1HasTree2(root1.right, root2.right); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_29_PrintMatrixWithClockWise.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class Ex_29_PrintMatrixWithClockWise { 6 | public ArrayList printMatrix(int [][] matrix) { 7 | if (matrix == null || matrix.length <= 0) { 8 | return new ArrayList<>(); 9 | } 10 | 11 | ArrayList result = new ArrayList<>(); 12 | ArrayList temp = new ArrayList<>(); 13 | 14 | int r1 = 0; 15 | int c1 = 0; 16 | int r2 = matrix.length-1; 17 | int c2 = matrix[r2].length-1; 18 | 19 | while (r1 <= r2 && c1 <= c2) { 20 | temp = printMatrixWithCircle(matrix, r1++, c1++, r2--, c2--); 21 | for (Integer i : temp) { 22 | result.add(i); 23 | } 24 | } 25 | return result; 26 | } 27 | 28 | public ArrayList printMatrixWithCircle(int[][] matrix, int r1, int c1, int r2, int c2) { 29 | ArrayList result = new ArrayList<>(); 30 | 31 | if (r1 == r2) { 32 | for (int i = c1; i <= c2; i++) { 33 | result.add(matrix[r1][i]); 34 | } 35 | return result; 36 | } 37 | 38 | if (c1 == c2) { 39 | for (int i = r1; i <= r2; i++) { 40 | result.add(matrix[i][c1]); 41 | } 42 | return result; 43 | } 44 | 45 | for (int i = c1; i < c2; i++) { 46 | result.add(matrix[r1][i]); 47 | } 48 | 49 | for (int i = r1; i < r2; i++) { 50 | result.add(matrix[i][c2]); 51 | } 52 | 53 | for (int i = c2; i > c1; i--) { 54 | result.add(matrix[r2][i]); 55 | } 56 | 57 | for (int i = r2; i > r1; i--) { 58 | result.add(matrix[i][c1]); 59 | } 60 | 61 | return result; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_30_StackWithMinFunction.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Stack; 4 | 5 | public class Ex_30_StackWithMinFunction { 6 | Stack stack = new Stack<>(); 7 | Stack help = new Stack<>(); 8 | 9 | public void push(int node) { 10 | stack.push(node); 11 | 12 | if (help.isEmpty()) { 13 | help.push(node); 14 | } 15 | 16 | if (help.peek() >= node) { 17 | help.push(node); 18 | } else { 19 | help.push(help.peek()); 20 | } 21 | } 22 | 23 | public void pop() { 24 | if (!stack.isEmpty()) { 25 | stack.pop(); 26 | help.pop(); 27 | } 28 | } 29 | 30 | public int top() { 31 | if (!stack.isEmpty()) { 32 | return stack.peek(); 33 | } 34 | return -1; 35 | } 36 | 37 | public int min() { 38 | if (!help.isEmpty()) { 39 | return help.peek(); 40 | } 41 | return -1; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_31_IsPopOrder.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Stack; 4 | 5 | public class Ex_31_IsPopOrder { 6 | public boolean IsPopOrder(int [] pushA,int [] popA) { 7 | Stack stack = new Stack<>(); 8 | 9 | int index = 0; 10 | // push: 1 2 3 4 5 11 | // pop : 4 5 3 2 1 12 | // stack : 1 2 3 -4- | <- 5 push: empty pop: 4 5 3 2 1 13 | // stack : 1 2 3 5 | push: empty pop: 5 3 2 1 14 | for (int i = 0; i < pushA.length; i++) { 15 | while (!stack.isEmpty() && popA[index] == stack.peek()) { 16 | stack.pop(); // 遍历完push之前pop出去的 17 | index++; 18 | } 19 | stack.push(pushA[i]); 20 | } 21 | 22 | // 遍历完push之后pop出去的 23 | while (!stack.isEmpty() && popA[index] == stack.peek()) { 24 | stack.pop(); 25 | index++; 26 | } 27 | 28 | return stack.isEmpty(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_32_PrintTreeByLayer.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | 7 | public class Ex_32_PrintTreeByLayer { 8 | 9 | ArrayList> Print(TreeNode pRoot) { 10 | ArrayList> result = new ArrayList<>(); 11 | ArrayList nodes = new ArrayList<>(); 12 | 13 | int countOfNextLevel = 0; // 统计下一层的节点数 14 | int left = 1; // 统计本层剩余的打印数 15 | 16 | if (pRoot == null) return result; 17 | 18 | Queue queue = new LinkedList<>(); 19 | queue.add(pRoot); 20 | 21 | while (!queue.isEmpty()) { 22 | TreeNode x = queue.poll(); 23 | left--; 24 | nodes.add(x.val); 25 | 26 | if (x.left != null) { 27 | queue.add(x.left); 28 | countOfNextLevel++; 29 | } 30 | 31 | if (x.right != null) { 32 | queue.add(x.right); 33 | countOfNextLevel++; 34 | } 35 | 36 | if (left == 0) { 37 | result.add(new ArrayList<>(nodes)); // 一定要注意这里,拷贝构造,而不能直接将nodes(这只是个引用)扔进去 38 | nodes.clear(); 39 | left = countOfNextLevel; 40 | countOfNextLevel = 0; 41 | } 42 | } 43 | return result; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_32_PrintTreeWithZhi.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Stack; 5 | 6 | public class Ex_32_PrintTreeWithZhi { 7 | 8 | public ArrayList > Print(TreeNode pRoot) { 9 | ArrayList> result = new ArrayList<>(); 10 | ArrayList nodes = new ArrayList<>(); 11 | 12 | if (pRoot == null) return result; 13 | 14 | Stack s1 = new Stack<>(); // 奇数层 1 15 | Stack s2 = new Stack<>(); // 偶数层 0 16 | 17 | int cur = 1; 18 | int next = 0; 19 | 20 | s1.add(pRoot); 21 | 22 | while (!s1.isEmpty() || !s2.isEmpty()) { 23 | TreeNode x = null; 24 | if (cur == 1) { 25 | x = s1.pop(); 26 | } else { 27 | x = s2.pop(); 28 | } 29 | 30 | nodes.add(x.val); 31 | 32 | if (cur == 1) { 33 | if (x.left != null) { 34 | s2.push(x.left); 35 | } 36 | 37 | if (x.right != null) { 38 | s2.push(x.right); 39 | } 40 | 41 | 42 | } else { 43 | if (x.right != null) { 44 | s1.push(x.right); 45 | } 46 | 47 | if (x.left != null) { 48 | s1.push(x.left); 49 | } 50 | } 51 | 52 | if (cur == 1 && s1.isEmpty() && !nodes.isEmpty()) { 53 | result.add(new ArrayList<>(nodes)); 54 | nodes.clear(); 55 | next = 1-next; 56 | cur = 1-cur; 57 | } 58 | 59 | 60 | if (cur == 0 && s2.isEmpty() && !nodes.isEmpty() ) { 61 | result.add(new ArrayList<>(nodes)); 62 | nodes.clear(); 63 | next = 1-next; 64 | cur = 1-cur; 65 | } 66 | } 67 | return result; 68 | } 69 | 70 | // 此答案有错 71 | public ArrayList> Print1(TreeNode pRoot) { 72 | ArrayList> result = new ArrayList<>(); 73 | ArrayList nodes = new ArrayList<>(); 74 | 75 | if (pRoot == null) return result; 76 | 77 | Stack[] stacks = new Stack[2]; 78 | int current = 0; //奇数层 79 | int next = 1; //偶数层 80 | stacks[current].push(pRoot); 81 | 82 | while (!stacks[0].isEmpty() || !stacks[1].isEmpty()) { 83 | TreeNode x = stacks[current].pop(); 84 | nodes.add(x.val); 85 | 86 | if (current == 0) { 87 | if (x.left != null) { 88 | stacks[next].push(x.left); 89 | } 90 | 91 | if (x.right != null) { 92 | stacks[next].push(x.right); 93 | } 94 | } else { 95 | if (x.right != null) { 96 | stacks[next].push(x.right); 97 | } 98 | 99 | if (x.left != null) { 100 | stacks[next].push(x.left); 101 | } 102 | } 103 | 104 | if (stacks[current].isEmpty()) { 105 | result.add(new ArrayList<>(nodes)); 106 | nodes.clear(); 107 | current = 1 - current; 108 | next = 1- next; 109 | 110 | } 111 | } 112 | 113 | return result; 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_32_TraverseTreeByLayer.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedList; 5 | import java.util.Queue; 6 | 7 | /** 8 | * 注1: 9 | * 树的按层遍历借助于 队列 10 | * 树的先中后序遍历借助于 栈 11 | * 12 | * 注2: 13 | * 树的按层遍历本质上说就是广度优先遍历二叉树(树是图的一种特殊退化形式) 14 | * 那么如何广度优先遍历有向图呢? 15 | * 16 | * A:无论是广度优先遍历有向图还是二叉树,都需要用到队列。 17 | * 首先把起始节点(或者根节点(对树而言))放入队列 18 | * 然后每次从队列的头部取出一个节点,遍历这个节点之后把它能够到达的节点(或者子节点(对树而言))都一次放入队列中 19 | * 重复以上遍历过程,知道队列中所有的节点全部被遍历完。 20 | * 21 | */ 22 | public class Ex_32_TraverseTreeByLayer { 23 | 24 | public ArrayList PrintFromTopToBottom(TreeNode root) { 25 | ArrayList result = new ArrayList<>(); 26 | 27 | if (root == null) return result; 28 | 29 | Queue queue = new LinkedList<>(); 30 | 31 | queue.add(root); 32 | 33 | while (!queue.isEmpty()) { 34 | TreeNode temp = queue.poll(); 35 | result.add(temp.val); 36 | if (temp.left != null) queue.add(temp.left); 37 | if (temp.right != null) queue.add(temp.right); 38 | } 39 | 40 | return result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_33_VerifySequenceOfBST.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_33_VerifySequenceOfBST { 6 | public boolean VerifySequenceOfBST(int [] sequence) { 7 | if (sequence == null || sequence.length <= 0) { 8 | return false; 9 | } 10 | 11 | return verifySequence(sequence, 0, sequence.length-1); 12 | } 13 | 14 | public boolean verifySequence(int[] sequence, int start, int end) { 15 | if (sequence == null || start > end) { 16 | return false; 17 | } 18 | 19 | // 若数组区间[start, end]元素为0则停止递归,其实可以去掉这个判断 20 | if (start == end) { 21 | return true; 22 | } 23 | 24 | int root = sequence[end]; 25 | 26 | // 找到左右子树的分界点[i-1,i] 27 | // 小于root: [start, i-1] 28 | int i = start; 29 | for ( ; i < end; i++) { 30 | if (sequence[i] > root) { 31 | break; 32 | } 33 | } 34 | 35 | // 大于root: [i, end-1] 36 | int j = i; 37 | for ( ; j < end; j++) { 38 | if (sequence[j] < root) { 39 | return false; 40 | } 41 | } 42 | 43 | // 判断左子树 44 | boolean left = true; // 若左子树为空,则左子树为后序遍历序列 45 | if (i > start) { 46 | left = verifySequence(sequence, start, i-1); 47 | } 48 | 49 | // 判断右子树 50 | boolean right = true; // 若右子树为空,则右子树为后序遍历序列 51 | if (i < end) { 52 | right = verifySequence(sequence, i, end-1); 53 | } 54 | 55 | return left && right; 56 | } 57 | 58 | @Test 59 | public void test() { 60 | int[] arr = new int[] {5, 7, 6, 9, 11, 10, 8}; 61 | boolean result = VerifySequenceOfBST(arr); 62 | System.out.println(result); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_34_FindPathInBT.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class Ex_34_FindPathInBT { 8 | 9 | public ArrayList> FindPath(TreeNode root, int target) { 10 | ArrayList> pathList = new ArrayList<>(); 11 | 12 | if (root == null) { 13 | return pathList; 14 | } 15 | ArrayList path = new ArrayList<>(); 16 | 17 | findPath(root, target, path, pathList); 18 | 19 | return pathList; 20 | } 21 | 22 | private void findPath(TreeNode root, 23 | int target, 24 | ArrayList path, 25 | ArrayList> pathList) { 26 | if (root == null) return; 27 | 28 | if (root.left == null && root.right == null) { 29 | if (root.val == target) { 30 | path.add(root.val); 31 | pathList.add(path); 32 | } 33 | return; 34 | } 35 | 36 | path.add(root.val); 37 | ArrayList pathCopy = new ArrayList<>(path); 38 | 39 | findPath(root.left, target - root.val, path, pathList); 40 | findPath(root.right, target - root.val, pathCopy, pathList); 41 | return; 42 | } 43 | 44 | 45 | @Test 46 | public void test() { 47 | TreeNode node1 = new TreeNode(10); 48 | TreeNode node2 = new TreeNode(5); 49 | TreeNode node3 = new TreeNode(12); 50 | TreeNode node4 = new TreeNode(4); 51 | TreeNode node5 = new TreeNode(7); 52 | node1.left = node2; 53 | node1.right = node3; 54 | node2.left = node4; 55 | node2.right = node5; 56 | 57 | ArrayList> list = FindPath(node1, 22); 58 | int a = 5; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_34_FindPathInBT_1.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class Ex_34_FindPathInBT_1 { 8 | ArrayList> pathList = new ArrayList<>(); 9 | ArrayList path = new ArrayList<>(); 10 | 11 | public ArrayList> FindPath(TreeNode root, int target) { 12 | if (root == null) return pathList; 13 | 14 | findPath(root, target); 15 | 16 | return pathList; 17 | } 18 | 19 | private void findPath(TreeNode root, int target) { 20 | path.add(root.val); 21 | 22 | if (root.val == target && root.left == null && root.right == null) { 23 | pathList.add(new ArrayList<>(path)); 24 | } 25 | 26 | if (root.left != null) { 27 | findPath(root.left, target - root.val); 28 | } 29 | 30 | if (root.right != null) { 31 | findPath(root.right, target - root.val); 32 | } 33 | 34 | path.remove(path.size()-1); 35 | 36 | return; 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_34_FindPathInBT_2.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class Ex_34_FindPathInBT_2 { 6 | ArrayList> pathList = new ArrayList<>(); 7 | ArrayList path = new ArrayList<>(); 8 | 9 | public ArrayList> FindPath(TreeNode root, int target) { 10 | if (root == null) return pathList; 11 | 12 | findPath(root, target, 0); 13 | 14 | return pathList; 15 | } 16 | 17 | private void findPath(TreeNode root, int target, int sum) { 18 | path.add(root.val); 19 | 20 | sum += root.val; 21 | 22 | if (sum == target && root.left == null && root.right == null) { 23 | pathList.add(new ArrayList<>(path)); 24 | } 25 | 26 | if (root.left != null) { 27 | findPath(root.left, target, sum); 28 | } 29 | 30 | if (root.right != null) { 31 | findPath(root.right, target, sum); 32 | } 33 | 34 | path.remove(path.size()-1); 35 | return; 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_35_CloneList.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class Ex_35_CloneList { 7 | public RandomListNode Clone(RandomListNode pHead) 8 | { 9 | if (pHead == null) return pHead; 10 | 11 | RandomListNode node = pHead; 12 | 13 | // A - A' - B - B' - C - C' - null 14 | while (node != null) { 15 | RandomListNode cloneNode = new RandomListNode(node.label); 16 | cloneNode.next = node.next; 17 | node.next = cloneNode; 18 | 19 | node = cloneNode.next; 20 | } 21 | 22 | // 设置Random 23 | node = pHead; 24 | while (node != null) { 25 | RandomListNode cloneNode = node.next; 26 | if (node.random != null) cloneNode.random = node.random.next; 27 | 28 | node = cloneNode.next; 29 | } 30 | 31 | RandomListNode head = pHead.next; 32 | 33 | // 拆分链表 34 | node = pHead; 35 | RandomListNode node1 = head; 36 | while (node != null) { 37 | node.next = node1.next; 38 | node = node.next; 39 | if (node == null) break; 40 | node1.next = node.next; 41 | node1 = node1.next; 42 | } 43 | return head; 44 | 45 | } 46 | 47 | public RandomListNode Clone1(RandomListNode pHead) 48 | { 49 | if (pHead == null) return pHead; 50 | 51 | Map map = new HashMap<>(); 52 | RandomListNode node = pHead; 53 | 54 | while (node != null) { 55 | map.put(node, new RandomListNode(node.label)); 56 | } 57 | 58 | for (RandomListNode key : map.keySet()) { 59 | map.get(key).next = map.get(key.next); 60 | map.get(key).random = map.get(key.random); 61 | } 62 | 63 | return map.get(0); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_36_ConvertBetweenBSTAndDList.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Stack; 4 | 5 | public class Ex_36_ConvertBetweenBSTAndDList { 6 | TreeNode head = null; 7 | TreeNode tail = null; 8 | 9 | public TreeNode Convert(TreeNode pRootOfTree) { 10 | convert(pRootOfTree); 11 | return head; 12 | } 13 | 14 | public void convert(TreeNode pRootOfTree) { 15 | if (pRootOfTree == null) return; 16 | 17 | convert(pRootOfTree.left); 18 | 19 | if (head == null) { // 第一次,标记head节点 20 | head = pRootOfTree; 21 | tail = pRootOfTree; 22 | } else { 23 | tail.right = pRootOfTree; 24 | pRootOfTree.left = tail; 25 | 26 | tail = pRootOfTree; 27 | } 28 | 29 | convert(pRootOfTree.right); 30 | } 31 | 32 | 33 | 34 | public TreeNode ConvertIterative(TreeNode pRootOfTree) { 35 | if (pRootOfTree == null) return null; 36 | 37 | Stack stack = new Stack<>(); 38 | TreeNode node = pRootOfTree; 39 | TreeNode pre = null; 40 | TreeNode head = null; 41 | boolean isFirst = true; 42 | 43 | while (node != null || !stack.isEmpty()) { 44 | while (node != null) { 45 | stack.push(node); 46 | node = node.left; 47 | } 48 | 49 | node = stack.pop(); 50 | 51 | if (isFirst) { 52 | head = node; 53 | pre = head; 54 | isFirst = false; 55 | } else { 56 | pre.right = node; 57 | node.left = pre; 58 | pre = node; 59 | } 60 | node = node.right; 61 | } 62 | return head; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_37_SerializeBT.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_37_SerializeBT { 4 | String Serialize(TreeNode root) { 5 | StringBuilder sb = new StringBuilder(); 6 | 7 | if (root == null) { 8 | return sb.toString(); 9 | } 10 | 11 | serialize(root, sb); 12 | return sb.toString(); 13 | } 14 | 15 | void serialize(TreeNode root, StringBuilder sb) { 16 | if (root == null) { 17 | sb.append("#,"); 18 | return; 19 | } 20 | 21 | sb.append(root.val + ","); 22 | serialize(root.left, sb); 23 | serialize(root.right, sb); 24 | } 25 | 26 | int index = -1; 27 | TreeNode Deserialize(String str) { 28 | if (str.length() == 0) return null; 29 | String[] strs = str.split(","); 30 | return Deserialize(strs); 31 | } 32 | 33 | TreeNode Deserialize(String[] strs) { 34 | index++; // 遍历strs,待返回root时,遍历结束 35 | TreeNode node = null; 36 | if (!strs[index].equals("#")) { 37 | node = new TreeNode(Integer.parseInt(strs[index])); 38 | node.left = Deserialize(strs); 39 | node.right = Deserialize(strs); 40 | } 41 | return node; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_38_EightQueen.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | // 8皇后问题与回溯法:https://www.cnblogs.com/bigmoyan/p/4521683.html 6 | // 7 | // 回溯法 8 | // 引例:设想将你放在迷宫之中,要想走出迷宫,最直接的办法是什么?试!先选择一条路开始走, 9 | // 走不通就退回去尝试别的路,走不通接着回退,直到走通为止。 10 | // 本质: 暴力破解。只不过是在暴力破解之前,利用了一些条件减少了暴力破解的一些步骤。 11 | 12 | public class Ex_38_EightQueen { 13 | 14 | private static final int QUEEN_NUMBER = 8; // 皇后个数 15 | private int[] columns = new int[QUEEN_NUMBER]; // 每个皇后存储的列 (row, col), row天然不相等 16 | private int total = 0; 17 | 18 | public int solution() { 19 | queen(0); 20 | return total; 21 | } 22 | 23 | private void queen(int row) { 24 | if (row == QUEEN_NUMBER) { 25 | total++; 26 | } else { 27 | for (int col = 0; col != QUEEN_NUMBER; col++) { 28 | columns[row] = col; 29 | if (isPut(row)) { 30 | queen(row+1); 31 | } 32 | } 33 | } 34 | } 35 | 36 | private boolean isPut(int row) { 37 | for (int i = 0; i != row; i++) { 38 | if (columns[row] == columns[i] || row - i == Math.abs(columns[row]-columns[i])) { 39 | return false; 40 | } 41 | } 42 | return true; 43 | } 44 | 45 | @Test 46 | public void test() { 47 | System.out.println(solution()); //92 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_38_StringCombination.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class Ex_38_StringCombination { 8 | public ArrayList Combination(String str) { 9 | ArrayList res = new ArrayList<>(); 10 | if (str == null || str.length() <= 0) return res; 11 | 12 | combination(str.toCharArray(), 0, res); 13 | return res; 14 | } 15 | 16 | private void combination(char[] chars, int startIndex, ArrayList res) { 17 | if (startIndex == chars.length) { 18 | StringBuilder sb = new StringBuilder(); 19 | for (char c : chars) { 20 | if (c != 0) sb.append(c); 21 | } 22 | 23 | res.add(sb.toString()); 24 | return; 25 | } 26 | 27 | combination(chars, startIndex+1, res); 28 | char temp = chars[startIndex]; 29 | chars[startIndex] = 0; 30 | combination(chars, startIndex+1, res); 31 | chars[startIndex] = temp; 32 | } 33 | 34 | @Test 35 | public void test() { 36 | ArrayList res = Combination(new String("abc")); 37 | for (String str : res) { 38 | System.out.println(str); 39 | } 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_38_StringPermutation.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | 6 | public class Ex_38_StringPermutation { 7 | public ArrayList Permutation(String str) { 8 | ArrayList res = new ArrayList<>(); 9 | if (str == null || str.length() <= 0) return res; 10 | 11 | permutation(str.toCharArray(), 0, res); 12 | Collections.sort(res); 13 | return res; 14 | } 15 | 16 | private void permutation(char[] chars, int startIndex, ArrayList res) { 17 | if (startIndex == chars.length-1) { 18 | String str = String.valueOf(chars); 19 | if (!res.contains(str)) { 20 | res.add(str); 21 | } 22 | } else { 23 | // 第一个字符与后面所有字符逐个交换:a|bcde b|acde c|bade d|bcae e|bcda 24 | // 第一个字符固定,第二个字符和后面所有字符逐个交换:a || b|cde c|bde d|cbe e|cdb 25 | for (int i = startIndex; i < chars.length; i++) { 26 | swap(chars, startIndex, i); 27 | permutation(chars, startIndex + 1, res); // a || b|cde c|bde d|cbe e|cdb 28 | swap(chars, startIndex, i); 29 | } 30 | } 31 | } 32 | 33 | private void swap(char[] chars, int i, int j) { 34 | char tmp = chars[i]; 35 | chars[i] = chars[j]; 36 | chars[j] = tmp; 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_39_MoreThanHalfNum.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_39_MoreThanHalfNum { 4 | 5 | public static int moreThanHalfNum(int[] array) { 6 | if (array == null || array.length <= 0) { 7 | return 0; 8 | } 9 | 10 | if (array.length == 1) { 11 | return array[0]; 12 | } 13 | 14 | int low = 0; 15 | int high = array.length-1; 16 | int mid = low + (high - low) / 2; 17 | 18 | int p = partition(array, low, high); 19 | 20 | while (p != mid) { 21 | if (p < mid) { 22 | p = partition(array, p+1, high); 23 | } else { 24 | p = partition(array, low, p-1); 25 | } 26 | } 27 | int result = array[mid]; 28 | 29 | if (!checkMoreThanHalf(array, result)) { 30 | result = 0; 31 | } 32 | 33 | return result; 34 | } 35 | 36 | public static boolean checkMoreThanHalf(int[] arr, int result) { 37 | int times = 0; 38 | 39 | for (int i = 0; i < arr.length; i++) { 40 | if (arr[i] == result) { 41 | times++; 42 | } 43 | } 44 | 45 | if (times * 2 <= arr.length) { 46 | return false; 47 | } 48 | 49 | return true; 50 | } 51 | 52 | public static int partition(int[] arr, int low, int high) { 53 | if (low == high) { 54 | return low; 55 | } 56 | int pIndex = low + (int) (Math.random() *(high - low)); 57 | swap(arr, low, pIndex); 58 | 59 | int pivot = arr[low]; 60 | 61 | int i = low; 62 | int j = high + 1; 63 | 64 | while (i < j) { 65 | while (arr[++i] < pivot) { 66 | if (i == high) { 67 | break; 68 | } 69 | } 70 | 71 | while (arr[--j] > pivot) { 72 | if (j == low) { 73 | break; 74 | } 75 | } 76 | 77 | if (i > j) { 78 | break; 79 | } 80 | 81 | swap(arr, i, j); 82 | } 83 | swap(arr, j, low); 84 | 85 | return j; 86 | } 87 | 88 | public static void swap(int[] arr, int i, int j) { 89 | int tmp = arr[i]; 90 | arr[i] = arr[j]; 91 | arr[j] = tmp; 92 | } 93 | 94 | public static int moreThanHalfNumWithoutChangeArray(int[] array) { 95 | if (array == null || array.length <= 0) { 96 | return 0; 97 | } 98 | 99 | int result = array[0]; 100 | int times = 1; 101 | 102 | for (int i = 1; i < array.length; i++) { 103 | if (times == 0) { 104 | result = array[i]; 105 | times = 1; 106 | } else if (array[i] == result) { 107 | times++; 108 | } else { 109 | times--; 110 | } 111 | } 112 | 113 | if (!checkMoreThanHalf(array, result)) { 114 | result = 0; 115 | } 116 | 117 | return result; 118 | } 119 | 120 | public static void main(String[] args) { 121 | int[] arr = new int[]{1,2,3,2,2,2,5,4,2}; 122 | System.out.println(moreThanHalfNumWithoutChangeArray(arr)); 123 | System.out.println(moreThanHalfNumWithoutChangeArray(new int[]{1})); 124 | System.out.println("============================="); 125 | TestUtils.printArray(arr); 126 | System.out.println(moreThanHalfNum(arr)); 127 | TestUtils.printArray(arr); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_40_GetLeastKNumbers.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class Ex_40_GetLeastKNumbers { 6 | 7 | public static ArrayList getLeastKNumbers(int[] input, int k) { 8 | if (input == null || k <= 0 || input.length < k || input.length <= 0) { 9 | return null; 10 | } 11 | 12 | int low = 0; 13 | int high = input.length - 1; 14 | int p = partition(input, low, high); 15 | 16 | while (p != k-1) { 17 | if (p > k-1) { 18 | p = partition(input, low, p-1); 19 | } else { 20 | p = partition(input, p+1, high); 21 | } 22 | } 23 | ArrayList res = new ArrayList<>(); 24 | for (int i = 0; i < k; i++) { 25 | res.add(input[i]); 26 | } 27 | return res; 28 | } 29 | 30 | // 找到第k小的数(那其左边就是比arr[k]小的k个数) 31 | public static int kthNum(int[] input, int k) { 32 | if (input == null || k <= 0 || input.length < k || input.length <= 0) { 33 | return -1; 34 | } 35 | 36 | int low = 0; 37 | int high = input.length - 1; 38 | int p = partition(input, low, high); 39 | 40 | while (p != k-1) { 41 | if (p > k-1) { 42 | p = partition(input, low, p-1); 43 | } else { 44 | p = partition(input, p+1, high); 45 | } 46 | } 47 | 48 | return input[p]; 49 | } 50 | 51 | public static int partition(int[] arr, int low, int high) { 52 | if (low == high) { 53 | return low; 54 | } 55 | 56 | int pivotIndex = low + (int) (Math.random() * (high - low)); 57 | swap(arr, low, pivotIndex); 58 | 59 | int pivot = arr[low]; 60 | int i = low; 61 | int j = high + 1; 62 | while (i < j) { 63 | while (arr[++i] < pivot) { 64 | if (i == high) break; 65 | } 66 | 67 | while (arr[--j] > pivot) { 68 | if (j == low) break; 69 | } 70 | 71 | if (i > j) break; 72 | 73 | swap(arr, i, j); 74 | } 75 | 76 | swap(arr, j, low); 77 | 78 | return j; 79 | } 80 | 81 | public static void swap(int[] arr, int i, int j) { 82 | int tmp = arr[i]; 83 | arr[i] = arr[j]; 84 | arr[j]= tmp; 85 | } 86 | 87 | public static void main(String[] args) { 88 | int[] arr = new int[] {4,5,1,6,2,7,3,8}; 89 | for (int i : getLeastKNumbers(arr, 8)) { 90 | System.out.println(i); 91 | } 92 | 93 | System.out.println(kthNum(arr, 5)); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_41_MedianInDataFlow.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Comparator; 4 | import java.util.PriorityQueue; 5 | 6 | public class Ex_41_MedianInDataFlow { 7 | 8 | private PriorityQueue maxHeap = new PriorityQueue<>(new MaxHeapComparator()); 9 | private PriorityQueue minHeap = new PriorityQueue<>(new MinHeapComparator()); 10 | 11 | public void Insert(Integer num) { 12 | if (this.maxHeap.isEmpty()) { 13 | this.maxHeap.add(num); 14 | return; 15 | } 16 | 17 | if (num <= this.maxHeap.peek()) { 18 | this.maxHeap.add(num); 19 | } else { 20 | if (this.minHeap.isEmpty()) { 21 | this.minHeap.add(num); 22 | return; 23 | } 24 | 25 | if (num >= this.minHeap.peek()) { 26 | this.minHeap.add(num); 27 | } else { 28 | this.maxHeap.add(num); 29 | } 30 | } 31 | 32 | modifyTwoHeapSize(); 33 | } 34 | 35 | public Double GetMedian() { 36 | int maxHeapSize = this.maxHeap.size(); 37 | int minHeapSize = this.minHeap.size(); 38 | 39 | // 若MaxHeap或者minHeap为空,则直接return null 40 | if (maxHeapSize + minHeapSize == 0) { 41 | return null; 42 | } 43 | 44 | Integer max = this.maxHeap.peek(); 45 | Integer min = this.minHeap.peek(); 46 | 47 | if (maxHeapSize == minHeapSize) { 48 | return (max + min) / 2.0; 49 | } 50 | 51 | return 1.0 * (maxHeapSize > minHeapSize ? max : min); 52 | } 53 | 54 | private void modifyTwoHeapSize() { 55 | if (this.maxHeap.size() == this.minHeap.size() + 2) { 56 | this.minHeap.add(this.maxHeap.poll()); 57 | } 58 | 59 | if (this.minHeap.size() == this.maxHeap.size() + 2) { 60 | this.maxHeap.add(this.minHeap.poll()); 61 | } 62 | } 63 | 64 | private static class MinHeapComparator implements Comparator { 65 | 66 | @Override 67 | public int compare(Integer o1, Integer o2) { 68 | if (o1 > o2) { 69 | return 1; 70 | } else { 71 | return -1; 72 | } 73 | } 74 | } 75 | 76 | private static class MaxHeapComparator implements Comparator { 77 | @Override 78 | public int compare(Integer o1, Integer o2) { 79 | return o2 > o1 ? 1 : -1; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_42_MaxSumOfSubArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | // 此题目类似于:Ex_63_MaxProfits 4 | public class Ex_42_MaxSumOfSubArray { 5 | public int FindGreatestSumOfSubArray(int[] array) { 6 | if (array == null || array.length < 1) { 7 | return 0; 8 | } 9 | 10 | int max = Integer.MIN_VALUE; 11 | int curSum = 0; 12 | 13 | for (int i = 0; i < array.length; i++) { 14 | curSum += array[i]; 15 | max = Math.max(max, curSum); 16 | curSum = curSum < 0 ? 0 : curSum; 17 | } 18 | 19 | return max; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_43_NumberOf1Between1AndN.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | //https://www.cnblogs.com/xuanxufeng/p/6854105.html 4 | public class Ex_43_NumberOf1Between1AndN { 5 | public int NumberOf1Between1AndN_Solution1(int n) { 6 | if (n < 1) { 7 | return 0; 8 | } 9 | 10 | int count = 0; 11 | for (int i = 1; i <= n; i++) { 12 | count += numberOf1(i); 13 | } 14 | 15 | return count; 16 | } 17 | 18 | private int numberOf1(int num) { 19 | int count = 0; 20 | while (num != 0) { 21 | if (num % 10 == 1) { 22 | count++; 23 | } 24 | num = num / 10; 25 | } 26 | 27 | return count; 28 | } 29 | 30 | public int NumberOf1Between1AndN_Solution(int n) { 31 | int ones = 0; // ones:1的个数 32 | // m:分别指的是个位,十位,百位...,即:10 100 1000 ... m是在以10倍增长,因此可能超过int型,变成long 33 | // 分别按照个位十位百位统计各个位子上的个数 34 | for (long m = 1; m <= n; m *= 10) { 35 | //a = n / m; // n的高位 36 | //b = n % m; // n的低位 37 | ones += (n/m + 8) / 10 * m + (n/m % 10 == 1 ? n%m + 1 : 0); 38 | } 39 | 40 | return ones; 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_44_ANumInArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_44_ANumInArray { 6 | public int digitAt(int index) { 7 | if (index < 0) { 8 | return -1; 9 | } 10 | 11 | int digits = 1; 12 | 13 | while (true) { 14 | int numbers = countNumbersOf(digits); 15 | if (index < numbers * digits) { 16 | return digitAt(index, digits); 17 | } 18 | 19 | index -= numbers * digits; 20 | digits++; 21 | } 22 | } 23 | 24 | private int countNumbersOf(int digits) { 25 | if (digits == 1) { 26 | return 10; 27 | } 28 | 29 | return 9 * (int)Math.pow(10, digits-1); 30 | } 31 | 32 | private int digitAt(int index, int digits) { 33 | int startNumber = digits == 1 ? 0 : (int)Math.pow(10, digits-1); 34 | int endNumber = startNumber + index / digits; 35 | index = digits - index % digits; 36 | for (int i = 1; i < index; i++) { 37 | endNumber /= 10; 38 | } 39 | 40 | return endNumber % 10; 41 | } 42 | 43 | @Test 44 | public void test() { 45 | System.out.println(digitAt(1001)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_45_MinNumByConcatArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Arrays; 4 | import java.util.Comparator; 5 | 6 | // 最小字典序问题 7 | public class Ex_45_MinNumByConcatArray { 8 | public String PrintMinNumber(int [] numbers) { 9 | if(numbers == null || numbers.length <= 0) { 10 | return ""; 11 | } 12 | 13 | String[] strs = new String[numbers.length]; 14 | for (int i = 0; i < numbers.length; i++) { 15 | strs[i] = String.valueOf(numbers[i]); 16 | } 17 | 18 | Arrays.sort(strs, new StrComparator()); 19 | 20 | String res = ""; 21 | for (String str : strs) { 22 | res += str; 23 | } 24 | 25 | return res; 26 | } 27 | 28 | private static class StrComparator implements Comparator { 29 | 30 | @Override 31 | public int compare(String o1, String o2) { 32 | return (o1+o2).compareTo(o2+o1); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_46_ConvertStringToIP.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 附加题目 5 | * 6 | * problem 5: [String][递归][动态规划] 7 | * 8 | * 给定一个由数字组成的字符串, 请返回能返回多少种合法的ipv4组合。 9 | * 10 | * 知识点: 11 | * IPv4: 点分十进制 12 | * 1. x.x.x.x: 4 parts 13 | * 2. 0 <= x <= 255 14 | * 3. x不能有0a这种形式 15 | */ 16 | public class Ex_46_ConvertStringToIP { 17 | 18 | public static int convertStringToIp1(String str) { 19 | if (str == null || str.length() < 4 || str.length() > 12) { 20 | return 0; 21 | } 22 | 23 | char[] chars = str.toCharArray(); 24 | return process1(chars, 0, 0); 25 | } 26 | 27 | /** 28 | * 29 | * @param chars 30 | * @param i 0~i-1已经形成合法的IPv4的部分,考察i~N-1能组合出多少种 31 | * @param parts 0~i-1已经形成合法IPv4的部分的部分数 32 | * @return 33 | */ 34 | public static int process1(char[] chars, int i, int parts) { 35 | // if (i > chars.length || parts > 4) { 36 | // return 0; 37 | // } 38 | 39 | if (i == chars.length) { 40 | return parts == 4 ? 1 : 0; 41 | } 42 | 43 | int res = 0; 44 | 45 | res += process1(chars, i+1, parts+1); 46 | 47 | if (chars[i] == '0') { 48 | return res; 49 | } 50 | 51 | if (i + 2 <= chars.length) { 52 | res += process1(chars, i+2, parts+1); 53 | } 54 | 55 | if (i + 3 <= chars.length) { 56 | int sum = (chars[i] - '0') * 100 + (chars[i+1] - '0') * 10 + (chars[i+2] - '0'); 57 | if (sum <= 255) { 58 | return res + process1(chars, i+3, parts + 1); 59 | } 60 | } 61 | 62 | return res; 63 | } 64 | 65 | public static int convertStringToIp2(String str) { 66 | if (str == null || str.length() < 4 || str.length() > 12) { 67 | return 0; 68 | } 69 | 70 | char[] chars = str.toCharArray(); 71 | int[][] dp = new int[chars.length+1][6]; 72 | 73 | dp[chars.length][4] = 1; 74 | 75 | for (int i = dp.length-2; i >= 0; i--) { 76 | for (int j = dp[i].length - 2; j >= 0; j--) { 77 | 78 | dp[i][j] = dp[i+1][j+1]; 79 | 80 | if (chars[i] != '0') { 81 | if (i+2 < dp.length) { 82 | dp[i][j] = dp[i][j] + dp[i+2][j+1]; 83 | } 84 | 85 | if (i+3 < dp.length) { 86 | int sum = (chars[i] - '0') * 100 + (chars[i+1] - '0') * 10 + (chars[i+2] - '0'); 87 | if (sum < 256) { 88 | dp[i][j] = dp[i][j] + dp[i + 3][j + 1]; 89 | } 90 | } 91 | } 92 | } 93 | } 94 | return dp[0][0]; 95 | } 96 | 97 | public static String getRandomNumberString() { 98 | char[] chas = new char[(int) (Math.random() * 10) + 3]; 99 | for (int i = 0; i < chas.length; i++) { 100 | chas[i] = (char) (48 + (int) (Math.random() * 10)); 101 | } 102 | return String.valueOf(chas); 103 | } 104 | 105 | public static void main(String[] args) { 106 | int testTime = 3000000; 107 | boolean hasErr = false; 108 | for (int i = 0; i < testTime; i++) { 109 | String test = getRandomNumberString(); 110 | if (convertStringToIp1(test) != convertStringToIp2(test)) { 111 | hasErr = true; 112 | } 113 | } 114 | if (hasErr) { 115 | System.out.println("233333"); 116 | } else { 117 | System.out.println("666666"); 118 | } 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_46_TranslationFromIntToString.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * String -> Another String 7 | */ 8 | public class Ex_46_TranslationFromIntToString { 9 | // 动态规划:从下而上(从后往前) 10 | public int translation(int num) { 11 | if (num < 0) { 12 | return -1; 13 | } 14 | 15 | String str = String.valueOf(num); 16 | int len = str.length(); 17 | int counts[] = new int[len]; 18 | 19 | counts[len-1] = 1; 20 | 21 | for (int i = len-2; i>=0; i--) { 22 | int count = 0; 23 | count = counts[i+1]; 24 | 25 | int d1 = str.charAt(i) - '0'; 26 | int d2 = str.charAt(i+1) - '0'; 27 | int convertedNum = d1 * 10 + d2; 28 | if (convertedNum >= 10 && convertedNum <=25) { 29 | if (i < len-2) { 30 | count += counts[i+2]; 31 | } else { 32 | count += 1; 33 | } 34 | } 35 | counts[i] = count; 36 | } 37 | 38 | return counts[0]; 39 | } 40 | 41 | // 递归:自上而下(从前到后) 42 | public int translation1(int num) { 43 | if (num < 0) { 44 | return -1; 45 | } 46 | 47 | String str = String.valueOf(num); 48 | char[] chars = str.toCharArray(); 49 | 50 | return translationCore(chars, 0); 51 | } 52 | 53 | private int translationCore(char[] chars, int start) { 54 | if (start == chars.length) { 55 | return 1; 56 | } 57 | 58 | int res = 0; 59 | 60 | res += translationCore(chars, start + 1); 61 | 62 | if (chars[start] == '0') { 63 | return res; 64 | } 65 | 66 | if (start + 1 < chars.length) { 67 | int sum = (chars[start] - '0') * 10 + (chars[start+1] - '0'); 68 | if (sum < 26) { 69 | res += translationCore(chars, start + 2); 70 | } 71 | } 72 | 73 | return res; 74 | } 75 | 76 | @Test 77 | public void test() { 78 | System.out.println(translation(1234)); 79 | System.out.println(translation(12258)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_47_MaxGiftValue.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_47_MaxGiftValue { 6 | public int getMaxValue(int[][] matrix) { 7 | if (matrix == null || matrix.length <= 0 || matrix[0].length <= 0) { 8 | return -1; 9 | } 10 | 11 | int rowSize = matrix.length; 12 | int colSize = matrix[0].length; 13 | int[][] result = new int[rowSize][colSize]; 14 | 15 | for (int i = 0; i < rowSize; i++) { 16 | for (int j = 0; j < colSize; j++) { 17 | int left = 0; 18 | int up = 0; 19 | if (i > 0) { 20 | left = result[i-1][j]; 21 | } 22 | if (j > 0) { 23 | up = result[i][j-1]; 24 | } 25 | 26 | result[i][j] = Math.max(left, up) + matrix[i][j]; 27 | } 28 | } 29 | 30 | return result[rowSize-1][colSize-1]; 31 | } 32 | 33 | public int getMaxValue1(int[][] matrix) { 34 | if (matrix == null || matrix.length <= 0 || matrix[0].length <= 0) { 35 | return -1; 36 | } 37 | 38 | return process(matrix, 0, 0); 39 | } 40 | 41 | private int process(int[][] matrix, int startRow, int startCol) { 42 | int rowSize = matrix.length; 43 | int colSize = matrix[0].length; 44 | int curValue = matrix[startRow][startCol]; 45 | 46 | if (startRow == rowSize && startCol == colSize) { 47 | return matrix[startRow][startCol]; 48 | } 49 | 50 | 51 | int down = 0; 52 | int right = 0; 53 | if (startRow + 1 < rowSize) { 54 | down = process(matrix, startRow + 1, startCol); 55 | } 56 | 57 | if (startCol + 1 < colSize) { 58 | right = process(matrix, startRow, startCol + 1); 59 | } 60 | 61 | return curValue + Math.max(down, right); 62 | } 63 | 64 | @Test 65 | public void test() { 66 | int[][] matrix = new int[][] { 67 | {1 , 10, 3 , 8 }, 68 | {12, 2 , 9 , 6 }, 69 | {5 , 7 , 4 , 11}, 70 | {3, 7 , 16, 5 } 71 | }; 72 | System.out.println(getMaxValue(matrix)); 73 | System.out.println(getMaxValue1(matrix)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_48_LongestSubStringWithDuplication.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | // 这个题目和Ex_42_MaxSumOfSubArray类似 6 | public class Ex_48_LongestSubStringWithDuplication { 7 | public int longestSubString(String str) { 8 | if (str == null || str.length() < 1) { 9 | return 0; 10 | } 11 | 12 | int curLen = 0; 13 | int maxLen = 0; 14 | 15 | // 注意这里利用一个int[]记录了每个字符上次出现的位置,这样就可以计算出每个位置和他上次出现位置的距离 16 | // 注意其下标为:char - 'a' 17 | int[] lastPositions = new int[26]; // 某个字符上一次出现的索引,从未出现为-1; 18 | 19 | for (int i = 0; i < 26; i++) { 20 | lastPositions[i] = -1; 21 | } 22 | 23 | for (int i = 0; i < str.length(); i++) { 24 | int lastIndex = lastPositions[str.charAt(i) - 'a']; 25 | int distance = i - lastIndex; 26 | if (lastIndex < -1 || distance > curLen) { 27 | curLen++; 28 | } else { 29 | curLen = distance; 30 | } 31 | 32 | if (curLen > maxLen) maxLen = curLen; 33 | 34 | lastPositions[str.charAt(i) - 'a'] = i; // 更新最后出现位置 35 | } 36 | 37 | return Math.max(maxLen, curLen); 38 | } 39 | 40 | @Test 41 | public void test() { 42 | String str = "arabcacfr"; 43 | System.out.println(longestSubString(str)); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_49_UglyNumber.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_49_UglyNumber { 6 | // 保存所有丑数,同时只检查丑数,不检查非丑数 7 | public int getUglyNumber(int index) { 8 | if (index <= 0) { 9 | return 0; 10 | } 11 | 12 | int[] uglyNumbers = new int[index]; 13 | uglyNumbers[0] = 1; 14 | int nextIndex = 1; 15 | int indexOf2 = 0; // nextIndex之前(包括)最小的索引(*2得到的丑数) 16 | int indexOf3 = 0; 17 | int indexOf5 = 0; 18 | 19 | while (nextIndex < index) { 20 | int nextUgly = min(uglyNumbers[indexOf2] * 2, uglyNumbers[indexOf3] * 3, uglyNumbers[indexOf5] * 5); 21 | uglyNumbers[nextIndex] = nextUgly; 22 | 23 | while (uglyNumbers[indexOf2] * 2 <= nextUgly) { 24 | indexOf2++; 25 | } 26 | 27 | while (uglyNumbers[indexOf3] * 3 <= nextUgly) { 28 | indexOf3++; 29 | } 30 | 31 | while (uglyNumbers[indexOf5] * 5 <= nextUgly) { 32 | indexOf5++; 33 | } 34 | 35 | nextIndex++; 36 | } 37 | 38 | return uglyNumbers[index-1]; 39 | } 40 | 41 | private int min(int x, int y, int z) { 42 | int min = x < y ? x : y; 43 | 44 | return min < z ? min : z; 45 | } 46 | // sol 1: 暴力解法 47 | public int getUglyNumber1(int index) { 48 | if (index <= 0) { 49 | return -1; 50 | } 51 | 52 | int number = 0; 53 | int uglyCount = 0; 54 | 55 | while (uglyCount < index) { 56 | number++; 57 | if (isUgly(number)) { 58 | uglyCount++; 59 | } 60 | } 61 | 62 | return number; 63 | } 64 | // 丑数的性质: 65 | // 若一个数仅能被2, 3, 5整除,那么除去所有的2 3 5 因子,之后应该是1 66 | // 若一个数是丑数,则这个数的2,3, 5倍都是丑数。 67 | public boolean isUgly(int number) { 68 | if (number == 1) { 69 | return true; 70 | } 71 | 72 | while (number % 2 == 0) { 73 | number /= 2; 74 | } 75 | 76 | while (number % 3 == 0) { 77 | number /= 3; 78 | } 79 | 80 | while (number % 5 == 0) { 81 | number /= 5; 82 | } 83 | 84 | return number == 1 ? true : false; 85 | } 86 | 87 | @Test 88 | public void test() { 89 | int number = 14; 90 | System.out.println(getUglyNumber(1500)); 91 | System.out.println(getUglyNumber1(1500)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_50_FirstNotRepeatedChar.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.HashMap; 4 | 5 | public class Ex_50_FirstNotRepeatedChar { 6 | public int FirstNotRepeatingChar(String str) { 7 | if (str == null || str.length() < 1) { 8 | return -1; 9 | } 10 | 11 | int[] hashTable = new int[256]; // 简单的HashTable 12 | 13 | for (int i = 0; i < 256; i++) { 14 | hashTable[i] = 0; 15 | } 16 | 17 | for (int i = 0; i < str.length(); i++) { 18 | hashTable[str.charAt(i)]++; 19 | } 20 | 21 | int index = -1; 22 | 23 | for (int i = 0; i < str.length(); i++) { 24 | if (hashTable[str.charAt(i)] == 1) { 25 | index = i; 26 | break; 27 | } 28 | } 29 | 30 | return index; 31 | } 32 | 33 | 34 | public int FirstNotRepeatingChar1(String str) { 35 | if (str == null || str.length() < 1) { 36 | return -1; 37 | } 38 | 39 | HashMap map = new HashMap<>(); 40 | for (int i = 0; i < str.length(); i++) { 41 | if (!map.containsKey(str.charAt(i))) { 42 | map.put(str.charAt(i), 1); 43 | } else { 44 | int count = map.get(str.charAt(i)).intValue() + 1; 45 | map.put(str.charAt(i), count); 46 | } 47 | } 48 | 49 | int index = 0; 50 | for (int i = 0; i < str.length(); i++) { 51 | if (map.get(str.charAt(i)).intValue() == 1) { 52 | index = i; 53 | break; 54 | } 55 | } 56 | return index; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_50_FirstNotRepeatedCharInDataFlow.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_50_FirstNotRepeatedCharInDataFlow { 4 | 5 | private static final int TABLE_SIZE = 256; 6 | 7 | // 保存字符在字符串中的位置 8 | // -1:初始值 9 | // -2:重复 10 | // >= 0:表示第一次出现 11 | private int[] hashTable = new int[TABLE_SIZE]; 12 | 13 | private int index = 0; 14 | 15 | public Ex_50_FirstNotRepeatedCharInDataFlow() { 16 | for (int i = 0; i < TABLE_SIZE; i++) { 17 | hashTable[i] = -1; 18 | } 19 | } 20 | 21 | //Insert one char from string stream 22 | public void Insert(char ch) 23 | { 24 | if (hashTable[ch] == -1) { 25 | hashTable[ch] = index; 26 | } else if (hashTable[ch] >= 0) { 27 | hashTable[ch] = -2; 28 | } 29 | 30 | index++; 31 | } 32 | //return the first appearance once char in current string stream 33 | public char FirstAppearingOnce() 34 | { 35 | char c = '#'; 36 | int minIndex = Integer.MAX_VALUE; 37 | 38 | for (int i = 0; i < TABLE_SIZE; i++) { 39 | if (hashTable[i] >= 0 && hashTable[i] < minIndex) { 40 | c = (char)i; 41 | minIndex = hashTable[i]; 42 | } 43 | } 44 | 45 | return c; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_50_StringUtilsSolutions.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.HashMap; 6 | 7 | public class Ex_50_StringUtilsSolutions { 8 | 9 | public String deleteString(String str1, String str2) { 10 | if (str1 == null || str1.length() <= 0) return null; 11 | 12 | if (str2 == null || str2.length() <= 0) return str1; 13 | 14 | HashMap map = new HashMap<>(); 15 | for (int i = 0; i < str2.length(); i++) { 16 | map.put(str2.charAt(i), 1); 17 | } 18 | 19 | StringBuilder sb = new StringBuilder(); 20 | for (int i = 0; i < str1.length(); i++) { 21 | if (!map.containsKey(str1.charAt(i))) { 22 | sb.append(str1.charAt(i)); 23 | } 24 | } 25 | 26 | return sb.toString(); 27 | } 28 | 29 | public String deleteDuplicatedChar(String str) { 30 | if (str == null || str.length() <= 0) { 31 | return null; 32 | } 33 | 34 | HashMap map = new HashMap<>(); 35 | for (int i = 0; i < str.length(); i++) { 36 | if (!map.containsKey(str.charAt(i))) { 37 | map.put(str.charAt(i), 1); 38 | } else { 39 | map.put(str.charAt(i), map.get(str.charAt(i)).intValue() + 1); 40 | } 41 | } 42 | 43 | StringBuilder sb = new StringBuilder(); 44 | for (int i = 0; i < str.length(); i++) { 45 | if (map.get(str.charAt(i)).intValue() > 1) { 46 | sb.append(str.charAt(i)); 47 | map.put(str.charAt(i), 0); 48 | } 49 | 50 | if (map.get(str.charAt(i)).intValue() == 1) { 51 | sb.append(str.charAt(i)); 52 | } 53 | } 54 | 55 | return sb.toString(); 56 | } 57 | 58 | public boolean isAnagram(String str1, String str2) { 59 | if (str1 == null || str1.length() <= 0 || str2 == null || str2.length() <= 0 || str1.length() != str2.length()) { 60 | return false; 61 | } 62 | 63 | HashMap map = new HashMap<>(); 64 | for (int i = 0; i < str1.length(); i++) { 65 | if (!map.containsKey(str1.charAt(i))) { 66 | map.put(str1.charAt(i), 1); 67 | } else { 68 | map.put(str1.charAt(i), map.get(str1.charAt(i)).intValue() + 1); 69 | } 70 | } 71 | 72 | for (int i = 0; i < str2.length(); i++) { 73 | if (map.containsKey(str2.charAt(i))) { 74 | map.put(str2.charAt(i), map.get(str2.charAt(i)).intValue()-1); 75 | } 76 | } 77 | 78 | for (Character c : map.keySet()) { 79 | if (map.get(c).intValue() != 0) { 80 | return false; 81 | } 82 | } 83 | return true; 84 | } 85 | 86 | @Test 87 | public void testDeleteString() { 88 | String str1 = "We are students"; 89 | String str2 = "aeiou"; 90 | System.out.println(deleteString(str1, str2)); 91 | } 92 | 93 | @Test 94 | public void testDeleteDuplicatedChar() { 95 | String str = "google"; 96 | System.out.println(deleteDuplicatedChar(str)); 97 | } 98 | 99 | @Test 100 | public void testIsAnagram() { 101 | String str1 = "silent"; 102 | String str2 = "listen"; 103 | String str3 = "livexy"; 104 | System.out.println(isAnagram(str1, str2)); 105 | System.out.println(isAnagram(str1, str3)); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_51_InversePairs.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Ex_51_InversePairs { 6 | public int InversePairs(int [] array) { 7 | if (array == null || array.length < 2) { 8 | return 0; 9 | } 10 | int[] copy = Arrays.copyOf(array, array.length); 11 | int count = mergeSort(array, 0, array.length-1); 12 | 13 | return count; 14 | } 15 | 16 | private int mergeSort(int[] array, int low, int high) { 17 | if (low == high) { 18 | return 0; 19 | } 20 | 21 | int mid = low + ((high-low) >> 1); 22 | int left = mergeSort(array, low, mid); 23 | int right = mergeSort(array, mid+1, high); 24 | int merge = merge(array, low, mid, high); 25 | return left + right + merge ; 26 | } 27 | 28 | private int merge(int[] array, int low, int mid, int high) { 29 | int[] help = new int[high-low+1]; 30 | int i = 0; 31 | int p1 = low; 32 | int p2 = mid+1; 33 | int res = 0; 34 | 35 | while (p1 <= mid && p2 <= high) { 36 | res += array[p1] > array[p2] ? (high-p2+1) : 0; 37 | help[i++] = array[p1] > array[p2] ? array[p1++] : array[p2++]; 38 | } 39 | 40 | while (p1 <= mid) { 41 | help[i++] = array[p1++]; 42 | } 43 | 44 | while (p2 <= high) { 45 | help[i++] = array[p2++]; 46 | } 47 | 48 | for (i = 0; i < help.length; i++) { 49 | array[low + i] = help[i]; 50 | } 51 | 52 | return res; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_51_InversePairs_BigData.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Ex_51_InversePairs_BigData { 6 | public int InversePairs(int [] array) { 7 | if (array == null || array.length < 2) { 8 | return 0; 9 | } 10 | 11 | int count = mergeSort(array, 0, array.length-1); 12 | 13 | return count; 14 | } 15 | 16 | private int mergeSort(int[] array, int low, int high) { 17 | if (low == high) { 18 | return 0; 19 | } 20 | 21 | int mid = low + ((high-low) >> 1); 22 | int left = mergeSort(array, low, mid); 23 | int right = mergeSort(array, mid+1, high); 24 | int merge = merge(array, low, mid, high); 25 | 26 | return (left + right + merge) % 1000000007 ; 27 | } 28 | 29 | private int merge(int[] array, int low, int mid, int high) { 30 | int[] help = new int[high-low+1]; 31 | int i = 0; 32 | int p1 = low; 33 | int p2 = mid+1; 34 | int res = 0; 35 | 36 | while (p1 <= mid && p2 <= high) { 37 | res += array[p1] > array[p2] ? (high-p2+1): 0; 38 | res = res >= 1000000007? res % 1000000007 : res; // 数据过大,会溢出 39 | help[i++] = array[p1] > array[p2] ? array[p1++] : array[p2++]; 40 | } 41 | 42 | while (p1 <= mid) { 43 | help[i++] = array[p1++]; 44 | } 45 | 46 | while (p2 <= high) { 47 | help[i++] = array[p2++]; 48 | } 49 | 50 | for (i = 0; i < help.length; i++) { 51 | array[low + i] = help[i]; 52 | } 53 | 54 | return res; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_52_FirstCommonNode.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_52_FirstCommonNode { 4 | public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { 5 | if (pHead1 == null || pHead2 == null) { 6 | return null; 7 | } 8 | 9 | int len1 = getLengthOfList(pHead1); 10 | int len2 = getLengthOfList(pHead2); 11 | int diff = Math.abs(len1-len2); 12 | 13 | ListNode longListHead = len1 > len2 ? pHead1 : pHead2; 14 | ListNode shortListHead = len1 < len2 ? pHead1 : pHead2; 15 | 16 | for (int i = 0; i < diff; i++) { 17 | longListHead = longListHead.next; 18 | } 19 | 20 | while (longListHead != null && longListHead.val != shortListHead.val) { 21 | longListHead = longListHead.next; 22 | shortListHead = shortListHead.next; 23 | } 24 | 25 | return longListHead != null ? longListHead : null; 26 | } 27 | 28 | private int getLengthOfList(ListNode pHead1) { 29 | if (pHead1 == null) { 30 | return 0; 31 | } 32 | 33 | int len = 0; 34 | for (ListNode node = pHead1; node != null; node = node.next) { 35 | len++; 36 | } 37 | 38 | return len; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_53_GetMissingNumber.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_53_GetMissingNumber { 4 | public int getMissingNumber(int[] array) { 5 | if (array == null || array.length < 1) { 6 | return -1; 7 | } 8 | 9 | int low = 0; 10 | int high = array.length-1; 11 | while (low <= high) { 12 | int mid = low + ((high - low) >> 1); 13 | if (array[mid] != mid) { 14 | if (mid == 0 || array[mid-1] == mid-1) { 15 | return mid; 16 | } 17 | high = mid-1; 18 | } else { 19 | low = mid + 1; 20 | } 21 | } 22 | 23 | if (low == array.length-1) { 24 | return array.length; 25 | } 26 | return -1; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_53_GetNumberOfK.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_53_GetNumberOfK { 6 | public int GetNumberOfK(int [] array , int k) { 7 | if (array == null || array.length <= 0) { 8 | return 0; 9 | } 10 | 11 | int left = getFirstIndexOfK(array, k, 0, array.length-1); 12 | int right = getLastIndexOfK(array, k, 0, array.length-1); 13 | 14 | if (left != -1 && right != -1) { 15 | return right - left + 1; 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | private int getFirstIndexOfK(int[] array, int k, int low, int high) { 22 | if (low > high) { 23 | return -1; 24 | } 25 | 26 | int midIndex = low + ((high-low) >> 1); 27 | int midData = array[midIndex]; 28 | if (midData == k) { 29 | if (midIndex > 0 && array[midIndex-1] != midData || midIndex == 0) { 30 | return midIndex; 31 | } else { 32 | high = midIndex-1; 33 | } 34 | } else if (midData > k) { 35 | high = midIndex - 1; 36 | } else { 37 | low = midIndex + 1; 38 | } 39 | 40 | return getFirstIndexOfK(array, k, low, high); 41 | } 42 | 43 | private int getLastIndexOfK(int[] array, int k, int low, int high) { 44 | if (low > high) { 45 | return -1; 46 | } 47 | 48 | int midIndex = low + ((high-low) >> 1); 49 | int midData = array[midIndex]; 50 | if (midData == k) { 51 | if (midIndex < array.length-1 && array[midIndex+1] != k || midIndex == array.length-1) { 52 | return midIndex; 53 | } else { 54 | low = midIndex + 1; 55 | } 56 | } else if (midData > k) { 57 | high = midIndex - 1; 58 | } else { 59 | low = midIndex + 1; 60 | } 61 | 62 | return getLastIndexOfK(array, k, low, high); 63 | } 64 | 65 | @Test 66 | public void test() { 67 | int[] array = new int[]{1,3,3,3,3,3,4,5}; 68 | System.out.println(getFirstIndexOfK(array, 2, 0, array.length-1)); 69 | System.out.println(getLastIndexOfK(array, 2, 0, array.length-1)); 70 | System.out.println(GetNumberOfK(array, 2)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_53_GetNumberSameAsIndex.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_53_GetNumberSameAsIndex { 6 | 7 | public int getNumberSameAsIndex(int[] array) { 8 | if (array == null || array.length <= 0) { 9 | return -1; 10 | } 11 | 12 | int low = 0; 13 | int high = array.length-1; 14 | 15 | while (low <= high) { 16 | int midIndex = low + ((high - low) >> 1); 17 | int midData = array[midIndex]; 18 | 19 | if (midData == midIndex) { 20 | return midData; 21 | } else if (midData > midIndex) { 22 | high = midIndex-1; 23 | } else { 24 | low = midIndex + 1; 25 | } 26 | } 27 | 28 | return -1; 29 | } 30 | 31 | @Test 32 | public void test() { 33 | int[] array = new int[] {-3,-1,1,3,5}; 34 | System.out.println(getNumberSameAsIndex(array)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_54_KthNodeInBST.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_54_KthNodeInBST { 4 | 5 | int count = 0; // 递归全局变量 6 | 7 | TreeNode KthNode(TreeNode pRoot, int k) 8 | { 9 | if (pRoot != null) { 10 | TreeNode node = KthNode(pRoot.left, k); 11 | if (node != null) { 12 | return node; 13 | } 14 | 15 | count++; 16 | if (count == k) { 17 | return pRoot; 18 | } 19 | 20 | node = KthNode(pRoot.right, k); 21 | if (node != null) { 22 | return node; 23 | } 24 | } 25 | 26 | return null; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_55_BalancedBT.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_55_BalancedBT { 4 | 5 | // Java没有引用和指针,可以使用全局变量,也可以使用数组引用 6 | int depth = 0; 7 | 8 | public boolean IsBalanced_Solution(TreeNode root) { 9 | return isBalance(root); 10 | } 11 | 12 | private boolean isBalance(TreeNode root) { 13 | if (root == null) { 14 | depth = 0; // 深度为0 15 | return true; 16 | } 17 | 18 | boolean left = isBalance(root.left); 19 | int leftDepth = depth; // 左子树深度 20 | 21 | boolean right = isBalance(root.right); 22 | int rightDepth = depth; // 右子树深度 23 | 24 | depth = Math.max(leftDepth + 1, rightDepth + 1); // root深度(后序遍历) 25 | 26 | if (left && right && Math.abs(leftDepth - rightDepth) <= 1) { 27 | return true; 28 | } 29 | 30 | return false; 31 | } 32 | 33 | //pos-order遍历,使用辅助数组depth来保存每一步遍历的深度,同时返回该节点是否是平衡的 34 | public boolean IsBalanced_Solution1(TreeNode root) { 35 | return isBalance(root, new int[1]); 36 | } 37 | 38 | public boolean isBalance(TreeNode root, int[] depth) { 39 | if (root == null) { 40 | depth[0] = 0; 41 | return true; 42 | } 43 | boolean left = isBalance(root.left, depth); 44 | int leftdepth = depth[0]; 45 | 46 | boolean right = isBalance(root.right, depth); 47 | int rightdepth = depth[0]; 48 | 49 | depth[0] = Math.max(leftdepth + 1, rightdepth + 1); 50 | 51 | if (left && right && Math.abs(leftdepth - rightdepth) <= 1) return true; 52 | return false; 53 | } 54 | 55 | // 从上到下遍历: 遍历每个结点,借助一个获取树深度的递归函数, 56 | // 根据该结点的左右子树高度差判断是否平衡,然后递归地对左右子树进行判断。 57 | public boolean IsBalanced_Solution2(TreeNode root) { 58 | if (root == null) { 59 | return true; 60 | } 61 | 62 | int leftDepth = TreeDepth(root.left); 63 | int rightDepth = TreeDepth(root.right); 64 | int diff = leftDepth - rightDepth; 65 | 66 | if (diff > 1 || diff < -1) { 67 | return false; 68 | } 69 | 70 | return IsBalanced_Solution2(root.left) && IsBalanced_Solution2(root.right); 71 | } 72 | 73 | private int TreeDepth(TreeNode root) { 74 | if (root == null) { 75 | return 0; 76 | } 77 | 78 | int leftTreeDepth = TreeDepth(root.left); 79 | int rightTreeDepth = TreeDepth(root.right); 80 | 81 | return leftTreeDepth > rightTreeDepth ? (leftTreeDepth + 1) : (rightTreeDepth + 1); 82 | } 83 | 84 | // 从下到上遍历: 85 | // 从上到下遍历在判断上层结点的时候,会多次重复遍历下层结点,增加了不必要的开销。 86 | // 如果改为从下往上遍历,如果子树是平衡二叉树,则返回子树的高度; 87 | // 如果发现子树不是平衡二叉树,则直接停止遍历,这样至多只对每个结点访问一次。 88 | public boolean IsBalanced_Solution3(TreeNode root) { 89 | return getDepth(root) != -1; 90 | } 91 | 92 | // 若左右子树高度差大于1,则返回-1(不是平衡二叉树) 93 | // 若左右子树高度差不大于1,则返回子树的高度 94 | private int getDepth(TreeNode root) { 95 | if (root == null) { 96 | return 0; 97 | } 98 | 99 | int leftDepth = getDepth(root.left); 100 | if (leftDepth == -1) return -1; 101 | 102 | int rightDepth = getDepth(root.right); 103 | if (rightDepth == -1) return -1; 104 | 105 | return Math.abs(leftDepth - rightDepth) > 1 ? -1 : (Math.max(leftDepth, rightDepth) + 1); 106 | } 107 | 108 | 109 | } 110 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_55_DepthOfBT.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_55_DepthOfBT { 4 | public int TreeDepth(TreeNode root) { 5 | if (root == null) { 6 | return 0; 7 | } 8 | 9 | int leftTreeDepth = TreeDepth(root.left); 10 | int rightTreeDepth = TreeDepth(root.right); 11 | 12 | return leftTreeDepth > rightTreeDepth ? (leftTreeDepth + 1) : (rightTreeDepth + 1); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_56_AppearanceOnce.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | //num1,num2分别为长度为1的数组。传出参数 4 | //将num1[0],num2[0]设置为返回结果 5 | public class Ex_56_AppearanceOnce { 6 | public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { 7 | if (array == null || array.length < 2) { 8 | return; 9 | } 10 | 11 | int xor = 0; 12 | for (int i = 0; i < array.length; i++) { 13 | xor = xor ^ array[i]; // xor = a ^ b = num1[0] ^ num2[0] 14 | } 15 | 16 | int indexOf1 = findFirst1_Bit(xor); 17 | 18 | for (int i = 0; i < array.length; i++) { 19 | if (is1_Bit(array[i], indexOf1)) { 20 | num1[0] = num1[0] ^ array[i]; 21 | } else { 22 | num2[0] = num2[0] ^ array[i]; 23 | } 24 | } 25 | } 26 | 27 | // 从右到左第1bit为1的index 28 | private int findFirst1_Bit(int num) { 29 | int index = 0; 30 | int len = 8 * 4; 31 | while (index < len && (num & 1) == 0) { 32 | num = num >> 1; 33 | index++; 34 | } 35 | return index; 36 | } 37 | 38 | // 判断从右到左第index位是不是1 39 | private boolean is1_Bit(int num, int index) { 40 | num = num >> index; 41 | return (num & 1) == 1; 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_56_AppearanceOnce_Continued.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_56_AppearanceOnce_Continued { 6 | public int FindNumAppearOnce(int[] array) { 7 | if (array == null || array.length < 1) { 8 | return -1; 9 | } 10 | 11 | int[] bitSum = new int[8 * 4];// 所有元素的各个bit分别相加 12 | 13 | for (int i = 0; i < array.length; i++) { 14 | int bitFlag = 1; // bit & 1 = bit 如:xxx & 010 = 0x0 15 | for (int j = 31; j >= 0; j--) { 16 | int bit = array[i] & bitFlag; // 每一位都是0x0...或者000... 17 | bitSum[j] += bit == 0 ? 0 : 1; // 但是这里只能加1或者0 18 | bitFlag = bitFlag << 1; 19 | } 20 | } 21 | 22 | int result = 0; 23 | for (int i = 0; i < 32; i++) { 24 | result = result << 1; 25 | result += bitSum[i] % 3; 26 | } 27 | 28 | return result; 29 | } 30 | 31 | @Test 32 | public void test() { 33 | int[] array = new int[] {4, 5,5,5,9,9,9,8,8,8, 20, 4,4}; 34 | System.out.println(FindNumAppearOnce(array)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_57_FindContinuousSequence.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class Ex_57_FindContinuousSequence { 8 | public ArrayList> FindContinuousSequence(int sum) { 9 | ArrayList> res = new ArrayList<>(); 10 | if (sum < 3) { 11 | return res; 12 | } 13 | 14 | int small = 1; 15 | int big = 2; 16 | int mid = (sum + 1) / 2; 17 | int curSum = small+big; 18 | 19 | while (small < mid) { 20 | if (curSum == sum) { 21 | res.add(new ArrayList<>(full(small, big))); // 一定要注意这里,要拷贝构造,不能直接传入引用 22 | } 23 | 24 | while (curSum > sum && small < mid) { 25 | curSum -= small; 26 | small++; 27 | if (curSum == sum) { 28 | res.add(new ArrayList<>(full(small, big))); 29 | } 30 | } 31 | big++; 32 | curSum+=big; 33 | } 34 | return res; 35 | } 36 | 37 | private ArrayList full(int small, int big) { 38 | ArrayList list = new ArrayList<>(); 39 | for (int i = small; i <= big; i++) { 40 | list.add(i); 41 | } 42 | return list; 43 | } 44 | 45 | @Test 46 | public void test() { 47 | ArrayList> list = FindContinuousSequence(15); 48 | for (ArrayList x : list) { 49 | for (Integer i : x) { 50 | System.out.print(i + " "); 51 | } 52 | System.out.println(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_57_FindNumbersWithSum.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | public class Ex_57_FindNumbersWithSum { 8 | public ArrayList FindNumbersWithSum(int [] array, int sum) { 9 | ArrayList res = new ArrayList<>(); 10 | if (array == null || array.length <= 1) return res; 11 | 12 | int left = 0; 13 | int right = array.length-1; 14 | int curSum = 0; 15 | ArrayList leftList = new ArrayList<>(); 16 | ArrayList rightList = new ArrayList<>(); 17 | boolean isFound = false; 18 | while (left < right) { 19 | curSum = array[left] + array[right]; 20 | if (curSum == sum) { 21 | leftList.add(left); 22 | rightList.add(right); 23 | left++; 24 | right--; 25 | isFound = true; 26 | } else if (curSum < sum) { 27 | left++; 28 | } else { 29 | right--; 30 | } 31 | } 32 | if (!isFound) return res; 33 | 34 | int min = Integer.MAX_VALUE; 35 | int minLeft = -1; 36 | int minRight = -1; 37 | for (int i = 0; i < leftList.size(); i++) { 38 | int tmp = array[leftList.get(i)] * array[rightList.get(i)]; 39 | if (tmp < min) { 40 | min = tmp; // 注意修改min的值 41 | minLeft = leftList.get(i); 42 | minRight = rightList.get(i); 43 | } 44 | } 45 | 46 | if (minLeft != -1) { 47 | res.add(array[minLeft]); 48 | res.add(array[minRight]); 49 | } 50 | 51 | return res; 52 | } 53 | 54 | @Test 55 | public void test() { 56 | int[] array = new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; 57 | ArrayList res = FindNumbersWithSum(array, -1); 58 | for (Integer i : res) { 59 | System.out.println(i); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_58_ROL.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_58_ROL { 6 | public String LeftRotateString(String str,int n) { 7 | if (str == null || str.length() <= 0 || n < 0 || n > str.length()) { 8 | return ""; 9 | } 10 | 11 | char[] chars = str.toCharArray(); 12 | 13 | reverse(chars, 0, n-1); 14 | reverse(chars, n, chars.length-1); 15 | reverse(chars, 0, chars.length-1); 16 | 17 | return String.valueOf(chars); 18 | } 19 | 20 | private void reverse(char[] chars, int start, int end) { 21 | for (int i = start, j = end; i <= j; i++, j--) { 22 | char temp = chars[i]; 23 | chars[i] = chars[j]; 24 | chars[j] = temp; 25 | } 26 | } 27 | 28 | @Test 29 | public void test() { 30 | String str = "abcXYZdef"; 31 | System.out.println(LeftRotateString(str, 3)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_58_ReverseSentence.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_58_ReverseSentence { 6 | public String ReverseSentence(String str) { 7 | // 边界条件1:str == null or str = "" 8 | if (str == null || str.length() <= 0) { 9 | return ""; 10 | } 11 | 12 | // 注意这里:String是不可变的,因此我们需要将String转换为char[] 13 | char[] chars = str.toCharArray(); 14 | reverse(chars, 0, chars.length-1); 15 | 16 | int start = 0; // 指向单词的开头 17 | while (start < chars.length && chars[start] == ' ') { 18 | start++; // 排除开头的' ' 19 | } 20 | 21 | // 边界条件2:str = " " (全部都是' ') 22 | if (start == chars.length) { 23 | return str; 24 | } 25 | 26 | // start 和 end像是在接力 27 | for (int end = start; end < chars.length; end++) { 28 | if (chars[end] == ' ') { 29 | reverse(chars, start, --end); 30 | end += 2; 31 | start = end; 32 | } 33 | } 34 | 35 | reverse(chars, start, chars.length-1); 36 | 37 | return String.valueOf(chars); 38 | } 39 | 40 | private void reverse(char[] chars, int start, int end) { 41 | for (int i = start, j = end; i <= j; i++, j--) { 42 | char temp = chars[i]; 43 | chars[i] = chars[j]; 44 | chars[j] = temp; 45 | } 46 | } 47 | 48 | 49 | @Test 50 | public void test() { 51 | String str = "I am a student."; 52 | String str1 = " "; 53 | System.out.println(ReverseSentence(str)); 54 | //System.out.println(ReverseSentence(str1)); 55 | System.out.println(str1.length()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_59_MaxNumOfSlidingWindow.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | 8 | public class Ex_59_MaxNumOfSlidingWindow { 9 | public ArrayList maxInWindows(int [] num, int size) 10 | { 11 | ArrayList res = new ArrayList<>(); 12 | 13 | if (num == null || num.length <= 0 || size <= 0 || size > num.length) { 14 | return res; 15 | } 16 | 17 | LinkedList qMax = new LinkedList<>(); // 双端队列:左端更新max,右端添加数据 18 | 19 | int left = 0; 20 | 21 | for (int right = 0; right < num.length; right++) { 22 | // 更新右端数据 23 | while (!qMax.isEmpty() && num[qMax.peekLast()] <= num[right]) { 24 | qMax.pollLast(); 25 | } 26 | 27 | qMax.addLast(right); 28 | 29 | // 更新max:如果max的索引不在窗口内,则更新 30 | if (qMax.peekFirst() == right - size) { 31 | qMax.pollFirst(); 32 | } 33 | 34 | // 待窗口达到size,输出max 35 | if (right >= size-1) { 36 | res.add(num[qMax.peekFirst()]); 37 | left++; 38 | } 39 | } 40 | 41 | return res; 42 | } 43 | 44 | @Test 45 | public void test() { 46 | int[] num = new int[] {2,3,4,2,6,2,5,1}; 47 | int size = 3; 48 | ArrayList list = maxInWindows(num, size); 49 | for (Integer i : list) { 50 | System.out.print(i + " "); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_59_QueueWithMax.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.LinkedList; 6 | 7 | public class Ex_59_QueueWithMax { 8 | private LinkedList data = new LinkedList<>(); 9 | private LinkedList qMax = new LinkedList<>(); 10 | 11 | public void push_back(Integer x) { 12 | 13 | if (!qMax.isEmpty() && qMax.peekLast() > x) { 14 | qMax.addLast(qMax.peek()); 15 | } 16 | 17 | qMax.addLast(x); 18 | data.addLast(x); 19 | } 20 | 21 | public Integer pop_front() { 22 | if (!data.isEmpty()) { 23 | qMax.pollFirst(); 24 | return data.pollFirst(); 25 | } 26 | 27 | return null; 28 | } 29 | 30 | public Integer max() { 31 | if (!qMax.isEmpty()) { 32 | return qMax.peekFirst(); 33 | } 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_60_ProbabilityOfS.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | // https://www.cnblogs.com/keedor/p/4474471.html 6 | // https://www.cnblogs.com/AndyJee/p/4686208.html 7 | public class Ex_60_ProbabilityOfS { 8 | private static final int MAX_VALUE = 6; // 骰子的最大点数 9 | 10 | // probability(n, currentLeft, currentSum, sum) 11 | public void printProbability_1(int number) { 12 | if (number < 1) { 13 | return; 14 | } 15 | 16 | int maxSum = number * MAX_VALUE; 17 | int[] sums = new int[maxSum-number + 1]; 18 | 19 | for (int i = 0; i < sums.length; i++) { 20 | sums[i] = 0; 21 | } 22 | 23 | probability(number, sums); 24 | 25 | double total = Math.pow(MAX_VALUE, number); 26 | for (int i = 0; i < sums.length; i++) { 27 | System.out.println(sums[i]/total); 28 | } 29 | } 30 | 31 | private void probability(int number, int[] sums) { 32 | for(int i = 1; i <= MAX_VALUE; i++) { 33 | probability(number, number - 1, i, sums); 34 | } 35 | } 36 | 37 | /** 38 | * @param number : 总共几个骰子 39 | * @param current:现在剩下几个骰子 40 | * @param sum:现在已有的和 41 | * @param sums 42 | */ 43 | private void probability(int number, int current, int sum, int[] sums) { 44 | if (current == 0) { 45 | sums[sum - number]++; 46 | return; 47 | } 48 | for (int i = 1; i <= MAX_VALUE; i++) { 49 | probability(number, current-1, sum + i, sums); 50 | } 51 | } 52 | 53 | /** 54 | * 55 | * k:骰子个数 56 | * n:点数和 57 | * f(k, n) = f(k-1, n-1) + f(k-1, n-2) + f(k-1, n-3) + f(k-1, n-4) + f(k-1, n-5) + f(k-1, n-6); 58 | * f(k-1, n-1):表示第k-1个骰子投了n-1点,则第k个骰子投1个点就可以得到n 59 | * f(n) = f(n-1) + f(n-2) + f(n-3) + f(n-4) + f(n-5) + f(n-6) 60 | * @param number 61 | */ 62 | public void printProbability_2(int number) { 63 | if (number < 1) { 64 | return; 65 | } 66 | 67 | /** 68 | * 我们需要将中间值存起来以减少递归过程中的重复计算问题,可以考虑我们用两个数组AB, 69 | * A在B之上得到,B又在A之上再次得到,这样AB互相作为对方的中间值, 70 | * 其实这个思想跟斐波拉契迭代算法中用中间变量保存n-1,n-2的值有异曲同工之妙 71 | */ 72 | int[][] sums = new int[2][MAX_VALUE * number + 1]; // [1,number] 73 | 74 | int flag = 0; 75 | // 抛掷第一枚骰子 [1,2,3,...,MAX_VALUE] 76 | for (int i = 1; i <= MAX_VALUE; i++) { 77 | sums[flag][i] = 1; 78 | } 79 | 80 | // 第二次抛掷骰子开始 81 | for (int k = 2; k <= number; k++) { 82 | // 第k次掷色子,和最小为k,和最大为MAX_VALUE * k 83 | for (int i = k; i <= MAX_VALUE * k; i++) { 84 | int temp = 0; 85 | for (int j = 1; j <= i && j <= MAX_VALUE; j++) { // j<=i,防止数组越界 86 | temp += sums[flag][i-j]; 87 | } 88 | sums[1-flag][i] = temp; 89 | } 90 | flag = 1- flag; 91 | } 92 | 93 | double total = Math.pow(MAX_VALUE, number); 94 | for (int i = number; i < sums[flag].length; i++) { 95 | System.out.println(sums[flag][i]/total); 96 | } 97 | } 98 | 99 | @Test 100 | public void test1() { 101 | printProbability_1(2); 102 | System.out.println(); 103 | } 104 | 105 | @Test 106 | public void test2() { 107 | printProbability_2(2); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_61_ContinuousSequence.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import java.util.Arrays; 4 | 5 | public class Ex_61_ContinuousSequence { 6 | public boolean isContinuous(int [] numbers) { 7 | if (numbers == null || numbers.length < 5) { 8 | return false; 9 | } 10 | 11 | Arrays.sort(numbers); 12 | 13 | int numberOfZero = 0; 14 | int gap = 0; 15 | 16 | for (int i = 0; i < numbers.length && numbers[i] == 0; i++) { 17 | numberOfZero++; 18 | } 19 | 20 | int small = numberOfZero; // 0之后的第一位索引 21 | int big = small + 1; 22 | 23 | while (big < numbers.length) { 24 | if (numbers[small] == numbers[big]) { 25 | return false; 26 | } 27 | 28 | gap += numbers[big] - numbers[small] - 1; 29 | small = big; 30 | big++; 31 | } 32 | 33 | return gap > numberOfZero ? false : true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_62_Josephus.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | import java.util.ArrayList; 6 | 7 | // 约瑟夫问题其实是一个环型链表 8 | // 假设 n > m, 则第一个要删除的位置是 index = m-1, 第二个是 (index + m) % size 9 | // 每次要删除的位置是 (lastIndex + m) % size; 10 | public class Ex_62_Josephus { 11 | public int LastRemaining_Solution(int n, int m) { 12 | if (n <= 0 || m <= 0) { 13 | return -1; 14 | } 15 | 16 | ArrayList list = new ArrayList<>(); 17 | 18 | for (int i = 0; i < n; i++) { 19 | list.add(i); 20 | } 21 | 22 | int index = -1; 23 | 24 | while (list.size() > 1) { 25 | index = (index + m) % list.size(); 26 | list.remove(index); 27 | index--; 28 | } 29 | 30 | return list.get(0); 31 | } 32 | 33 | /** 34 | * f(n, m) = [f(n-1, m) + m] % n (n > 1) 35 | * 36 | * @param n 37 | * @param m 38 | * @return 39 | */ 40 | public int LastRemaining_Solution1(int n, int m) { 41 | if (n <= 0 || m <= 0) { 42 | return -1; 43 | } 44 | 45 | int lastRemain = 0; 46 | for (int i = 2; i <= n; i++) { 47 | lastRemain = (lastRemain + m) % i; 48 | } 49 | return lastRemain; 50 | } 51 | @Test 52 | public void test() { 53 | System.out.println(LastRemaining_Solution(5, 3)); 54 | System.out.println(LastRemaining_Solution1(5, 3)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_63_MaxProfits.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | // 此题目类似于Ex_42_MaxSumOfSubArray 6 | public class Ex_63_MaxProfits { 7 | public int maxProfits(int[] prices) { 8 | if (prices == null || prices.length < 2) { 9 | return -1; 10 | } 11 | 12 | int minPrice = prices[0]; // i之前[0,i-1]的最小值,控制左侧 13 | int maxDiff = prices[1] - minPrice; // 控制右侧,遍历了所有可能最大差值 14 | 15 | for (int i = 2; i < prices.length; i++) { 16 | int curDiff = prices[i] - minPrice; 17 | 18 | if (curDiff > maxDiff) { 19 | maxDiff = curDiff; 20 | } 21 | 22 | if (prices[i] < minPrice) { 23 | minPrice = prices[i]; 24 | } 25 | } 26 | 27 | return maxDiff; 28 | } 29 | 30 | @Test 31 | public void test() { 32 | int[] prices = new int[] {9,11,8,5,7,12,16,14}; 33 | System.out.println(maxProfits(prices)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_64_SumFrom1ToN.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_64_SumFrom1ToN { 6 | public int Sum_Solution(int n) { 7 | int sum = n; 8 | boolean stop = (n > 0) && ((sum += Sum_Solution(n-1)) > 1); 9 | return sum; 10 | } 11 | 12 | @Test 13 | public void test() { 14 | System.out.println(Sum_Solution(10)); 15 | } 16 | 17 | } 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_65_AddWithoutCarry.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_65_AddWithoutCarry { 4 | public int Add(int num1,int num2) { 5 | int sum = 0; 6 | int carry = 0; 7 | do { 8 | sum = num1 ^ num2; //不进位加法(不断执行不进位加法,直到进位为0,则不进位加法=进位加法) 9 | carry = (num1 & num2) << 1; 10 | 11 | num1 = sum; 12 | num2 = carry; 13 | } while (num2 != 0); 14 | 15 | return sum; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_65_SwapNumWithoutTemp.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_65_SwapNumWithoutTemp { 4 | public int[] swap1 (int a, int b) { 5 | int[] res = new int[2]; 6 | //================================= 7 | a = a + b; 8 | b = a - b; // b = (a + b) - b 9 | a = a - b; // a = (a + b) - a 10 | //================================= 11 | res[0] = a; 12 | res[1] = b; 13 | return res; 14 | } 15 | 16 | public int[] swap2 (int a, int b) { 17 | int[] res = new int[2]; 18 | 19 | //================================= 20 | a = a ^ b; 21 | b = a ^ b; // b = (a ^ b) ^ b = a ^ (b ^ b) = a ^ 0 = a 22 | a = a ^ b; 23 | //================================= 24 | res[0] = a; 25 | res[1] = b; 26 | return res; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_66_ConstructMultiplyArray.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_66_ConstructMultiplyArray { 4 | public int[] multiply(int[] A) { 5 | int[] res = new int[A.length]; 6 | if (A == null || A.length < 2) { 7 | return res; 8 | } 9 | 10 | int[] C = new int[A.length]; 11 | int[] D = new int[A.length]; 12 | C[0] = 1; 13 | D[D.length-1] = 1; 14 | 15 | for (int i = 1; i < C.length; i++) { 16 | C[i] = C[i-1] * A[i-1]; 17 | } 18 | 19 | for (int i = D.length-2; i >= 0; i--) { 20 | D[i] = D[i+1] * A[i+1]; 21 | } 22 | 23 | for (int i = 0; i < res.length; i++) { 24 | res[i] = C[i] * D[i]; 25 | } 26 | 27 | return res; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_67_StringToInt.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | import org.junit.Test; 4 | 5 | public class Ex_67_StringToInt { 6 | /** 7 | * 说明:当输入不合法时,返回0。但是由于正常输出也可能有0, 8 | * 因此需要设置全局变量isValid标记返回的0是因为输入不合法返回 9 | * 10 | * @param str 11 | * @return 12 | */ 13 | public int StrToInt(String str) { 14 | boolean isValid = true; 15 | // 边界1:str = null 16 | // 边界2:str = "" 17 | if (str == null || str == "") { 18 | isValid = false; 19 | return 0; 20 | } 21 | 22 | int number = 0; 23 | boolean minus = false; 24 | 25 | for (int i = 0; i < str.length(); i++) { 26 | char c = str.charAt(i); 27 | 28 | if (i == 0) { 29 | if (c == '+') continue; 30 | if (c == '-') { 31 | minus = true; 32 | continue; 33 | } 34 | } 35 | 36 | // 边界3:输入存在非法字符 37 | // [0,1,2,...,9]的ASII码[48,49,...,57] 38 | // a = 97 39 | // A = 65 40 | // x = (char)x - '0' (char -> int) 41 | if (c < 48 || c > 57) { 42 | isValid = false; 43 | return 0; 44 | } 45 | number = number * 10 + (c - '0'); 46 | } 47 | 48 | return minus ? -1 * number : number; 49 | } 50 | 51 | @Test 52 | public void test() { 53 | String str1 = null; 54 | String str2 = ""; // str2 = " "; 55 | String str3 = "1234"; 56 | String str4 = "+1234"; 57 | String str5 = "-1234"; 58 | String str6 = "123a5"; 59 | 60 | System.out.println(StrToInt(str1)); 61 | System.out.println(StrToInt(str2)); 62 | System.out.println(StrToInt(str3)); 63 | System.out.println(StrToInt(str4)); 64 | System.out.println(StrToInt(str5)); 65 | System.out.println(StrToInt(str6)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Ex_68_LowestCommonAncestor.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | public class Ex_68_LowestCommonAncestor { 4 | // case1: 二叉树(二叉搜索树) 5 | public TreeNode commonAncestor(TreeNode root, TreeNode node1, TreeNode node2) { 6 | if (root == null) { 7 | return null; 8 | } 9 | 10 | return null; 11 | } 12 | 13 | // case2: 不是二叉树,但是存在指向父节点的指针 14 | 15 | // case3: 不是二叉树,不存在指向父节点的指针 16 | } 17 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/ListNode.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 单链表节点 5 | */ 6 | 7 | public class ListNode { 8 | int val; 9 | ListNode next; 10 | 11 | public ListNode(int val) { 12 | this.val = val; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/Node.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 单链表节点 5 | */ 6 | public class Node { 7 | int val; 8 | Node next; 9 | 10 | Node (int val) { 11 | this.val = val; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/RandomListNode.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 含有指向随机节点指针的单链表节点 5 | */ 6 | public class RandomListNode { 7 | int label; 8 | RandomListNode next = null; 9 | RandomListNode random = null; 10 | 11 | RandomListNode(int label) { 12 | this.label = label; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/TreeLinkNode.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 含有指向父节点指针的二叉树节点 5 | * Ex_08_GetNextNodeInBT 6 | */ 7 | public class TreeLinkNode { 8 | int val; 9 | TreeLinkNode left = null; 10 | TreeLinkNode right = null; 11 | TreeLinkNode parent = null; 12 | 13 | TreeLinkNode(int val) { 14 | this.val = val; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /offer/src/com/ex/offer/TreeNode.java: -------------------------------------------------------------------------------- 1 | package com.ex.offer; 2 | 3 | /** 4 | * 二叉树节点 5 | */ 6 | public class TreeNode { 7 | int val; 8 | TreeNode left; 9 | TreeNode right; 10 | 11 | TreeNode(int x) { 12 | this.val = x; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /offer/src/com/ex/singleton/Singleton1.java: -------------------------------------------------------------------------------- 1 | package com.ex.singleton; 2 | 3 | // V1.0: 饿汉式 4 | public class Singleton1 { 5 | // instance必须是static变量(类变量) 6 | private static Singleton1 instance = new Singleton1(); 7 | 8 | // private无参构造函数: Java会自动为没有明确声明构造函数的类, 9 | // 定义一个public的无参构造函数,若没有这个private无参构造函数, 10 | // 外部可以随意new Singleton 11 | private Singleton1() {} 12 | 13 | // getInstance必须是static方法(类方法) 14 | public static Singleton1 getInstance() { 15 | return instance; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /offer/src/com/ex/singleton/Singleton2.java: -------------------------------------------------------------------------------- 1 | package com.ex.singleton; 2 | 3 | // V2.0: 懒汉式 4 | public class Singleton2 { 5 | private static Singleton2 instance = null; 6 | 7 | private Singleton2() {} 8 | 9 | public static Singleton2 getInstance() { 10 | if (instance == null) { 11 | instance = new Singleton2(); 12 | } 13 | 14 | return instance; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /offer/src/com/ex/singleton/Singleton3.java: -------------------------------------------------------------------------------- 1 | package com.ex.singleton; 2 | 3 | // V3.0: 双重校验 4 | public class Singleton3 { 5 | // volatile提供可见性(工作内存的值能立即在主内存中可见), 6 | // 保证getInstance返回的是初始化完全的对象 7 | private static volatile Singleton3 instance = null; 8 | 9 | private Singleton3() {} 10 | 11 | public static Singleton3 getInstance() { 12 | // 同步之前进行null检查,避免进入代价相对昂贵的同步块 13 | if (instance == null) { 14 | synchronized (Singleton3.class) { 15 | // 持有锁之后进行null检查,避免上一个线程已经初始化变量 16 | if (instance == null) { 17 | instance = new Singleton3(); 18 | } 19 | } 20 | } 21 | return instance; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /offer/src/com/ex/singleton/Singleton4.java: -------------------------------------------------------------------------------- 1 | package com.ex.singleton; 2 | 3 | // V4.0: 静态内部类 4 | public class Singleton4 { 5 | private static class SingletonHolder { 6 | public static Singleton4 instance = new Singleton4(); 7 | } 8 | 9 | public static Singleton4 getInstance() { 10 | return SingletonHolder.instance; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /offer/src/com/ex/singleton/Singleton5.java: -------------------------------------------------------------------------------- 1 | package com.ex.singleton; 2 | 3 | // V5.0: 枚举方法 4 | public enum Singleton5 { 5 | INSTANCE; 6 | 7 | private int id; 8 | 9 | public int getId() { 10 | return id; 11 | } 12 | 13 | public void setId(int id) { 14 | this.id = id; 15 | } 16 | 17 | public static void main(String[] args) { 18 | //调用 19 | Singleton5.INSTANCE.setId(1); 20 | Singleton5.INSTANCE.getId(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /offer/src/com/ex/singleton/singleton.md: -------------------------------------------------------------------------------- 1 | # 单例模式 2 | 3 | ## 单例模式的好处 4 | 单例模式适用于应用中频繁创建的对象,尤其是频繁创建的重量级对象。 5 | 例如统一的配置文件。 6 | 使用单例模式能够提升性能,减小内存开销。 7 | 8 | ## 单例模式的实现 9 | ### 1.饿汉式 10 | 饿汉式加载类的时候,就会创建类的实例对象,那么如果不用这个单例的话,就会消耗内存,浪费性能。 11 | 因此,需要懒加载(lazy-load) 12 | 13 | ### 2.懒汉式 14 | 懒汉式改进了饿汉式的性能问题,但是又带来了一个问题,即线程安全问题。 15 | 在多线程的情况下,会出现多个实例,违背了单例模式的原则。 16 | 17 | ### 3.双重校验(双检锁) 18 | 双重校验能够保证单例模式的实例唯一性,同时能够兼顾效率和线程安全。 19 | 20 | ### 4.静态内部类 21 | 静态内部类的方式实现,可以保证多线程对象的唯一性,同时可以降低双重校验中同步锁机制的代价。 22 | 这种方式还有个好处,就是静态内部类不会在单例类加载的时候就加载,而是在调用`getInstance()` 23 | 方法时才加载。 24 | 25 | ### 5.枚举方法 by Josh Bloch (《Effective Java》作者) 26 | 好处: 27 | (1)自由序列化 28 | (2)保证只有一个实例 29 | (3)线程安全 30 | -------------------------------------------------------------------------------- /pictures/algo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guokaide/algorithm/9bee14b08b06ddb64155abc720cc135167671ca5/pictures/algo.jpg -------------------------------------------------------------------------------- /practice/Final.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | 时间过得很快,不知不觉间,一切就结束了。 4 | 5 | 无论课程多么精彩,似乎精彩总是他们的,我什么都没有。无论如何,感谢各位工作人员的辛勤付出。 6 | 7 | 很多课程都没来得及消化和理解,后续仍然需要进一步的学习、总结、实践。 8 | 9 | 复习总结列表: 10 | 11 | 1. [《第一课 数组、链表、栈、队列 * 》](https://shimo.im/docs/RCdRgwWjVWJppyJj/ ) 12 | 2. [《第二课 前缀和、差分、双指针、单调栈、单调队列》](https://shimo.im/docs/HvwKPhKHk9dcH9Q6/ ) 13 | 3. To be continued ... 14 | 15 | -------------------------------------------------------------------------------- /practice/README.md: -------------------------------------------------------------------------------- 1 | # Practice 2 | 3 | -------------------------------------------------------------------------------- /practice/src/io/gkd/ListNode.java: -------------------------------------------------------------------------------- 1 | package io.gkd; 2 | 3 | public class ListNode { 4 | public int val; 5 | public ListNode next; 6 | 7 | public ListNode() { 8 | } 9 | 10 | public ListNode(int val) { 11 | this.val = val; 12 | } 13 | 14 | public ListNode(int val, ListNode next) { 15 | this.val = val; 16 | this.next = next; 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /practice/src/io/gkd/Node.java: -------------------------------------------------------------------------------- 1 | package io.gkd; 2 | 3 | import java.util.List; 4 | 5 | public class Node { 6 | public int val; 7 | public List children; 8 | 9 | public Node() {} 10 | 11 | public Node(int _val) { 12 | val = _val; 13 | } 14 | 15 | public Node(int _val, List _children) { 16 | val = _val; 17 | children = _children; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /practice/src/io/gkd/TreeNode.java: -------------------------------------------------------------------------------- 1 | package io.gkd; 2 | 3 | public class TreeNode { 4 | public int val; 5 | public TreeNode left; 6 | public TreeNode right; 7 | 8 | public TreeNode() {} 9 | 10 | public TreeNode(int val) { 11 | this.val = val; 12 | } 13 | 14 | public TreeNode(int val, TreeNode left, TreeNode right) { 15 | this.val = val; 16 | this.left = left; 17 | this.right = right; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture04/Lc077_Combine.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture04; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Lc077_Combine { 7 | 8 | public List> combine(int n, int k) { 9 | this.n = n; 10 | this.k = k; 11 | findSubsets(1); 12 | return ans; 13 | } 14 | 15 | private void findSubsets(int index) { 16 | // 剪枝:选的数大于 k 个,或者剩下的全部选了也不够 k 个,就可以直接退出了 17 | if (subset.size() > k || subset.size() + n - index + 1 < k) return; 18 | if (index == n + 1) { 19 | ans.add(new ArrayList<>(subset)); // make a copy 20 | return; 21 | } 22 | findSubsets(index + 1); 23 | subset.add(index); 24 | findSubsets(index + 1); 25 | subset.remove(subset.size() - 1); 26 | } 27 | 28 | private List> ans = new ArrayList<>(); 29 | private List subset = new ArrayList<>(); 30 | private int n; 31 | private int k; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture04/Lc078_SubSets.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture04; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Medium 8 | * 78. https://leetcode-cn.com/problems/subsets/submissions/ 9 | */ 10 | public class Lc078_SubSets { 11 | 12 | public List> subsets(int[] nums) { 13 | findSubsets(nums, 0); 14 | return ans; 15 | } 16 | 17 | // 递归去枚举 nums[0], nums[1], nums[2], ..., nums[n-1] 这 n 个数选或者不选 18 | private void findSubsets(int[] nums, int index) { 19 | if (index == nums.length) { 20 | ans.add(new ArrayList<>(subset)); // make a copy 21 | return; 22 | } 23 | // 不选 index 位置的数 24 | findSubsets(nums, index + 1); 25 | subset.add(nums[index]); 26 | // 选 index 位置的数 27 | findSubsets(nums, index + 1); 28 | // 恢复现场,防止一次递归结束,subset 被上一次递归污染 29 | subset.remove(subset.size() - 1); 30 | } 31 | 32 | private List> ans = new ArrayList<>(); 33 | private List subset = new ArrayList<>(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture05/Lc094_InOrderTraversal.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture05; 2 | 3 | import io.gkd.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class Lc094_InOrderTraversal { 9 | 10 | private List list = new ArrayList<>(); 11 | 12 | public List inorderTraversal(TreeNode root) { 13 | find(root); 14 | return list; 15 | } 16 | 17 | public void find(TreeNode root) { 18 | if (root == null) return; 19 | find(root.left); 20 | list.add(root.val); 21 | find(root.right); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture05/Lc105_BuildTree.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture05; 2 | 3 | import io.gkd.TreeNode; 4 | 5 | /** 6 | * Medium 7 | * 105. https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ 8 | * 9 | * preorder [3 | 9 | 20 15 7] 找到了 root, 但是不确定左右子树的大小 [l1, r1] 10 | * inorder [9 | 3 | 15 20 7] 知道 root,自然知道了左右子树的大小 [l2, r2]. 左子树大小 = mid - l2 11 | * l2 mid r2 12 | * 13 | * 3 14 | * / \ 15 | * [9] [20 15 7] preorer 16 | * [9] [15 20 7] inorer 17 | * left right 18 | */ 19 | public class Lc105_BuildTree { 20 | public TreeNode buildTree(int[] preorder, int[] inorder) { 21 | return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1); 22 | } 23 | 24 | private TreeNode build(int[] preorder, int l1, int r1, int[] inorder, int l2, int r2) { 25 | if (l1 > r1) return null; 26 | TreeNode root = new TreeNode(preorder[l1]); 27 | // 通过找到 root 在 inorder 中的位置,确定左右子树的大小 28 | int mid = l2; 29 | while (inorder[mid] != root.val) mid++; 30 | int leftSize = mid - l2; 31 | root.left = build(preorder, l1 + 1, l1 + leftSize, inorder, l2, mid - 1); 32 | root.right = build(preorder, l1 + leftSize + 1, r1, inorder, mid + 1, r2); 33 | return root; 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture05/Lc236_LCA.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture05; 2 | 3 | import io.gkd.TreeNode; 4 | 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | /** 11 | * Medium 12 | * 236.https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ 13 | * 14 | * 向上标记法 15 | */ 16 | public class Lc236_LCA { 17 | 18 | // 存储每个节点的 father 19 | private Map father; 20 | 21 | // Time: O(n) 22 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 23 | this.father = new HashMap<>(); // TreeNode.val -> root TreeNode 24 | calcFather(root); 25 | // 存储其中一个节点的所有祖先 26 | Set redNodes = new HashSet<>(); 27 | redNodes.add(root); 28 | // 记录从 p 向上的所有祖先,标记为红色 29 | while(p != root) { 30 | redNodes.add(p); 31 | p = father.get(p.val); 32 | } 33 | // 在 p 的祖先中找到距离 q 最近的祖先,即 q 向上走,走到距离最近的一个红点 34 | while (!redNodes.contains(q)) { 35 | q = father.get(q.val); 36 | } 37 | return q; 38 | } 39 | 40 | // 深度优先遍历记录每个节点的父节点 41 | private void calcFather(TreeNode root) { 42 | if (root == null) return; 43 | if (root.left != null) { 44 | father.put(root.left.val, root); 45 | calcFather(root.left); 46 | } 47 | if (root.right != null) { 48 | father.put(root.right.val, root); 49 | calcFather(root.right); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture05/Lc297_Codec.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture05; 2 | 3 | import io.gkd.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * Hard 11 | * 297. https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/ 12 | */ 13 | public class Lc297_Codec { 14 | 15 | // deserialized string list 16 | private List seq = new ArrayList<>(); 17 | // deserialized string list pointer 18 | private int curr; 19 | 20 | // Encodes a tree to a single string. 21 | // 1 2 null null 3 4 null null 5 null null 22 | public String serialize(TreeNode root) { 23 | traverse(root); 24 | return String.join(" ", seq); 25 | } 26 | 27 | // Decodes your encoded data to tree. 28 | public TreeNode deserialize(String data) { 29 | seq = Arrays.asList(data.split(" ")); 30 | curr = 0; 31 | return calc(); 32 | } 33 | 34 | private TreeNode calc() { 35 | if (seq.get(curr).equals("null")) { 36 | curr++; 37 | return null; 38 | } 39 | TreeNode root = new TreeNode(Integer.parseInt(seq.get(curr))); 40 | curr++; 41 | root.left = calc(); 42 | root.right = calc(); 43 | return root; 44 | } 45 | 46 | private void traverse(TreeNode root) { 47 | // for judge leaf node 48 | if (root == null) { 49 | seq.add("null"); 50 | return; 51 | } 52 | seq.add(Integer.toString(root.val)); 53 | traverse(root.left); 54 | traverse(root.right); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture05/Lc429_LevelOrderNTree.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture05; 2 | 3 | import io.gkd.Node; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | import java.util.Queue; 9 | 10 | /** 11 | * Medium 12 | * 429. https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/ 13 | */ 14 | public class Lc429_LevelOrderNTree { 15 | 16 | public List> levelOrder(Node root) { 17 | // result: [[1], [3, 2, 4], [5, 6]] 18 | List> result = new ArrayList<>(); 19 | if (root == null) return result; 20 | // Queue: Node - depth 21 | Queue> q = new LinkedList<>(); 22 | // Put root in Queue 23 | q.add(new Pair(root, 0)); 24 | while (!q.isEmpty()) { 25 | Pair pair = q.poll(); 26 | Node node = pair.getKey(); 27 | int depth = pair.getValue(); 28 | // initialize a list in every depth(0...) 29 | if (result.size() <= depth) { 30 | result.add(new ArrayList()); 31 | } 32 | result.get(depth).add(node.val); 33 | for (Node child : node.children) { 34 | q.add(new Pair<>(child, depth + 1)); 35 | } 36 | } 37 | return result; 38 | } 39 | 40 | static class Pair { 41 | 42 | public K key; 43 | public V value; 44 | 45 | public Pair(K key, V value) { 46 | this.key = key; 47 | this.value = value; 48 | } 49 | 50 | public K getKey() { 51 | return key; 52 | } 53 | 54 | public V getValue() { 55 | return value; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /practice/src/io/gkd/lectures/lecture05/Lc589_PreOrderNTree.java: -------------------------------------------------------------------------------- 1 | package io.gkd.lectures.lecture05; 2 | 3 | import io.gkd.Node; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Stack; 8 | 9 | /** 10 | * Easy 11 | * 589. https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/ 12 | */ 13 | public class Lc589_PreOrderNTree { 14 | private List list = new ArrayList<>(); 15 | 16 | public List preorder(Node root) { 17 | find(root); 18 | return list; 19 | } 20 | 21 | private void find(Node root) { 22 | if (root == null) return; 23 | list.add(root.val); 24 | for (Node node : root.children) { 25 | find(node); 26 | } 27 | } 28 | 29 | public List preorderIter(Node root) { 30 | List list = new ArrayList<>(); 31 | if (root == null) return list; 32 | Stack stack = new Stack<>(); 33 | stack.push(root); 34 | while(!stack.isEmpty()) { 35 | Node r = stack.pop(); 36 | list.add(r.val); 37 | List children = r.children; 38 | for (int i = children.size() - 1; i >= 0; i--) { 39 | stack.push(children.get(i)); 40 | } 41 | } 42 | return list; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /practice/src/io/gkd/week01/Lc021_MergeTwoLists.java: -------------------------------------------------------------------------------- 1 | package io.gkd.week01; 2 | 3 | import io.gkd.ListNode; 4 | 5 | /** 6 | * Easy 7 | * 21. https://leetcode-cn.com/problems/merge-two-sorted-lists/ 8 | */ 9 | public class Lc021_MergeTwoLists { 10 | 11 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 12 | ListNode sentinel = new ListNode(); 13 | ListNode cur = sentinel; 14 | while (l1 != null && l2 != null) { 15 | if (l1.val <= l2.val) { 16 | cur.next = l1; 17 | l1 = l1.next; 18 | } else { 19 | cur.next = l2; 20 | l2 = l2.next; 21 | } 22 | cur = cur.next; 23 | } 24 | if (l1 != null) { 25 | cur.next = l1; 26 | } else { 27 | cur.next = l2; 28 | } 29 | return sentinel.next; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /practice/src/io/gkd/week01/Lc066_PlusOne.java: -------------------------------------------------------------------------------- 1 | package io.gkd.week01; 2 | 3 | /** 4 | * Easy 5 | * 66. https://leetcode-cn.com/problems/plus-one/submissions/ 6 | */ 7 | public class Lc066_PlusOne { 8 | 9 | public int[] plusOne(int[] digits) { 10 | for (int i = digits.length - 1; i >= 0; i--) { 11 | digits[i] = (digits[i] + 1) % 10; 12 | if (digits[i] != 0) { 13 | return digits; 14 | } 15 | } 16 | int[] res = new int[digits.length + 1]; 17 | res[0] = 1; 18 | return res; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /practice/src/io/gkd/week02/Lc146_LRUCache.java: -------------------------------------------------------------------------------- 1 | package io.gkd.week02; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * Medium 7 | * 146. https://leetcode-cn.com/problems/lru-cache/ 8 | * Time: put、get: O(1) 9 | * Space: O(capacity) 10 | */ 11 | public class Lc146_LRUCache { 12 | // key - Node 13 | HashMap cache; 14 | int capacity; 15 | // sentinel head 16 | Node head; 17 | // sentinel tail 18 | Node tail; 19 | 20 | public Lc146_LRUCache(int capacity) { 21 | this.capacity = capacity; 22 | this.cache = new HashMap<>(); 23 | this.head = new Node(); 24 | this.tail = new Node(); 25 | // Doubly Linked List: head - tail 26 | this.head.next = this.tail; 27 | this.tail.pre = this.head; 28 | } 29 | 30 | public int get(int key) { 31 | Node node = this.cache.get(key); 32 | if (node == null) { 33 | return -1; 34 | } 35 | removeNode(node); 36 | addToHead(node); 37 | return node.val; 38 | } 39 | 40 | // head -> latest -> ... -> oldest -> tail 41 | // head -> 1 -> 2 -> tail 42 | public void put(int key, int value) { 43 | if (cache.containsKey(key)) { 44 | removeNode(cache.get(key)); 45 | } 46 | Node node = new Node(key, value); 47 | addToHead(node); 48 | this.cache.put(key, node); 49 | if (this.cache.size() > capacity) { 50 | Node oldestNode = tail.pre; 51 | removeNode(oldestNode); 52 | this.cache.remove(oldestNode.key); 53 | } 54 | } 55 | 56 | // O(1) 57 | private void addToHead(Node node) { 58 | // node - head.next 59 | node.next = this.head.next; 60 | this.head.next.pre = node; 61 | // head - node 62 | node.pre = this.head; 63 | this.head.next = node; 64 | } 65 | 66 | // O(1) 67 | private void removeNode(Node node) { 68 | node.pre.next = node.next; 69 | node.next.pre = node.pre; 70 | } 71 | 72 | static class Node { 73 | public int key; 74 | public int val; 75 | public Node pre; 76 | public Node next; 77 | 78 | public Node() {} 79 | 80 | public Node(int key, int val) { 81 | this.key = key; 82 | this.val = val; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /practice/src/io/gkd/week02/Lc697_FindShortestSubArray.java: -------------------------------------------------------------------------------- 1 | package io.gkd.week02; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Easy 8 | * 697. https://leetcode-cn.com/problems/degree-of-an-array/ 9 | */ 10 | public class Lc697_FindShortestSubArray { 11 | public int findShortestSubArray(int[] nums) { 12 | // map: 13 | // key - element 14 | // value - value[] 15 | // - value[0]: element count; 16 | // - value[1]: first element index; 17 | // - value[2]: last element index 18 | HashMap map = new HashMap<>(); 19 | int degree = 0; 20 | for (int i = 0; i < nums.length; i++) { 21 | int element = nums[i]; 22 | if (map.containsKey(element)) { 23 | int[] value = map.get(element); 24 | value[0]++; 25 | value[2] = i; 26 | degree = Math.max(degree, value[0]); 27 | } else { 28 | map.put(element, new int[] {1, i, i}); 29 | degree = Math.max(degree, 1); 30 | } 31 | } 32 | // System.out.println(degree); 33 | int shortestSubArrayLen = 50000; 34 | for (Map.Entry entry : map.entrySet()) { 35 | int[] value = entry.getValue(); 36 | if (degree == value[0]) { 37 | shortestSubArrayLen = Math.min(shortestSubArrayLen, value[2] - value[1] + 1); 38 | } 39 | } 40 | return shortestSubArrayLen; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /practice/src/io/gkd/week03/Lc106_BuildTree.java: -------------------------------------------------------------------------------- 1 | package io.gkd.week03; 2 | 3 | import io.gkd.TreeNode; 4 | 5 | /** 6 | * Medium 7 | * 106. https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/ 8 | * 9 | * postorder [9 | 15 7 20 | 3] 10 | * inorder [9 | 3 | 15 20 7] 11 | * l1 mid r1 12 | * 3 13 | * / \ 14 | * [9] [15 7 20] 15 | * [9] [15 20 7] 16 | */ 17 | public class Lc106_BuildTree { 18 | public TreeNode buildTree(int[] inorder, int[] postorder) { 19 | return build(inorder, 0, inorder.length, postorder, 0, postorder.length - 1); 20 | } 21 | 22 | private TreeNode build(int[] inorder, int l1, int r1, int[] postorder, int l2, int r2) { 23 | if (l2 > r2) return null; 24 | TreeNode root = new TreeNode(postorder[r2]); 25 | int mid = l1; 26 | while (inorder[mid] != root.val) mid++; 27 | int leftSize = mid - l1; 28 | root.left = build(inorder, l1, mid - 1, postorder, l2, l2 + leftSize - 1); 29 | root.right = build(inorder, mid + 1, r1, postorder, l2 + leftSize, r2 - 1); 30 | return root; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /practice/src/io/gkd/week03/Lc210_FindOrder2.java: -------------------------------------------------------------------------------- 1 | package io.gkd.week03; 2 | 3 | import java.util.LinkedList; 4 | import java.util.Queue; 5 | 6 | public class Lc210_FindOrder2 { 7 | public int[] findOrder(int numCourses, int[][] prerequisites) { 8 | if (numCourses == 0) return new int[0]; 9 | int[] inDegrees = new int[numCourses]; 10 | // 建立入度表 11 | // 对于有先修课的课程,计算有几门先修课 12 | for (int[] p : prerequisites) { 13 | inDegrees[p[0]]++; 14 | } 15 | // 入度为0的节点队列 16 | Queue queue = new LinkedList<>(); 17 | for (int i = 0; i < inDegrees.length; i++) { 18 | if (inDegrees[i] == 0) queue.offer(i); 19 | } 20 | int count = 0; // 记录可以学完的课程数量 21 | int[] res = new int[numCourses]; // 可以学完的课程 22 | // 根据提供的先修课列表,删除入度为 0 的节点 23 | while (!queue.isEmpty()){ 24 | int curr = queue.poll(); 25 | res[count++] = curr; // 将可以学完的课程加入结果当中 26 | for (int[] p : prerequisites) { 27 | if (p[1] == curr){ 28 | inDegrees[p[0]]--; 29 | if (inDegrees[p[0]] == 0) queue.offer(p[0]); 30 | } 31 | } 32 | } 33 | if (count == numCourses) return res; 34 | return new int[0]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /practice/src/io/gkd/week03/NOTES.md: -------------------------------------------------------------------------------- 1 | # 本周总结 2 | 3 | 本周主要理解了树的相关内容,图的内容还在学习中。 4 | 5 | ## 树 6 | 7 | * 树的定义 8 | * 二叉树 9 | * 完全二叉树 10 | * 满二叉树 11 | * 二(多)叉树的遍历 12 | * 基环树 13 | 14 | ## 图 15 | 16 | * 链表、树、基环树、图的关系 17 | * 图的表示 18 | * 图的遍历 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------