├── 20170505_share_divide_conquer ├── [每日一题]4.pdf ├── code │ ├── 312_Burst_Balloons.java │ ├── 4_Median_Two_Sorted_Arrays.java │ ├── 4_Median_Two_Sorted_Arrays.py │ ├── BinarySearch.java │ ├── Tree_7_02_print.java │ ├── Tree_7_03_noRecursive.java │ ├── Tree_7_05_LevelTraverse.java │ ├── mergeSort_Rec.java │ ├── mergeSort_nonRec.java │ ├── partition.java │ └── quickSort.java ├── readme.md ├── 手写记录01.pdf ├── 手写记录02.pdf └── 手写记录03.pdf ├── LinkedList └── 链表review _ 岁月轻狂.pdf ├── README.md ├── String ├── HashSearch.java ├── KMPMatch.java ├── bfMatch.cpp ├── bfMatch.java └── kmpMatch.cpp ├── UnionFind.java ├── bit_bigdata ├── readme.md └── 海量数据处理 _ 岁月轻狂.pdf ├── nowcoder ├── chap01_intro │ ├── Rotation.java │ └── TreePrinter.java ├── chap02_sort │ ├── BubbleSort.java │ ├── CountingSort.java │ ├── HeapSort.java │ ├── InsertionSort.java │ ├── MergeSort.java │ ├── MergeSortBU.java │ ├── QuickSort.java │ ├── RadixSort.java │ ├── SelectionSort.java │ ├── ShellSort.java │ ├── readme.md │ ├── sort_2_13.java │ ├── sort_2_14.java │ ├── sort_2_15.java │ ├── sort_2_17.java │ ├── sort_2_18.java │ ├── sort_2_19.java │ └── sort_2_20.java ├── chap03_string │ ├── readme.md │ ├── string_3_02.java │ ├── string_3_02_b.java │ ├── string_3_03.java │ ├── string_3_03_best.java │ ├── string_3_05.java │ ├── string_3_06.java │ ├── string_3_07.java │ ├── string_3_08.java │ ├── string_3_10.java │ ├── string_3_11.java │ └── string_3_12.java ├── chap04_stack_queue │ ├── img1.png │ ├── img2.png │ ├── readme.md │ ├── stack_4_02.java │ ├── stack_4_04.java │ ├── stack_4_05.java │ ├── stack_4_06.java │ ├── stack_4_08.java │ └── stack_4_09.java ├── chap05_linkedlist │ ├── list_5_02.java │ ├── list_5_03.java │ ├── list_5_05.java │ ├── list_5_06.java │ ├── list_5_07.java │ ├── list_5_08.java │ ├── list_5_09.java │ ├── list_5_11.java │ ├── list_5_12.java │ ├── list_5_13.java │ ├── list_5_14.java │ ├── list_5_15.java │ └── readme.md ├── chap06_BinarySearch │ ├── BS_6_02_local_minimum.java │ ├── BS_6_03_left.java │ ├── BS_6_04_Min_circle.java │ ├── BS_6_06_left_pos.java │ ├── BS_6_07_Complete_Binary_Tree.java │ ├── BS_Quick_Pow.java │ └── readme.md ├── chap07_BinaryTree │ ├── BST.png │ ├── LongestDistance1.png │ ├── LongestDistance2.png │ ├── Tree_7_02_print.java │ ├── Tree_7_03_noRecursive.java │ ├── Tree_7_05_LevelTraverse.java │ ├── Tree_7_06_serialize.java │ ├── Tree_7_08_Balance.java │ ├── Tree_7_09_Complete.java │ ├── Tree_7_11_paper.java │ ├── Tree_7_12_FindError.java │ ├── Tree_7_13_LongestDistance.java │ ├── Tree_7_14_MaxSubtree.java │ ├── Tree_7_validate_BST.java │ ├── balanced.png │ ├── complete.png │ ├── inorder1.png │ ├── inorder2.png │ ├── maxBST1.png │ ├── maxBST2.png │ ├── paper.png │ ├── postorder1.png │ ├── postorder2.png │ ├── postorder3.png │ ├── preorder1.png │ ├── preorder2.png │ └── readme.md ├── chap08_Bit │ ├── Screen Shot 2017-04-30 at 3.54.01 PM.png │ ├── Screen Shot 2017-04-30 at 3.54.49 PM.png │ ├── Screen Shot 2017-04-30 at 3.55.34 PM.png │ ├── Screen Shot 2017-04-30 at 3.55.53 PM.png │ ├── Screen Shot 2017-04-30 at 3.57.27 PM.png │ ├── Screen Shot 2017-04-30 at 4.01.49 PM.png │ ├── Screen Shot 2017-04-30 at 4.02.13 PM.png │ ├── Screen Shot 2017-04-30 at 4.08.07 PM.png │ ├── bit_8_03.java │ ├── bit_8_04.java │ ├── bit_8_05.java │ ├── bit_8_06.java │ └── readme.md ├── chap09_Permulation_Combination │ ├── PC_9_02_countWays.java │ ├── PC_9_03_StandInLine.java │ ├── PC_9_04_getWays.java │ ├── PC_9_05_getWays.java │ ├── PC_9_07_blanket.java │ ├── PC_9_08_stack.java │ ├── PC_9_09_ticket.java │ ├── PC_9_10_TreeCount.java │ ├── PC_9_11_HighAndShort.java │ ├── PC_9_12_CombineByMistake.java │ ├── Screen Shot 2017-04-30 at 5.24.05 PM.png │ └── readme.md ├── chap09_arrange │ ├── Screen Shot 2017-04-30 at 5.24.05 PM.png │ └── readme.md ├── chap10_probability │ ├── pro_10_02_Championship.java │ ├── pro_10_03_collision.java │ ├── pro_10_04_Random7.java │ ├── pro_10_05_Random01.java │ ├── pro_10_07_RandomSeg.java │ ├── pro_10_08_RandomPrint.java │ ├── pro_10_09_bag.java │ └── readme.md ├── chap11_BigData │ ├── Screen Shot 2017-05-01 at 6.19.01 PM.png │ ├── Screen Shot 2017-05-01 at 6.19.35 PM.png │ ├── Screen Shot 2017-05-01 at 6.19.49 PM.png │ ├── Screen Shot 2017-05-01 at 6.39.03 PM.png │ ├── Screen Shot 2017-05-01 at 6.44.00 PM.png │ ├── Screen Shot 2017-05-01 at 6.48.32 PM.png │ ├── Screen Shot 2017-05-01 at 6.53.55 PM.png │ ├── Screen Shot 2017-05-01 at 6.55.04 PM.png │ └── readme.md ├── chap12_DaynamicProgramming │ ├── 1.png │ ├── 12.1_1_暴力解法.png │ ├── 12.1_2_记忆化搜索.png │ ├── 12.1_3_动态规划.png │ ├── 12.1_4_动态规划的简化.png │ ├── 12.1_对比.png │ ├── 4.png │ ├── 5.png │ ├── 6_1.png │ ├── 6_2.png │ ├── dp_12_02_Exchange.java │ ├── dp_12_04_GoUpStairs.java │ ├── dp_12_05_MinimumPath.java │ ├── dp_12_06_LIS.java │ ├── dp_12_07_LCS.java │ ├── dp_12_08_backpack.java │ ├── dp_12_09_minCost.java │ └── readme.md ├── chap13_brain │ ├── brain_13_01.java │ ├── brain_13_02.java │ ├── brain_13_03.java │ ├── brain_13_04.java │ └── brain_13_05.java ├── nowcode_0519_test │ ├── test1.java │ ├── test2.java │ └── test3.java └── readme.md ├── others ├── README.md └── image │ ├── 25353.png │ └── 25353_.png ├── sort ├── 01_insertSort.java ├── 01_insertSort.py ├── 02_bubbleSort.java ├── 02_bubbleSort.py ├── 03_selectionSort.java ├── 03_selectionSort.py ├── 04_quickSort.java ├── 04_quickSort.py ├── 05_shellSort.java ├── 05_shellSort.py ├── 05_shellSort_2.java ├── 06_heapSort.java ├── 06_heapSort.py ├── 06_heapSort_recursive.java ├── 07_mergeSort.py ├── 07_mergeSort_Rec.java ├── 07_mergeSort_nonRec.java ├── 07_mergeSort_test.java ├── 08_LSD.java ├── 08_radixSort.java ├── 08_radixSort.py ├── 08_radixSort2.java ├── 08_radixSort2.py ├── 09_otherSort.py ├── Quicksort.java ├── QuicksortTest.java ├── README.md ├── _1156494-62f859c2ac6f95ff.png ├── _1156494-ab4cecff133d87b3.png ├── _大根堆演示.jpg └── quick_sort.py ├── sort2 ├── BubbleSort.java ├── HeapSort.java ├── InsetSort.java ├── MergeSort.java ├── QuickSort.java ├── README.md ├── RadixSort.java ├── SelectionSort.java └── ShellSort.java ├── stack └── README.md └── tree ├── BinaryTree_Traversal.java ├── BinaryTree_tranverse01.java ├── BinaryTree_tranverse02.java ├── Binary_Tree_Traversal.java └── 二叉树 review _ 岁月轻狂.pdf /20170505_share_divide_conquer/[每日一题]4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/20170505_share_divide_conquer/[每日一题]4.pdf -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/4_Median_Two_Sorted_Arrays.py: -------------------------------------------------------------------------------- 1 | # http://www.jiuzhang.com/solutions/median-of-two-sorted-arrays/ 2 | 3 | class Solution: 4 | """ 5 | @param A: An integer array. 6 | @param B: An integer array. 7 | @return: a double whose format is *.5 or *.0 8 | """ 9 | def findMedianSortedArrays(self, A, B): 10 | n = len(A) + len(B) 11 | if n % 2 == 1: 12 | return self.findKth(A, B, n / 2 + 1) 13 | else: 14 | smaller = self.findKth(A, B, n / 2) 15 | bigger = self.findKth(A, B, n / 2 + 1) 16 | return (smaller + bigger) / 2.0 17 | 18 | def findKth(self, A, B, k): 19 | if len(A) == 0: 20 | return B[k - 1] 21 | if len(B) == 0: 22 | return A[k - 1] 23 | if k == 1: 24 | return min(A[0], B[0]) 25 | 26 | a = A[k / 2 - 1] if len(A) >= k / 2 else None 27 | b = B[k / 2 - 1] if len(B) >= k / 2 else None 28 | 29 | if b is None or (a is not None and a < b): 30 | return self.findKth(A[k / 2:], B, k - k / 2) 31 | return self.findKth(A, B[k / 2:], k - k / 2) 32 | 33 | -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/BinarySearch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * http://www.jiuzhang.com/solutions/binary-search/ 3 | * 4 | * 本代码由九章算法编辑提供。版权所有,转发请注明出处。 5 | * - 九章算法致力于帮助更多中国人找到好的工作,教师团队均来自硅谷和国内的一线大公司在职工程师。 6 | * - 现有的面试培训课程包括:九章算法班,系统设计班,算法强化班,Java入门与基础算法班,Android 项目实战班,Big Data 项目实战班, 7 | * - 更多详情请见官方网站:http://www.jiuzhang.com/?source=code 8 | */ 9 | 10 | // version 1: with jiuzhang template 11 | public class Solution { 12 | /** 13 | * @param A an integer array sorted in ascending order 14 | * @param target an integer 15 | * @return an integer 16 | */ 17 | public int findPosition(int[] nums, int target) { 18 | if (nums == null || nums.length == 0) { 19 | return -1; 20 | } 21 | 22 | int start = 0, end = nums.length - 1; 23 | while (start + 1 < end) { 24 | int mid = start + (end - start) / 2; 25 | if (nums[mid] == target) { 26 | return mid; 27 | } else if (nums[mid] < target) { 28 | start = mid; 29 | } else { 30 | end = mid; 31 | } 32 | } 33 | 34 | if (nums[start] == target) { 35 | return start; 36 | } 37 | if (nums[end] == target) { 38 | return end; 39 | } 40 | return -1; 41 | } 42 | } 43 | 44 | // version 2: without jiuzhang template 45 | public class Solution { 46 | /** 47 | * @param A an integer array sorted in ascending order 48 | * @param target an integer 49 | * @return an integer 50 | */ 51 | public int findPosition(int[] nums, int target) { 52 | if (nums == null || nums.length == 0) { 53 | return -1; 54 | } 55 | 56 | int start = 0, end = nums.length - 1; 57 | while (start < end) { 58 | int mid = start + (end - start) / 2; 59 | if (nums[mid] == target) { 60 | return mid; 61 | } else if (nums[mid] < target) { 62 | start = mid + 1; 63 | } else { 64 | end = mid - 1; 65 | } 66 | } 67 | 68 | if (nums[start] == target) { 69 | return start; 70 | } 71 | return -1; 72 | } 73 | } -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/Tree_7_02_print.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 请用递归方式实现二叉树的先序、中序和后序的遍历打印。 6 | 7 | 给定一个二叉树的根结点root,请依次返回二叉树的先序,中序和后续遍历(二维数组的形式)。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | public TreeNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | public class TreeToSequence { 21 | public int[][] convert(TreeNode root) { 22 | // write code here 23 | ArrayList> list = new ArrayList>(); 24 | for (int i = 0; i < 3; i++) { 25 | list.add(new ArrayList()); 26 | } 27 | preOrder((root), list.get(0)); 28 | inOrder((root), list.get(1)); 29 | postOrder((root), list.get(2)); 30 | int[][] arr = new int[3][list.get(0).size()]; 31 | for (int i = 0; i < 3; i++) { 32 | for (int j = 0; j < list.get(0).size(); j++) { 33 | arr[i][j] = list.get(i).get(j); 34 | } 35 | } 36 | return arr; 37 | } 38 | public void preOrder(TreeNode root, ArrayList res) { 39 | if (root == null) { 40 | return; 41 | } 42 | res.add(root.val); 43 | preOrder(root.left, res); 44 | preOrder(root.right, res); 45 | } 46 | public void inOrder(TreeNode root, ArrayList res) { 47 | if (root == null) { 48 | return; 49 | } 50 | inOrder(root.left, res); 51 | res.add(root.val); 52 | inOrder(root.right, res); 53 | } 54 | public void postOrder(TreeNode root, ArrayList res) { 55 | if (root == null) { 56 | return; 57 | } 58 | postOrder(root.left, res); 59 | postOrder(root.right, res); 60 | res.add(root.val); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/Tree_7_05_LevelTraverse.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 有一棵二叉树,请设计一个算法,按照层次打印这棵二叉树。 6 | 7 | 给定二叉树的根结点root,请返回打印结果,结果按照每一层一个数组进行储存,所有数组的顺序按照层数从上往下,且每一层的数组内元素按照从左往右排列。保证结点数小于等于500。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | public TreeNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | public class TreePrinter { 21 | public int[][] printTree(TreeNode root) { 22 | // write code here 23 | if (root == null) { 24 | return null; 25 | } 26 | ArrayList> res = new ArrayList>(); 27 | levelTraverse(root, 1, res); 28 | int[][] ans = new int[res.size()][]; 29 | for (int i = 0; i < res.size(); i++) { 30 | ans[i] = new int[res.get(i).size()]; 31 | for (int j = 0; j < res.get(i).size(); j++) { 32 | ans[i][j] = res.get(i).get(j); 33 | } 34 | } 35 | return ans; 36 | } 37 | public void levelTraverse(TreeNode root, int level, ArrayList> res) { 38 | if (root == null) { 39 | return; 40 | } 41 | if (res.size() < level) { 42 | res.add(new ArrayList()); 43 | } 44 | res.get(level - 1).add(root.val); 45 | levelTraverse(root.left, level + 1, res); 46 | levelTraverse(root.right, level + 1, res); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/mergeSort_Rec.java: -------------------------------------------------------------------------------- 1 | // http://www.vogella.com/tutorials/JavaAlgorithmsMergesort/article.html 2 | public class Mergesort { 3 | private int[] numbers; 4 | private int[] helper; 5 | 6 | private int number; 7 | 8 | public void sort(int[] values) { 9 | this.numbers = values; 10 | number = values.length; 11 | this.helper = new int[number]; 12 | mergesort(0, number - 1); 13 | } 14 | 15 | private void mergesort(int low, int high) { 16 | if (low < high) { 17 | int middle = low + (high - low) / 2; 18 | mergesort(low, middle); 19 | mergesort(middle + 1, high); 20 | merge(low, middle, high); 21 | } 22 | } 23 | 24 | private void merge(int low, int middle, int high) { 25 | 26 | // Copy both parts into the helper array 27 | for (int i = low; i <= high; i++) { 28 | helper[i] = numbers[i]; 29 | } 30 | 31 | int i = low; 32 | int j = middle + 1; 33 | int k = low; 34 | // to the original array 35 | while (i <= middle && j <= high) { 36 | if (helper[i] <= helper[j]) { 37 | numbers[k] = helper[i]; 38 | i++; 39 | } else { 40 | numbers[k] = helper[j]; 41 | j++; 42 | } 43 | k++; 44 | } 45 | // Copy the rest of the left side of the array into the target array 46 | while (i <= middle) { 47 | numbers[k] = helper[i]; 48 | k++; 49 | i++; 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/mergeSort_nonRec.java: -------------------------------------------------------------------------------- 1 | public class MergeSort { 2 | public void Merge(int[] array, int low, int mid, int high) { 3 | int i = low; 4 | int j = mid + 1; 5 | int k = 0; 6 | int[] array2 = new int[high - low + 1]; 7 | 8 | // 扫描第一段和第二段序列,直到有一个扫描结束 9 | while (i <= mid && j <= high) { 10 | if (array[i] <= array[j]) { 11 | array2[k] = array[i]; 12 | i++; 13 | k++; 14 | } else { 15 | array2[k] = array[j]; 16 | j++; 17 | k++; 18 | } 19 | } 20 | while (i <= mid) { 21 | array2[k++] = array[i++]; 22 | } 23 | while (j <= high) { 24 | array2[k++] = array[j++]; 25 | } 26 | for (k = 0, i = low; i <= high; i++, k++) { 27 | array[i] = array2[k]; 28 | } 29 | } 30 | 31 | // 这里用的是非递归的方法 32 | public void MergePass(int[] array, int gap, int length) { 33 | int i = 0; 34 | // 归并gap长度的两个相邻子表 35 | for (i = 0; i + 2 * gap - 1 < length; i = i + 2 * gap) { 36 | Merge(array, i, i + gap - 1, i + 2 * gap - 1); 37 | } 38 | // 余下两个子表,后者长度小于gap 39 | if (i + gap - 1 < length) { 40 | Merge(array, i, i + gap - 1, length - 1); 41 | } 42 | } 43 | 44 | public int[] sort(int[] list) { 45 | for (int gap = 1; gap < list.length; gap = 2 * gap) { 46 | MergePass(list, gap, list.length); 47 | System.out.print("gap = " + gap + ":\t"); 48 | this.printAll(list); 49 | } 50 | return list; 51 | } 52 | 53 | // 打印完整序列 54 | public void printAll(int[] list) { 55 | for (int value : list) { 56 | System.out.print(value + "\t"); 57 | } 58 | System.out.println(); 59 | } 60 | 61 | public static void main(String[] args) { 62 | int[] array = { 63 | 9, 1, 5, 3, 4, 2, 6, 8, 7 64 | }; 65 | MergeSort merge = new MergeSort(); 66 | System.out.print("排序前:\t\t"); 67 | merge.printAll(array); 68 | merge.sort(array); 69 | System.out.print("排序后:\t\t"); 70 | merge.printAll(array); 71 | } 72 | } -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/partition.java: -------------------------------------------------------------------------------- 1 | // two pointer 2 | // quick sort 3 | public int partition(int[] nums, int l, int r) { 4 | // 初始双指针 和 pivot 5 | int left = l; 6 | int right = r; 7 | int pivot = nums[left]; 8 | while (left < right) { 9 | // 右边小与的移动到左边 10 | while (left < right && num[right] >= pivot) { 11 | right--; 12 | } 13 | nums[left] = nums[right]; 14 | // 左边小于的移动到右边 15 | while (left < right && nums[left] <= pivot) { 16 | left++; 17 | } 18 | nums[right] = nums[left]; 19 | } 20 | // 注意这一句!! pivot归位。 21 | nums[left] = pivot; 22 | return left 23 | } -------------------------------------------------------------------------------- /20170505_share_divide_conquer/code/quickSort.java: -------------------------------------------------------------------------------- 1 | public class Quicksort { 2 | private int[] numbers; 3 | private int number; 4 | 5 | public void sort(int[] values) { 6 | // check for empty or null array 7 | if (values ==null || values.length==0){ 8 | return; 9 | } 10 | this.numbers = values; 11 | number = values.length; 12 | quicksort(0, number - 1); 13 | } 14 | 15 | private void quicksort(int low, int high) { 16 | int i = low, j = high; 17 | int pivot = numbers[low + (high-low)/2]; 18 | 19 | // Divide into two lists 20 | while (i <= j) { 21 | while (numbers[i] < pivot) { 22 | i++; 23 | } 24 | while (numbers[j] > pivot) { 25 | j--; 26 | } 27 | if (i <= j) { 28 | exchange(i, j); 29 | i++; 30 | j--; 31 | } 32 | } 33 | // Recursion 34 | if (low < j) 35 | quicksort(low, j); 36 | if (i < high) 37 | quicksort(i, high); 38 | } 39 | 40 | private void exchange(int i, int j) { 41 | int temp = numbers[i]; 42 | numbers[i] = numbers[j]; 43 | numbers[j] = temp; 44 | } 45 | } 46 | 47 | 48 | public class Quicksort implements Sorter { 49 | // Sort the array a[0..n-1] by the quicksort algorithm. 50 | public void sort(Comparable [] a, int n) { 51 | quicksort(a, 0, n-1); 52 | } 53 | private void quicksort(Comparable [] a, int p, int r) { 54 | if (p < r) { 55 | int q = partition(a, p, r); // q is pivot position 56 | quicksort(a, p, q-1); 57 | quicksort(a, q+1, r); 58 | } 59 | } 60 | 61 | protected int partition(Comparable [] a, int p, int r) { 62 | Comparable pivot = a[r]; 63 | int i = p - 1; 64 | for (int j = p; j < r; j++) { 65 | if (a[j].compareTo(pivot) <= 0) { 66 | i++; 67 | swap(a, i, j); 68 | } 69 | } 70 | 71 | swap(a, i+1, r); 72 | return i+1; 73 | } 74 | 75 | protected void swap(Comparable [] a, int i, int j) { 76 | Comparable t = a[i]; 77 | a[i] = a[j]; 78 | a[j] = t; 79 | } 80 | } -------------------------------------------------------------------------------- /20170505_share_divide_conquer/手写记录01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/20170505_share_divide_conquer/手写记录01.pdf -------------------------------------------------------------------------------- /20170505_share_divide_conquer/手写记录02.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/20170505_share_divide_conquer/手写记录02.pdf -------------------------------------------------------------------------------- /20170505_share_divide_conquer/手写记录03.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/20170505_share_divide_conquer/手写记录03.pdf -------------------------------------------------------------------------------- /LinkedList/链表review _ 岁月轻狂.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/LinkedList/链表review _ 岁月轻狂.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code_Practice 2 | 3 | ### Sort[./sort] 4 | 5 | [readme](./sort/README.md) 6 | 7 | 8 | practice coding. The coding was divided into different catalogs. 9 | 10 | JAVA 修饰符 public, private 等的区别,[stackoverflow] (http://stackoverflow.com/questions/215497/in-java-whats-the-difference-between-public-default-protected-and-private) 11 | 12 | 13 | 修饰符 | 类内部 | 同个包(package) | 子类 | 其他范围 14 | ------------- | ------------- | -------------| -------------| ------------- 15 | public | Y | Y | Y | Y 16 | protected | Y | Y | Y | N 17 | 无修饰符 | Y | Y | N or Y(见说明) | N 18 | private | Y | N | N | N 19 | 20 | 21 | 22 | 23 | ### stack and queue 24 | [readme] (./stack/README.md) 25 | * 熟悉基本操作 26 | * 栈和递归 27 | * 利用栈的窗口操作 28 | 29 | -------------------------------------------------------------------------------- /String/KMPMatch.java: -------------------------------------------------------------------------------- 1 | public class KMPMatch { 2 | 3 | // 计算部分匹配表 4 | public static int[] getNext(String pattern) { 5 | int j = 0, k = -1; 6 | int[] next = new int[pattern.length()]; 7 | next[0] = -1; 8 | while (j < pattern.length() - 1) { 9 | if (-1 == k || pattern.charAt(j) == pattern.charAt(k)) { 10 | j++; 11 | k++; 12 | next[j] = k; 13 | } else { 14 | k = next[k]; 15 | } 16 | } 17 | 18 | return next; 19 | } 20 | 21 | // KMP算法 22 | static int kmpMatch(String target, String pattern) { 23 | int i = 0, j = 0, index = 0; 24 | int[] next = getNext(pattern); // 计算部分匹配表 25 | 26 | while (i < target.length() && j < pattern.length()) { 27 | if (-1 == j || target.charAt(i) == pattern.charAt(j)) { 28 | i++; 29 | j++; 30 | } else { 31 | j = next[j]; // 如果出现部分不匹配,获取跳过的位置 32 | } 33 | } 34 | 35 | if (j >= pattern.length()) 36 | index = i - pattern.length(); // 匹配成功,返回匹配子串的首字符下标 37 | else 38 | index = -1; // 匹配失败 39 | 40 | return index; 41 | 42 | } 43 | 44 | // 打印完整序列 45 | public static void printAll(int[] list) { 46 | for (int value : list) { 47 | System.out.print(value + "\t"); 48 | } 49 | System.out.println(); 50 | } 51 | 52 | public static void main(String[] args) { 53 | String target = "ababcabcacbab"; 54 | String pattern = "abcac"; 55 | int index = kmpMatch(target, pattern); 56 | System.out.format("[%s] is in the pos = %d of [%s]", pattern, index, target); 57 | } 58 | 59 | } 60 | 61 | 62 | 63 | KMP算法之JAVA实现 -------------------------------------------------------------------------------- /String/bfMatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int bfMatch(string target, string pattern) { 7 | int pos = -1; 8 | int i = 0, j = 0, k = 0; 9 | 10 | // 在没找到匹配pattern的子串前,遍历整个target 11 | while (-1 == pos && i < (int)target.length()) { 12 | 13 | // 将目标串和模式串逐一比对,如果有不同的则退出 14 | while (j < (int)pattern.length() && target[i] == pattern[j]) { 15 | i++; 16 | j++; 17 | } 18 | 19 | if (j >= (int)pattern.length()) { // 如果模式串扫描完,说明目标串中含有这个子串 20 | pos = k; 21 | } else { // 反之,没有扫描完,则从目标串的下一个字符开始重新逐一比对 22 | j = 0; 23 | k++; 24 | i = k; 25 | } 26 | } 27 | 28 | return pos; 29 | } 30 | 31 | void print(string target, string pattern, int index) { 32 | if (-1 != index) { 33 | cout << "[" << pattern << "] is in the Pos = " << index << " of [" << target << "]" << endl; 34 | } else { 35 | cout << "[" << pattern << "] is not in the [" << target << "]" << endl; 36 | } 37 | } 38 | 39 | int main() 40 | { 41 | string target = "Hello World"; 42 | string pattern = "llo"; 43 | string pattern2 = "Woe"; 44 | 45 | int index = bfMatch(target, pattern); 46 | int index2 = bfMatch(target, pattern2); 47 | print(target, pattern, index); 48 | print(target, pattern2, index2); 49 | return 0; 50 | } 51 | 52 | 53 | 54 | BF算法之C++实现 -------------------------------------------------------------------------------- /String/bfMatch.java: -------------------------------------------------------------------------------- 1 | public class BFMatch { 2 | 3 | static int bfMatch(String target, String pattern) { 4 | int pos = -1; 5 | int i = 0, j = 0, k = 0; 6 | 7 | // 在没找到匹配pattern的子串前,遍历整个target 8 | while (-1 == pos && i < target.length()) { 9 | 10 | // 将目标串和模式串逐一比对,如果有不同的则退出 11 | while (j < pattern.length() && target.charAt(i) == pattern.charAt(j)) { 12 | i++; 13 | j++; 14 | } 15 | 16 | if (j >= pattern.length()) { // 如果模式串扫描完,说明目标串中含有这个子串 17 | pos = k; 18 | } else { // 反之,没有扫描完,则从目标串的下一个字符开始重新逐一比对 19 | j = 0; 20 | k++; 21 | i = k; 22 | } 23 | } 24 | 25 | return pos; 26 | } 27 | 28 | public static void print(String target, String pattern, int index) { 29 | if (-1 != index) { 30 | System.out.format("[%s] is in the Pos = %d of [%s]\n", pattern, index, target); 31 | } else { 32 | System.out.format("[%s] is not in the [%s]\n", pattern, target); 33 | } 34 | } 35 | 36 | public static void main(String[] args) { 37 | String target = "Hello World"; 38 | String pattern = "llo"; 39 | String pattern2 = "Woe"; 40 | 41 | int index = bfMatch(target, pattern); 42 | int index2 = bfMatch(target, pattern2); 43 | print(target, pattern, index); 44 | print(target, pattern2, index2); 45 | 46 | } 47 | 48 | } 49 | 50 | 51 | 52 | BF算法之JAVA实现 -------------------------------------------------------------------------------- /String/kmpMatch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | const int MAX = 100; 7 | int next[MAX] = {0}; 8 | 9 | // 计算部分匹配表 10 | void getNext(string pattern) { 11 | int j = 0, k = -1; 12 | next[0] = -1; 13 | while (j < (int)pattern.length() - 1) { 14 | if (-1 == k || pattern[j] == pattern[k]) { 15 | j++; 16 | k++; 17 | next[j] = k; 18 | } else { 19 | k = next[k]; 20 | } 21 | } 22 | return; 23 | } 24 | 25 | // KMP算法 26 | int kmpMatch(string target, string pattern) { 27 | int i = 0, j = 0, index = 0; 28 | getNext(pattern); // 计算部分匹配表 29 | 30 | while (i < (int)target.length() && j < (int)pattern.length()) { 31 | if (-1 == j || target[i] == pattern[j]) { 32 | i++; 33 | j++; 34 | } else { 35 | j = next[j]; // 如果出现部分不匹配,获取跳过的位置 36 | } 37 | } 38 | 39 | if (j >= (int)pattern.length()) 40 | index = i - pattern.length(); // 匹配成功,返回匹配子串的首字符下标 41 | else 42 | index = -1; // 匹配失败 43 | 44 | return index; 45 | 46 | } 47 | 48 | void print(string target, string pattern, int index) { 49 | if (-1 != index) { 50 | cout << "[" << pattern << "] is in the Pos = " << index << " of [" << target << "]" << endl; 51 | } else { 52 | cout << "[" << pattern << "] is not in the [" << target << "]" << endl; 53 | } 54 | } 55 | 56 | int main() 57 | { 58 | string target = "ababcabcacbab"; 59 | string pattern = "abcac"; 60 | int index = kmpMatch(target, pattern); 61 | print(target, pattern, index); 62 | return 0; 63 | } 64 | 65 | 66 | 67 | KMP算法之C++实现 -------------------------------------------------------------------------------- /UnionFind.java: -------------------------------------------------------------------------------- 1 | // https://discuss.leetcode.com/topic/85039/java-solution-union-find 2 | public class Solution { 3 | class UnionFind { 4 | private int count = 0; 5 | private int[] parent, rank; 6 | 7 | public UnionFind(int n) { 8 | count = n; 9 | parent = new int[n]; 10 | rank = new int[n]; 11 | for (int i = 0; i < n; i++) { 12 | parent[i] = i; 13 | } 14 | } 15 | 16 | public int find(int p) { 17 | while (p != parent[p]) { 18 | parent[p] = parent[parent[p]]; 19 | p = parent[p]; 20 | } 21 | return p; 22 | } 23 | 24 | public void union(int p, int q) { 25 | int rootP = find(p); 26 | int rootQ = find(q); 27 | if (rootP == rootQ) return; 28 | if (rank[rootQ] > rank[rootP]) { 29 | parent[rootP] = rootQ; 30 | } 31 | else { 32 | parent[rootQ] = rootP; 33 | if (rank[rootP] == rank[rootQ]) { 34 | rank[rootP]++; 35 | } 36 | } 37 | count--; 38 | } 39 | 40 | public int count() { 41 | return count; 42 | } 43 | } 44 | 45 | public int findCircleNum(int[][] M) { 46 | int n = M.length; 47 | UnionFind uf = new UnionFind(n); 48 | for (int i = 0; i < n - 1; i++) { 49 | for (int j = i + 1; j < n; j++) { 50 | if (M[i][j] == 1) uf.union(i, j); 51 | } 52 | } 53 | return uf.count(); 54 | } 55 | } -------------------------------------------------------------------------------- /bit_bigdata/readme.md: -------------------------------------------------------------------------------- 1 | 【大数据题目一】 不安全网页的黑名单包含100亿个黑名单网页,每个网页的URL最多占用64B。现 在想要实现一种网页过滤系统,可以根据网页的URL判断该网页是否在黑名单上, 请设计该系统。 【要求】 1.该系统允许有万分之一以下的判断失误率。 2 | 2.使用的额外空间不要超过30GB。 3 | 4 | 【大数据题目二】 有一个包含20亿个全是32位整数的大文件,在其中找到出现次数最多的数。 5 | 【要求】 内存限制为2GB。 6 | 7 | 【大数据题目三】 32位无符号整数的范围是0~4294967295,现在有一个正好包含40亿个无符号整 数的文件,所以在整个范围中必然有没出现过的数。可以使用最多1GB的内存, 怎么找到所有没出现过的数? 【大数据题目三进阶】 内存限制为10MB,但是只用找到一个没出现过的数即可。 8 | 9 | 【大数据题目四】 有一个包含100亿个URL的大文件,假设每个URL占用64B,请找出其中所有重复 的URL。 10 | 【大数据题目四补充题目】 某搜索公司一天的用户搜索词汇是海量的(百亿数据量),请设计一种求出每天 最热top 100词汇的可行办法。 11 | 12 | 13 | 【大数据题目五】 32位无符号整数的范围是0~4294967295,现在有40亿个无符号整数,可以使用 最多1GB的内存,找出所有出现了两次的数。 【补充题目】 可以使用最多10MB的内存,怎么找到这40亿个整数的中位数? 14 | 15 | 【大数据题目六】 工程师常使用服务器集群来设计和实现数据缓存,以下是常见的策略: 16 | 1.无论是添加、查询还是删除数据,都先将数据的id通过哈希函数转换成一个哈 希值,记为key。 17 | 2.如果目前机器有N台,则计算key%N的值,这个值就是该数据所属的机器编号, 无论是添加、删除还是查询操作,都只在这台机器上进行。 请分析这种缓存策略可能带来的问题,并提出改进的方案。 18 | 19 | --- 20 | > & | ^ ~ 21 | > \>\> << 22 | > \>\>\> 无符号移动 23 | >判断奇偶: i & 1 24 | >交换两数: c = a ^ b; a = c ^ a; b = c ^ a; 25 | >交换符号: ~a + 1 26 | >求绝对值: int i = a >> 31; i == 0 ? a : (~a + 1) 27 | >求平均数: ((x&y) + ((x^y)>>1) 28 | 29 | 【位运算题目一,大俗题】 不用额外变量交换两个整数的值 30 | 31 | 【位运算题目二】 给定两个32位整数a和b,返回a和b中较大的。不用任何比较判断。 32 | 33 | 【位运算题目三】 给定一个32位整数n,可为0,可为正,也可为负,返回该整数二进制表达中1的 个数。 34 | > 多种解题方法 35 | 36 | 【位运算题目四】 给定一个整型数组arr,其中只有一个数出现了奇数次,其他的数都出现了偶数次, 打印这个数。 【进阶】 有两个数出现了奇数次,其他的数都出现了偶数次,打印这两个数 37 | >整数n与0异或的结果是n,整数n与整数n异或的结果是0。 38 | 39 | 【位运算题目五】 给定一个整型数组arr和一个大于1的整数k。已知arr中只有1个数出现了1次,其他 的数都出现了k次,请返回只出现了1次的数。 【要求】 时间复杂度为O(N),额外空间复杂度为O(1)。 40 | 41 | 【位运算题目六】 只用位运算实现整数的加减乘除运算 -------------------------------------------------------------------------------- /bit_bigdata/海量数据处理 _ 岁月轻狂.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/bit_bigdata/海量数据处理 _ 岁月轻狂.pdf -------------------------------------------------------------------------------- /nowcoder/chap01_intro/Rotation.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | /** 4 | * Created by xing on 4/25/17. 5 | */ 6 | import java.util.*; 7 | 8 | public class Rotation { 9 | public boolean chkRotation(String A, int lena, String B, int lenb) { 10 | // write code here 11 | if (lena != lenb) { 12 | return false; 13 | } 14 | String str = A + A; 15 | return str.contains(B); 16 | for (int i = 0; i < str.length(); i++) { 17 | int start = i; 18 | for (int j = 0; j < B.length(); j++) { 19 | if (B.charAt()) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nowcoder/chap01_intro/TreePrinter.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | import java.util.*; 3 | import utils.TreeNode; 4 | 5 | //public class TreeNode { 6 | // int val = 0; 7 | // TreeNode left = null; 8 | // TreeNode right = null; 9 | // public TreeNode(int val) { 10 | // this.val = val; 11 | // } 12 | //} 13 | public class TreePrinter { 14 | public int[][] printTree(TreeNode root) { 15 | // write code here 16 | ArrayList> res = new ArrayList>(); 17 | if (root == null) { 18 | return null; 19 | } 20 | Queue queue = new LinkedList(); 21 | queue.offer(root); 22 | while (!queue.isEmpty()) { 23 | int size = queue.size(); 24 | res.add(new ArrayList()); 25 | for (int i = 0; i < size; i++) { 26 | TreeNode node = queue.poll(); 27 | res.get(res.size() - 1).add(node.val); 28 | if (node.left != null) { 29 | queue.offer(node.left); 30 | } 31 | if (node.right != null) { 32 | queue.offer(node.right); 33 | } 34 | } 35 | } 36 | int[][] ans = new int[res.size()][]; 37 | for (int i = 0; i < res.size(); i++) { 38 | ans[i] = new int[res.get(i).size()]; 39 | for (int j = 0; j < res.get(i).size(); j++) { 40 | ans[i][j] = res.get(i).get(j); 41 | } 42 | } 43 | return ans; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/BubbleSort.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | /** 4 | * Created by xing on 4/25/17. 5 | */ 6 | public class BubbleSort { 7 | public int[] bubbleSort(int[] A, int n) { 8 | // write code here 9 | for(int i = 0; i < n - 1; i++){ 10 | for(int j = 0; j < n - i - 1; j++){ 11 | if(A[j] > A[j + 1]) { 12 | int temp = A[j]; 13 | A[j] = A[j + 1]; 14 | A[j + 1] = temp; 15 | } 16 | } 17 | } 18 | return A; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/CountingSort.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class CountingSort { 4 | public int[] countingSort(int[] A, int n) { 5 | // write code here 6 | int min = Integer.MAX_VALUE; 7 | int max = Integer.MIN_VALUE; 8 | for (int i = 0; i < n; i++) { 9 | if (A[i] < min) { 10 | min = A[i]; 11 | } 12 | if (A[i] > max) { 13 | max = A[i]; 14 | } 15 | } 16 | int[] list = new int[max - min + 1]; 17 | for (int i = 0; i < n; i++) { 18 | list[A[i] - min]++; 19 | } 20 | int[] res = new int[n]; 21 | int index = 0; 22 | for (int i = 0; i < max - min + 1; i++) { 23 | while (list[i] != 0) { 24 | res[index++] = i + min; 25 | list[i]--; 26 | } 27 | } 28 | return res; 29 | } 30 | } -------------------------------------------------------------------------------- /nowcoder/chap02_sort/HeapSort.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class HeapSort { 4 | public int[] heapSort(int[] A, int n) { 5 | // write code here 6 | for (int i = n / 2; i >= 0; i--) { 7 | heapAdjust(A, i, A.length); 8 | } 9 | for (int i = A.length - 1; i > 0; i--) { 10 | swap(A, 0, i); 11 | heapAdjust(A, 0, i); 12 | } 13 | return A; 14 | } 15 | public void heapAdjust(int[] A, int parent, int length) { 16 | int parent_value = A[parent]; 17 | //int left = 2 * parent + 1; 18 | //int right = 2 * parent + 2; 19 | int child = 2 * parent + 1; 20 | while (child < length) { 21 | if (child + 1 < length && A[child] < A[child +1]) { 22 | child++; 23 | } 24 | if (parent_value >= A[child]) { 25 | break; 26 | } 27 | A[parent] = A[child]; 28 | parent = child; 29 | child = 2 * child + 1; 30 | } 31 | A[parent] = parent_value; 32 | } 33 | public void swap(int[] A, int i, int j) { 34 | int temp = A[i]; 35 | A[i] = A[j]; 36 | A[j] = temp; 37 | } 38 | } -------------------------------------------------------------------------------- /nowcoder/chap02_sort/InsertionSort.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class InsertionSort { 4 | public int[] insertionSort(int[] A, int n) { 5 | // write code here 6 | for (int i = 0; i < n; i++) { 7 | for (int j = i - 1; j >= 0; j--) { 8 | if (A[j] > A[j + 1]) { 9 | swap(A, j + 1, j); 10 | } 11 | } 12 | } 13 | return A; 14 | } 15 | public void swap(int[] A, int i, int j) { 16 | int temp = A[i]; 17 | A[i] = A[j]; 18 | A[j] = temp; 19 | } 20 | } -------------------------------------------------------------------------------- /nowcoder/chap02_sort/MergeSort.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class MergeSort { 4 | public int[] mergeSort(int[] A, int n) { 5 | // write code here 6 | mergeS(A, 0, A.length - 1); 7 | return A; 8 | } 9 | public void mergeS(int[] A, int start, int end) { 10 | if (start >= end) { 11 | return; 12 | } 13 | int mid = (start + end) / 2; 14 | mergeS(A, start, mid); 15 | mergeS(A, mid + 1, end); 16 | mergeArray(A, start, mid, end); 17 | } 18 | public void mergeArray(int[] A, int start, int mid, int end) { 19 | int[] B = new int[end - start + 1]; 20 | int left = start; 21 | int right = mid + 1; 22 | int index = 0; 23 | while (left <= mid && right <= end) { 24 | if (A[left] <= A[right]) { 25 | B[index++] = A[left++]; 26 | } else { 27 | B[index++] = A[right++]; 28 | } 29 | } 30 | while (left <= mid) { 31 | B[index++] = A[left++]; 32 | } 33 | while (right <= end) { 34 | B[index++] = A[right++]; 35 | } 36 | for (int i = 0; i <= end - start; i++) { 37 | A[start + i] = B[i]; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /nowcoder/chap02_sort/MergeSortBU.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | public class MergeSortBU { 4 | public int[] mergeSort(int[] A, int n) { 5 | // write code here 6 | for (int sz = 1; sz < n; sz *= 2) { 7 | for (int lo = 0; lo < n - sz; lo += sz * 2) { 8 | merge(A, lo, lo + sz - 1, Math.min(lo + sz * 2 - 1, n - 1)); 9 | } 10 | } 11 | return A; 12 | } 13 | public void merge(int[] A, int lo, int mid, int hi) { 14 | int i = lo; 15 | int j = mid + 1; 16 | int[] B = new int[hi - lo + 1]; 17 | for (int k = 0; k <= hi - lo; k++) { 18 | if (i > mid) { 19 | B[k] = A[j++]; 20 | } else if (j > hi) { 21 | B[k] = A[i++]; 22 | } else if (A[i] < A[j]) { 23 | B[k] = A[i++]; 24 | } else { 25 | B[k] = A[j++]; 26 | } 27 | } 28 | for (int k = 0; k <= hi - lo; k++) { 29 | A[lo + k] = B[k]; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/QuickSort.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class QuickSort { 4 | public int[] quickSort(int[] A, int n) { 5 | // write code here 6 | sort(A, 0, n - 1); 7 | return A; 8 | } 9 | public void sort(int[] A, int start, int end) { 10 | if (start >= end) { 11 | return; 12 | } 13 | int i = start; 14 | int j = end; 15 | int pivot = A[start + (end - start) / 2]; 16 | while (i <= j) { 17 | while (A[i] < pivot) { 18 | i++; 19 | } 20 | while (A[j] > pivot) { 21 | j--; 22 | } 23 | if (i <= j) { 24 | swap(A, i, j); 25 | i++; 26 | j--; 27 | } 28 | } 29 | sort(A, start, j); 30 | sort(A, i, end); 31 | } 32 | public void swap(int[] A, int i, int j) { 33 | int temp = A[i]; 34 | A[i] = A[j]; 35 | A[j] = temp; 36 | } 37 | } -------------------------------------------------------------------------------- /nowcoder/chap02_sort/RadixSort.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | public class RadixSort { 4 | public int[] radixSort(int[] A, int n) { 5 | // write code here 6 | int max = getMax(A); 7 | for (int exp = 1; max / exp > 0; exp *= 10) { 8 | countSort(A, exp); 9 | } 10 | return A; 11 | } 12 | public int getMax(int[] A) { 13 | int max = Integer.MIN_VALUE; 14 | for (int i = 0; i < A.length; i++) { 15 | if (max < A[i]) { 16 | max = A[i]; 17 | } 18 | } 19 | return max; 20 | } 21 | public void countSort(int[] A, int exp) { 22 | int[] ans = new int[A.length]; 23 | int[] count = new int[10]; 24 | for (int i = 0; i < A.length; i++) { 25 | count[(A[i] / exp) % 10]++; 26 | } 27 | for (int i = 1; i < 10; i++) { 28 | count[i] += count[i - 1]; 29 | } 30 | for (int i = A.length - 1; i >= 0; i--) { 31 | ans[count[(A[i] / exp) % 10] - 1] = A[i]; 32 | count[(A[i] / exp) % 10]--; 33 | } 34 | for (int i = 0; i < A.length; i++) { 35 | A[i] = ans[i]; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/SelectionSort.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | 3 | public class SelectionSort { 4 | public int[] selectionSort(int[] A, int n) { 5 | // write code here 6 | for (int i = 0; i < n; i++) { 7 | int min = i; 8 | for (int j = i + 1; j < n; j++) { 9 | if (A[j] < A[min]) { 10 | min = j; 11 | } 12 | } 13 | swap(A, i, min); 14 | } 15 | return A; 16 | } 17 | public void swap(int[] A, int i, int j) { 18 | int temp = A[i]; 19 | A[i] = A[j]; 20 | A[j] = temp; 21 | } 22 | } -------------------------------------------------------------------------------- /nowcoder/chap02_sort/ShellSort.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | public class ShellSort { 4 | public int[] shellSort(int[] A, int n) { 5 | // write code here 6 | int gap = n / 2; 7 | while (gap >= 1) { 8 | for (int i = gap; i < n; i++) { 9 | for (int j = i; j >= gap; j -= gap) { 10 | if (A[j] < A[j - gap]) { 11 | swap(A, j, j - gap); 12 | } 13 | } 14 | } 15 | gap /= 2; 16 | } 17 | return A; 18 | } 19 | public void swap(int[] A, int i, int j) { 20 | int temp = A[i]; 21 | A[i] = A[j]; 22 | A[j] = temp; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/readme.md: -------------------------------------------------------------------------------- 1 | ### 排序2 2 | 3 | 4 | 5 | ### 排序3 6 | 7 | 已知一个几乎有序的数组。数组排好顺序后,每个元素移动距离不超过k。并且k相对于数组大小很小,请选择什么方法进行排序。 8 | O(n)的算法不可用 9 | O(n2)算法 10 | 11 | 冒泡排序,选择排序,不依赖于数组的有序情况 12 | 插入排序,移动距离与原始顺序有关。时间复杂度为O(n*k) 13 | O(nlogn)算法 14 | 15 | 快速排序,归并排序,与原始顺序无关 16 | 改进后的堆排序,建立k个数的小根堆。时间复杂度为O(n*logk) 17 | 18 | 19 | 判断一个数组中是否有重复值,必须保证额外空间复杂度为O(1)。 20 | 21 | 如果没有空间复杂度的要求,那么用哈希表实现。 22 | 由于空间复杂度的要求,那么可以先排序再判断。 23 | 24 | O(1) 25 | 冒泡排序,选择排序,插入排序 26 | 希尔排序,堆排序(递归实现的话是O(logN)) 27 | O(logN) ~ O(N) 28 | 快速排序 29 | O(N) 30 | 归并排序 31 | O(M) 32 | 计数排序,基数排序 33 | 34 | 35 | 把两个有序数组合并为一个数组,第一个数组的空间正好可以容纳两个数组的元素。 36 | 归并排序的思想,但是从最后元素开始进行排序 37 | 38 | ### 排序4 39 | 荷兰国旗问题 0 1 2 三个元素数组的排序 40 | 行列都排序好的矩阵中查找元素。 41 | 从数组中找出需要排序的最短子数组长度 42 | 给定一个无需数组,找出排序后相邻数的最大差值 O(N) -------------------------------------------------------------------------------- /nowcoder/chap02_sort/sort_2_13.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | /** 3 | * 已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离可以不超过k,并且k相对于数组来说比较小。请选择一个合适的排序算法针对这个数据进行排序。 4 | 5 | 给定一个int数组A,同时给定A的大小n和题意中的k,请返回排序后的数组。 6 | 7 | 测试样例: 8 | [2,1,4,3,6,5,8,7,10,9],10,2 9 | 返回:[1,2,3,4,5,6,7,8,9,10] 10 | */ 11 | 12 | public class ScaleSort { 13 | public int[] sortElement(int[] A, int n, int k) { 14 | // write code here 15 | k = Math.min(n, k); 16 | int[] aux = new int[k]; 17 | // copy aux array 18 | for (int i = 0; i < k; i++) { 19 | aux[i] = A[i]; 20 | } 21 | // min heapfy the aux 22 | for (int i = k / 2; i >= 0; i--) { 23 | heapAdjust(aux, i, k); 24 | } 25 | // loop the aux array 26 | for (int i = 0; i < n - k; i++) { 27 | A[i] = aux[0]; 28 | aux[0] = A[i + k]; 29 | heapAdjust(aux, 0, k); 30 | } 31 | // loop the left array 32 | for (int i = n - k; i < n; i++) { 33 | A[i] = aux[0]; 34 | swap(aux, 0, k - 1); 35 | k--; 36 | heapAdjust(aux, 0, k); 37 | } 38 | return A; 39 | } 40 | public void heapSort(int[] A, int lo, int hi) { 41 | int len = hi - lo; 42 | for (int i = lo + len / 2; i < hi; i++) { 43 | heapAdjust(A, i, hi); 44 | } 45 | for (int i = hi - 1; i > 0; i--) { 46 | swap(A, 0, i); 47 | heapAdjust(A, 0, i); 48 | } 49 | } 50 | public void heapAdjust(int[] A, int parent, int length) { 51 | int parent_value = A[parent]; 52 | int child = 2 * parent + 1; 53 | while (child < length) { 54 | if (child + 1 < length && A[child] > A[child + 1]) { 55 | child++; 56 | } 57 | if (parent_value <= A[child]) { 58 | break; 59 | } 60 | A[parent] = A[child]; 61 | parent = child; 62 | child = 2 * child + 1; 63 | } 64 | A[parent] = parent_value; 65 | } 66 | public void swap(int[] A, int i, int j) { 67 | int temp = A[i]; 68 | A[i] = A[j]; 69 | A[j] = temp; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/sort_2_15.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | public class Merge { 4 | public int[] mergeAB(int[] A, int[] B, int n, int m) { 5 | // write code here 6 | int size = m + n; 7 | m--; 8 | n--; 9 | for (int i = size - 1; i >= 0; i--) { 10 | if (n < 0) { 11 | A[i] = B[m--]; 12 | } else if (m < 0) { 13 | //return A; 14 | A[i] = A[n--]; 15 | } else if (A[n] > B[m]) { 16 | A[i] = A[n--]; 17 | } else { 18 | A[i] = B[m--]; 19 | } 20 | } 21 | return A; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/sort_2_17.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | /** 4 | * 有一个只由0,1,2三种元素构成的整数数组,请使用交换、原地排序而不是使用计数进行排序。 5 | 6 | 给定一个只含0,1,2的整数数组A及它的大小,请返回排序后的数组。保证数组大小小于等于500。 7 | 8 | 测试样例: 9 | [0,1,1,0,2,2],6 10 | 返回:[0,0,1,1,2,2] 11 | */ 12 | 13 | public class ThreeColor { 14 | public int[] sortThreeColor(int[] A, int n) { 15 | // write code here 16 | int i = -1; // index of 0 17 | int j = 0; // index 18 | int k = A.length - 1; // index of last one 19 | while (j <= k) { 20 | if (A[j] == 0) { 21 | swap(A, i + 1, j); 22 | i++; 23 | j++; 24 | } else if (A[j] == 2) { 25 | swap(A, j, k); 26 | k--; 27 | } else { 28 | j++; 29 | } 30 | } 31 | return A; 32 | } 33 | public void swap(int[] A, int i, int j) { 34 | int temp = A[i]; 35 | A[i] = A[j]; 36 | A[j] = temp; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/sort_2_18.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | /** 4 | * 现在有一个行和列都排好序的矩阵,请设计一个高效算法,快速查找矩阵中是否含有值x。 5 | 6 | 给定一个int矩阵mat,同时给定矩阵大小nxm及待查找的数x,请返回一个bool值,代表矩阵中是否存在x。所有矩阵中数字及x均为int范围内整数。保证n和m均小于等于1000。 7 | 8 | 测试样例: 9 | [[1,2,3],[4,5,6],[7,8,9]],3,3,10 10 | 返回:false 11 | */ 12 | 13 | public class Finder { 14 | public boolean findX(int[][] mat, int n, int m, int x) { 15 | // write code here 16 | int i = 0; 17 | int j = m - 1; 18 | while (i < n && j >= 0) { 19 | if (mat[i][j] == x) { 20 | return true; 21 | } else if (mat[i][j] > x) { 22 | j--; 23 | } else { 24 | i++; 25 | } 26 | } 27 | return false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/sort_2_19.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | /** 4 | * 对于一个数组,请设计一个高效算法计算需要排序的最短子数组的长度。 5 | 6 | 给定一个int数组A和数组的大小n,请返回一个二元组,代表所求序列的长度。(原序列位置从0开始标号,若原序列有序,返回0)。保证A中元素均为正整数。 7 | 8 | 测试样例: 9 | [1,4,6,5,9,10],6 10 | 返回:2 11 | */ 12 | 13 | public class Subsequence { 14 | public int shortestSubsequence(int[] A, int n) { 15 | // write code here 16 | int cur_max = A[0]; 17 | int right = -1; 18 | int left = -1; 19 | for (int i = 0; i < A.length; i++) { 20 | if (A[i] >= cur_max) { 21 | cur_max = A[i]; 22 | } else { 23 | right = i; 24 | } 25 | } 26 | int cur_min = A[A.length - 1]; 27 | for (int i = A.length - 1; i >= 0; i--) { 28 | if (A[i] <= cur_min) { 29 | cur_min = A[i]; 30 | } else { 31 | left = i; 32 | } 33 | } 34 | if (left == -1 || right == -1) { 35 | return 0; 36 | } 37 | return right - left + 1; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /nowcoder/chap02_sort/sort_2_20.java: -------------------------------------------------------------------------------- 1 | package chap02_sort; 2 | 3 | /** 4 | * 有一个整形数组A,请设计一个复杂度为O(n)的算法,算出排序后相邻两数的最大差值。 5 | 6 | 给定一个int数组A和A的大小n,请返回最大的差值。保证数组元素多于1个。 7 | 8 | 测试样例: 9 | [1,2,5,4,6],5 10 | 返回:2 11 | */ 12 | 13 | public class Gap { 14 | public int maxGap(int[] A, int n) { 15 | // write code here 16 | int max = A[0]; 17 | int min = A[0]; 18 | for (int i = 0; i < A.length; i++) { 19 | if (max < A[i]) { 20 | max = A[i]; 21 | } 22 | if (min > A[i]) { 23 | min = A[i]; 24 | } 25 | } 26 | int[] arr = new int[max - min + 1]; 27 | for (int i = 0; i < A.length; i++) { 28 | arr[A[i] - min]++; 29 | } 30 | int last = 0; 31 | int count = 0; 32 | for (int i = 0; i < max - min + 1; i++) { 33 | if (arr[i] != 0) { 34 | count = Math.max(count, i - last); 35 | last = i; 36 | } 37 | } 38 | return count; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/readme.md: -------------------------------------------------------------------------------- 1 | 字符串问题可以看做字符类型数组,与数组排序,查找,调整有关。 2 | 3 | JAVA中字符串类型是不可更改的,需要结合StringBuffer, StringBuilder 类和toCharArray 的相关操作。 4 | 5 | 字符串中相关概念: 6 | 7 | 回文,子串(连续),子序列(不连续),前缀树(Trie树),后缀树和后缀数组,匹配,字典序。 8 | 9 | 基本操作: 10 | 11 | 数组相关的 增删改查 12 | 字符的替换 13 | 字符串的旋转 14 | 15 | 高级算法 16 | 17 | Manacher算法 18 | KMP算法 19 | 前缀树结构 20 | 后缀树和后缀数组 21 | 22 | 注意 23 | 字符串问题在分割字符串的时候最后一段经常不能在循环中完成,循环完成后需要再判断一次,例如string_3_06题目。 24 | 25 | 26 | 字符串题目的常见类型 27 | 28 | 1.规则判断 29 | 30 | 判断字符串是否符合整数规则 31 | 判断字符串是否符合浮点数规则 32 | 判断字符串是否符合会问字符串规则 33 | 34 | 2.数字运算 35 | 36 | int 和long 类型表达整数范围有限所以经常用字符串实现大整数 37 | 与大整数相关的加减乘除操作,需要模拟笔算的过程 38 | 39 | 3.与数组操作相关的类型 40 | 41 | 数组相关的调整、排序等操作需要掌握 42 | 快速排序的划分过程需要掌握和改写 43 | 44 | 4.字符计数 45 | 46 | hash表 47 | 固定长度的数组 48 | 滑动串口问题、寻找无重复字符子串问题、计算变位词问题 49 | 50 | 5.动态规划类型 51 | 52 | 最长公共子串 53 | 最长公共子串序列 54 | 最长回文子串 55 | 最长回文子序列 56 | 57 | 6.搜索类型 58 | 59 | 宽度优先搜索 60 | 深度优先搜索 61 | 62 | 7.高级算法与数据结构 63 | 64 | manacher算法解决最长回文子串问题 65 | kmp算法解决字符串匹配问题 66 | 前缀树结构 67 | 后缀树和后缀数组 -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_02.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * 对于两棵彼此独立的二叉树A和B,请编写一个高效算法,检查A中是否存在一棵子树与B树的拓扑结构完全相同。 5 | 6 | 给定两棵二叉树的头结点A和B,请返回一个bool值,代表A中是否存在一棵同构于B的子树。 7 | */ 8 | 9 | /* 10 | public class TreeNode { 11 | int val = 0; 12 | TreeNode left = null; 13 | TreeNode right = null; 14 | public TreeNode(int val) { 15 | this.val = val; 16 | } 17 | }*/ 18 | public class IdenticalTree { 19 | public boolean chkIdentical(TreeNode A, TreeNode B) { 20 | // write code here 21 | if (A == null && B == null) { 22 | return true; 23 | } else if (A == null || B == null) { 24 | return false; 25 | } 26 | if (isSame(A, B)) { 27 | return true; 28 | } 29 | return chkIdentical(A.left, B) || chkIdentical(A.right, B); 30 | } 31 | public boolean isSame(TreeNode A, TreeNode B) { 32 | if (A == null && B == null) { 33 | return true; 34 | } else if (A == null || B == null) { 35 | return false; 36 | } 37 | if (A.val == B.val) { 38 | return (isSame(A.left, B.left) && isSame(A.right, B.right)); 39 | } 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_02_b.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * Created by xing on 4/26/17. 5 | */ 6 | /* 7 | public class TreeNode { 8 | int val = 0; 9 | TreeNode left = null; 10 | TreeNode right = null; 11 | public TreeNode(int val) { 12 | this.val = val; 13 | } 14 | }*/ 15 | public class IdenticalTree { 16 | public boolean chkIdentical(TreeNode t1, TreeNode t2){ 17 | String t1Str = serialByPre(t1); 18 | String t2Str = serialByPre(t2); 19 | return getIndexOf(t1Str, t2Str) != -1; 20 | } 21 | 22 | //KMP 23 | private int getIndexOf(String s, String m) { 24 | if(s == null || m == null || m.length() < 1 ||s.length() < m.length()){ 25 | return -1; 26 | } 27 | char[] ss = s.toCharArray(); 28 | char[] ms = m.toCharArray(); 29 | 30 | int[] nextArr = getNextArray(ms); 31 | int index = 0; 32 | int mi = 0; 33 | while(index < ss.length && mi < ms.length){ 34 | if(ss[index] == ms[mi]){ 35 | index++; 36 | mi++; 37 | }else if(nextArr[mi] == -1){ 38 | index++; 39 | }else{ 40 | mi = nextArr[mi]; 41 | } 42 | } 43 | return mi == ms.length? index - mi: -1; 44 | } 45 | 46 | private static int[] getNextArray(char[] ms) { 47 | if(ms.length == 1){ 48 | return new int[]{-1}; 49 | } 50 | int[] nextArr = new int[ms.length]; 51 | nextArr[0] = -1; 52 | nextArr[1] = 0; 53 | int pos = 2; 54 | int cn = 0; 55 | while(pos < nextArr.length){ 56 | if(ms[pos - 1] == ms[cn]){ 57 | nextArr[pos++] = ++cn; 58 | }else if(cn > 0){ 59 | cn = nextArr[cn]; 60 | }else{ 61 | nextArr[pos++] = 0; 62 | } 63 | } 64 | return nextArr; 65 | } 66 | 67 | private String serialByPre(TreeNode head) { 68 | if(head == null){ 69 | return "#!"; 70 | } 71 | 72 | String res = head.val + "!"; 73 | res += serialByPre(head.left); 74 | res += serialByPre(head.right); 75 | return res; 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_03.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * 对于两个字符串A和B,如果A和B中出现的字符种类相同且每种字符出现的次数相同,则A和B互为变形词,请设计一个高效算法,检查两给定串是否互为变形词。 5 | 6 | 给定两个字符串A和B及他们的长度,请返回一个bool值,代表他们是否互为变形词。 7 | 8 | 测试样例: 9 | "abc",3,"bca",3 10 | 返回:true 11 | */ 12 | import java.util.*; 13 | 14 | public class Transform { 15 | public boolean chkTransform(String A, int lena, String B, int lenb) { 16 | // write code here 17 | HashMap map = new HashMap(); 18 | char[] a = A.toCharArray(); 19 | char[] b = B.toCharArray(); 20 | for (int i = 0; i < a.length; i++) { 21 | if (!map.containsKey(a[i])) { 22 | map.put(a[i], 1); 23 | } else { 24 | map.put(a[i], map.get(a[i]) + 1); 25 | } 26 | } 27 | for (int i = 0; i < b.length; i++) { 28 | if (!map.containsKey(b[i])) { 29 | return false; 30 | } 31 | if (map.get(b[i]) == 0) { 32 | return false; 33 | } 34 | map.put(b[i], map.get(b[i]) - 1); 35 | } 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_03_best.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * 对于两个字符串A和B,如果A和B中出现的字符种类相同且每种字符出现的次数相同,则A和B互为变形词,请设计一个高效算法,检查两给定串是否互为变形词。 5 | 6 | 给定两个字符串A和B及他们的长度,请返回一个bool值,代表他们是否互为变形词。 7 | 8 | 测试样例: 9 | "abc",3,"bca",3 10 | 返回:true 11 | */ 12 | 13 | public class Transform { 14 | public boolean chkTransform(String A, int lena, String B, int lenb) { 15 | // write code here 16 | char[] a = A.toCharArray(); 17 | char[] b = B.toCharArray(); 18 | int[] map = new int[256]; 19 | for (int i = 0; i < a.length; i++) { 20 | map[a[i] - ' ']++; 21 | } 22 | for (int i = 0; i < b.length; i++) { 23 | map[b[i] - ' ']--; 24 | if (map[b[i] - ' '] < 0) { 25 | return false; 26 | } 27 | } 28 | return true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_05.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 如果对于一个字符串A,将A的前面任意一部分挪到后边去形成的字符串称为A的旋转词。比如A="12345",A的旋转词有"12345","23451","34512","45123"和"51234"。对于两个字符串A和B,请判断A和B是否互为旋转词。 6 | 7 | 给定两个字符串A和B及他们的长度lena,lenb,请返回一个bool值,代表他们是否互为旋转词。 8 | 9 | 测试样例: 10 | "cdab",4,"abcd",4 11 | 返回:true 12 | */ 13 | 14 | public class Rotation { 15 | public boolean chkRotation(String A, int lena, String B, int lenb) { 16 | // write code here 17 | if (lena != lenb) { 18 | return false; 19 | } 20 | String str = A + A; 21 | for (int i = 0; i < str.length(); i++) { 22 | int start = i; 23 | for (int j = 0; j < B.length(); j++) { 24 | if (B.charAt(j) != str.charAt(start + j)) { 25 | break; 26 | } 27 | if (j == B.length() - 1) { 28 | return true; 29 | } 30 | } 31 | } 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_06.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 对于一个字符串,请设计一个算法,只在字符串的单词间做逆序调整,也就是说,字符串由一些由空格分隔的部分组成,你需要将这些部分逆序。 6 | 7 | 给定一个原字符串A和他的长度,请返回逆序后的字符串。 8 | 9 | 测试样例: 10 | "dog loves pig",13 11 | 返回:"pig loves dog" 12 | 13 | */ 14 | 15 | public class Reverse { 16 | public String reverseSentence(String A, int n) { 17 | // write code here 18 | char[] chars = A.toCharArray(); 19 | int start = -1; 20 | for (int i = 1; i < chars.length; i++) { 21 | if (chars[i] == ' ') { 22 | reverseCharArray(chars, start + 1, i); 23 | start = i; 24 | } 25 | } 26 | //if (start < chars.length - 1) { 27 | // reverseCharArray(chars, start + 1, chars.length); 28 | //} 29 | reverseCharArray(chars, start + 1, chars.length); 30 | reverseCharArray(chars, 0, chars.length); 31 | return String.valueOf(chars); 32 | } 33 | public void reverseCharArray(char[] chars, int i, int j) { 34 | while (i < j - 1) { 35 | char temp = chars[i]; 36 | chars[i] = chars[j - 1]; 37 | chars[j - 1] = temp; 38 | i++; 39 | j--; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_07.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 对于一个字符串,请设计一个算法,将字符串的长度为len的前缀平移到字符串的最后。 6 | 7 | 给定一个字符串A和它的长度,同时给定len,请返回平移后的字符串。 8 | 9 | 测试样例: 10 | "ABCDE",5,3 11 | 返回:"DEABC" 12 | */ 13 | 14 | public class Translation { 15 | public String stringTranslation(String A, int n, int len) { 16 | // write code here 17 | char[] a = A.toCharArray(); 18 | reverseChars(a, 0, len); 19 | reverseChars(a, len, n); 20 | reverseChars(a, 0, a.length); 21 | return String.valueOf(a); 22 | } 23 | public void reverseChars(char[] chars, int i , int j) { 24 | while (i < j - 1) { 25 | char temp = chars[i]; 26 | chars[i] = chars[j - 1]; 27 | chars[j - 1] = temp; 28 | i++; 29 | j--; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_08.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 对于一个给定的字符串数组,请找到一种拼接顺序,使所有小字符串拼接成的大字符串是所有可能的拼接中字典序最小的。 6 | 7 | 给定一个字符串数组strs,同时给定它的大小,请返回拼接成的串。 8 | 9 | 测试样例: 10 | ["abc","de"],2 11 | "abcde" 12 | */ 13 | import java.util.*; 14 | 15 | public class Prior { 16 | public String findSmallest(String[] strs, int n) { 17 | // write code here 18 | if (strs == null || strs.length == 0) { 19 | return null; 20 | } 21 | Arrays.sort(strs, new Comparator() { 22 | public int compare(String s1, String s2) { 23 | return (s1 + s2).compareTo(s2 + s1); 24 | } 25 | }); 26 | // ??? 27 | // Arrays.sort(strs, (String s1, String s2) -> (s2 + s1).compareTo(s1 + s2)); 28 | StringBuilder sb = new StringBuilder(); 29 | for (int i = 0; i < strs.length; i++) { 30 | sb.append(strs[i]); 31 | } 32 | return sb.toString(); 33 | } 34 | } 35 | 36 | import java.util.*; 37 | 38 | public class Prior { 39 | public class MyComparator implements Comparator { 40 | public int compare(String a, String b) { 41 | return (a + b).compareTo(b + a); 42 | } 43 | } 44 | 45 | public String findSmallest(String[] strs, int n) { 46 | if (strs == null || n == 0) { 47 | return ""; 48 | } 49 | // 根据新的比较方式排序 50 | Arrays.sort(strs, new MyComparator()); 51 | StringBuilder res = new StringBuilder(); 52 | for (String str:strs) { 53 | res.append(str); 54 | } 55 | return res.toString(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_10.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 请编写一个方法,将字符串中的空格全部替换为“%20”。假定该字符串有足够的空间存放新增的字符,并且知道字符串的真实长度(小于等于1000),同时保证字符串由大小写的英文字母组成。 6 | 7 | 给定一个string iniString 为原始的串,以及串的长度 int len, 返回替换后的string。 8 | 9 | 测试样例: 10 | "Mr John Smith”,13 11 | 返回:"Mr%20John%20Smith" 12 | ”Hello World”,12 13 | 返回:”Hello%20%20World” 14 | */ 15 | 16 | public class Replacement { 17 | public String replaceSpace(String iniString, int length) { 18 | // write code here 19 | int count = 0; 20 | for (int i = 0; i < iniString.length(); i++) { 21 | if (iniString.charAt(i) == ' ') { 22 | count++; 23 | } 24 | } 25 | char[] str = {'%', '2', '0'}; 26 | char[] res = new char[iniString.length() + count * (str.length - 1)]; 27 | count = 0; 28 | for (int i = 0; i < iniString.length(); i++) { 29 | if (iniString.charAt(i) != ' ') { 30 | res[i + count * (str.length - 1)] = iniString.charAt(i); 31 | } else { 32 | for (int j = 0; j < str.length; j++) { 33 | res[i + count * (str.length - 1) + j] = str[j]; 34 | } 35 | count++; 36 | } 37 | } 38 | return String.valueOf(res); 39 | } 40 | } 41 | 42 | 43 | 44 | import java.util.*; 45 | 46 | public class Replacement { 47 | public String replaceSpace(String iniString, int length) { 48 | // write code here 49 | int count = 0; 50 | for (int i = 0; i < iniString.length(); i++) { 51 | if (iniString.charAt(i) == ' ') { 52 | count++; 53 | } 54 | } 55 | char[] str = {'%', '2', '0'}; 56 | char[] res = new char[iniString.length() + count * (str.length - 1)]; 57 | int j = res.length - 1; 58 | for (int i = iniString.length() - 1; i >= 0; i--) { 59 | if (iniString.charAt(i) != ' ') { 60 | res[j] = iniString.charAt(i); 61 | j--; 62 | } else { 63 | res[j - 2] = '%'; 64 | res[j - 1] = '2'; 65 | res[j] = '0'; 66 | j -= 3; 67 | } 68 | } 69 | return String.valueOf(res); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /nowcoder/chap03_string/string_3_11.java: -------------------------------------------------------------------------------- 1 | package chap03_string; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 对于一个字符串,请设计一个算法,判断其是否为一个合法的括号串。 6 | 7 | 给定一个字符串A和它的长度n,请返回一个bool值代表它是否为一个合法的括号串。 8 | 9 | 测试样例: 10 | "(()())",6 11 | 返回:true 12 | 测试样例: 13 | "()a()()",7 14 | 返回:false 15 | 测试样例: 16 | "()(()()",7 17 | 返回:false 18 | 19 | */ 20 | 21 | public class Parenthesis { 22 | public boolean chkParenthesis(String A, int n) { 23 | // write code here 24 | int num = 0; 25 | for (int i = 0; i < A.length(); i++) { 26 | if (A.charAt(i) == '(') { 27 | num++; 28 | } else if (A.charAt(i) == ')') { 29 | num--; 30 | } 31 | if (num < 0) { 32 | return false; 33 | } 34 | } 35 | return num == 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap04_stack_queue/img1.png -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap04_stack_queue/img2.png -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/readme.md: -------------------------------------------------------------------------------- 1 | 栈和队列的基本性质 2 | 3 | 先进先出 4 | 先进后出 5 | 6 | 实现方式 7 | 8 | 数组实现,比较容易 9 | 链表实现, 10 | 11 | 12 | 栈的操作 操作时间复杂度为O(1) 13 | 14 | pop 15 | top peek 16 | push 17 | size 18 | 19 | 队列操作 20 | 类似,只是顺序不同 21 | 22 | 双端队列 23 | 优先级队列,不是一种先线性结构,实际是一种堆的结构 24 | 25 | 深度优先遍历(DFS)和 广度优先遍历(BFS) 26 | 对应的是栈和队列的操作。 27 | -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/stack_4_02.java: -------------------------------------------------------------------------------- 1 | package chap04_stack_queue; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。 6 | 7 | */ 8 | import java.util.Stack; 9 | 10 | public class Solution { 11 | private Stack stack = new Stack(); 12 | private Stack ministack = new Stack(); 13 | 14 | public void push(int node) { 15 | if (ministack.isEmpty() || ministack.peek() >= node) { 16 | ministack.push(node); 17 | } 18 | stack.push(node); 19 | } 20 | 21 | public void pop() { 22 | if (ministack.isEmpty()) { 23 | throw new RuntimeException("Your stack is empty!"); 24 | } 25 | if (ministack.peek() == stack.peek()) { 26 | ministack.pop(); 27 | } 28 | stack.pop(); 29 | } 30 | 31 | public int top() { 32 | return stack.peek(); 33 | } 34 | 35 | public int min() { 36 | if (ministack.isEmpty()) { 37 | throw new RuntimeException("Your stack is empty!"); 38 | } 39 | return ministack.peek(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/stack_4_04.java: -------------------------------------------------------------------------------- 1 | package chap04_stack_queue; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 编写一个类,只能用两个栈结构实现队列,支持队列的基本操作(push,pop)。 6 | 7 | 给定一个操作序列ope及它的长度n,其中元素为正数代表push操作,为0代表pop操作,保证操作序列合法且一定含pop操作,请返回pop的结果序列。 8 | 9 | 测试样例: 10 | [1,2,3,0,4,0],6 11 | 返回:[1,2] 12 | */ 13 | import java.util.*; 14 | 15 | public class TwoStack { 16 | private Stack stack1 = new Stack(); 17 | private Stack stack2 = new Stack(); 18 | private boolean sign = true; // true, use stack1. 19 | public int pop() { 20 | if (sign) { 21 | while (!stack1.isEmpty()) { 22 | stack2.push(stack1.pop()); 23 | } 24 | sign = !sign; 25 | } 26 | return stack2.pop(); 27 | } 28 | public void push(int num) { 29 | if (!sign) { 30 | while (!stack2.isEmpty()) { 31 | stack1.push(stack2.pop()); 32 | } 33 | sign = !sign; 34 | } 35 | stack1.push(num); 36 | } 37 | public int[] twoStack(int[] ope, int n) { 38 | // write code here 39 | ArrayList list = new ArrayList<>(); 40 | for (int num: ope) { 41 | if (num > 0) { 42 | push(num); 43 | } else { 44 | list.add(pop()); 45 | } 46 | } 47 | int[] res = new int[list.size()]; 48 | for (int i = 0; i < list.size(); i++) { 49 | res[i] = list.get(i); 50 | } 51 | return res; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/stack_4_05.java: -------------------------------------------------------------------------------- 1 | package chap04_stack_queue; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 实现一个栈的逆序,但是只能用递归函数和这个栈本身的pop操作来实现,而不能自己申请另外的数据结构。 6 | 7 | 给定一个整数数组A即为给定的栈,同时给定它的大小n,请返回逆序后的栈。 8 | 9 | 测试样例: 10 | [4,3,2,1],4 11 | 返回:[1,2,3,4] 12 | */ 13 | import java.util.*; 14 | 15 | public class StackReverse { 16 | public int[] reverseStack(int[] A, int n) { 17 | // write code here 18 | if (A == null || n == 1) { 19 | return A; 20 | } 21 | int last = getLast(A, n); 22 | reverseStack(A, n - 1); 23 | A[n - 1] = last; 24 | return A; 25 | } 26 | public int getLast(int[] A, int n) { 27 | int num = A[n - 1]; 28 | n--; 29 | if (n == 0) { 30 | return num; 31 | } 32 | int bottom = getLast(A, n); 33 | A[n - 1] = num; 34 | return bottom; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/stack_4_06.java: -------------------------------------------------------------------------------- 1 | package chap04_stack_queue; 2 | 3 | /** 4 | * Created by xing on 4/27/17. 5 | * 请编写一个程序,按升序对栈进行排序(即最大元素位于栈顶),要求最多只能使用一个额外的栈存放临时数据,但不得将元素复制到别的数据结构中。 6 | 7 | 给定一个int[] numbers(C++中为vector),其中第一个元素为栈顶,请返回排序后的栈。请注意这是一个栈,意味着排序过程中你只能访问到第一个元素。 8 | 9 | 测试样例: 10 | [1,2,3,4,5] 11 | 返回:[5,4,3,2,1] 12 | */ 13 | import java.util.*; 14 | 15 | public class TwoStacks { 16 | public ArrayList twoStacksSort(int[] numbers) { 17 | // write code here 18 | ArrayList list = new ArrayList<>(); 19 | int num; 20 | int i = numbers.length - 1; 21 | int j = -1; 22 | while (i >= 0) { 23 | num = numbers[i--]; 24 | while (j >= 0 && num > list.get(j)) { 25 | numbers[++i] = list.get(j--); 26 | } 27 | j++; 28 | if (list.size() < j + 1) { 29 | list.add(num); 30 | } else { 31 | list.set(j, num); 32 | } 33 | } 34 | return list; 35 | } 36 | } 37 | 38 | 39 | 40 | import java.util.*; 41 | 42 | public class TwoStacks { 43 | public ArrayList twoStacksSort(int[] numbers) { 44 | // write code here 45 | int[] stack = new int[numbers.length]; 46 | int num; 47 | int m = numbers.length - 1; // index of numbers array 48 | int n = -1; // index of auxiliary stack 49 | while (m >= 0) { 50 | num = numbers[m--]; 51 | // cannot push to the stack, but we can pop some firstly. 52 | while (n >= 0 && num < stack[n]) { 53 | numbers[++m] = stack[n--]; 54 | } 55 | stack[++n] = num; 56 | } 57 | ArrayList list = new ArrayList<>(); 58 | for (int i = numbers.length - 1; i >= 0; i--) { 59 | list.add(stack[i]); 60 | } 61 | return list; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/stack_4_08.java: -------------------------------------------------------------------------------- 1 | package chap04_stack_queue; 2 | 3 | /** 4 | * Created by xing on 4/28/17. 5 | * 有一个整型数组 arr 和一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。 返回一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值。 以数组为[4,3,5,4,3,3,6,7],w=3为例。因为第一个窗口[4,3,5]的最大值为5,第二个窗口[3,5,4]的最大值为5,第三个窗口[5,4,3]的最大值为5。第四个窗口[4,3,3]的最大值为4。第五个窗口[3,3,6]的最大值为6。第六个窗口[3,6,7]的最大值为7。所以最终返回[5,5,5,4,6,7]。 6 | 7 | 给定整形数组arr及它的大小n,同时给定w,请返回res数组。保证w小于等于n,同时保证数组大小小于等于500。 8 | 9 | 测试样例: 10 | [4,3,5,4,3,3,6,7],8,3 11 | 返回:[5,5,5,4,6,7] 12 | */ 13 | import java.util.*; 14 | 15 | public class SlideWindow { 16 | public int[] slide(int[] arr, int n, int w) { 17 | // write code here 18 | int[] res = new int[arr.length - w + 1]; 19 | if (arr == null || w > n) { 20 | return res; 21 | } 22 | Deque deque = new LinkedList(); 23 | for (int i = 0; i < arr.length; i++) { 24 | // 尾部删除元素 25 | if (!deque.isEmpty() && deque.peekLast() <= i - w) { 26 | deque.pollLast(); 27 | } 28 | // 头部删除元素 29 | while (!deque.isEmpty() && arr[deque.peekFirst()] < arr[i]) { 30 | deque.pollFirst(); 31 | } 32 | // 头部添加元素, 只添加更大的元素 33 | if (deque.isEmpty() || arr[deque.peekFirst()] >= arr[i]) { 34 | deque.offerFirst(i); 35 | } 36 | // 37 | if (i >= w - 1) { 38 | res[i - w + 1] = arr[deque.peekLast()]; 39 | } 40 | } 41 | return res; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /nowcoder/chap04_stack_queue/stack_4_09.java: -------------------------------------------------------------------------------- 1 | package chap04_stack_queue; 2 | 3 | /** 4 | * Created by xing on 4/28/17. 5 | * 对于一个没有重复元素的整数数组,请用其中元素构造一棵MaxTree,MaxTree定义为一棵二叉树,其中的节点与数组元素一一对应,同时对于MaxTree的每棵子树,它的根的元素值为子树的最大值。现有一建树方法,对于数组中的每个元素,其在树中的父亲为数组中它左边比它大的第一个数和右边比它大的第一个数中更小的一个。若两边都不存在比它大的数,那么它就是树根。请设计O(n)的算法实现这个方法。 6 | 7 | 给定一个无重复元素的数组A和它的大小n,请返回一个数组,其中每个元素为原数组中对应位置元素在树中的父亲节点的编号,若为根则值为-1。 8 | 9 | 测试样例: 10 | [3,1,4,2],4 11 | 返回:[2,0,-1,2] 12 | 13 | 解题注释: 14 | 1. MaxTree是一颗二叉树,数组的每个值对应的一个二叉树节点 15 | 2. 包括MaxTree树在内且在其中的每一颗子树上,值最大的节点都是树节点 16 | 解题思路: 17 | 找出每个元素左右第一个大的数,然后将其中较校的数作为父节点建立MaxTree 18 | 题目要求返回数组,每个元素为父亲节点编号,因此只需要找到每个节点的父节点即可。找每个点父节点的时候需要用到栈结构。 19 | */ 20 | import java.util.*; 21 | 22 | public class MaxTree { 23 | public int[] buildMaxTree(int[] A, int n) { 24 | // write code here 25 | int[] res = new int[A.length]; 26 | Stack stack = new Stack(); 27 | // 找到左边大于该值的下标 28 | for (int i = 0; i < A.length; i++) { 29 | // 栈中元素值必须top < bottom 30 | while (!stack.isEmpty() && A[stack.peek()] < A[i]) { 31 | stack.pop(); 32 | } 33 | if (stack.isEmpty()) { 34 | res[i] = -1; 35 | } else { 36 | res[i] = stack.peek(); 37 | } 38 | stack.push(i); 39 | } 40 | stack.clear(); 41 | // 找到左右两边大于该值中较小的那个的下标。 42 | for (int i = A.length - 1; i >= 0; i--) { 43 | while (!stack.isEmpty() && A[stack.peek()] < A[i]) { 44 | stack.pop(); 45 | } 46 | // 当前找不到最右边的第一个大于的值的时候,即stack 为空时,直接采用左边找到比它大值的下表。 47 | // stack非空时,如果左边没有较大值,或者右边找到更小值,更新数组。 48 | if (!stack.isEmpty() && (res[i] == -1 || A[stack.peek()] < A[res[i]]) ){ 49 | // 找到左右两边中较小那个值的下标 50 | res[i] = stack.peek(); 51 | } 52 | stack.push(i); 53 | } 54 | return res; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_02.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/28/17. 5 | 有一个整数val,如何在节点值有序的环形链表中插入一个节点值为val的节点,并且保证这个环形单链表依然有序。 6 | 7 | 给定链表的信息,及元素的值A及对应的nxt指向的元素编号同时给定val,请构造出这个环形链表,并插入该值。 8 | 9 | 测试样例: 10 | [1,3,4,5,7],[1,2,3,4,0],2 11 | 返回:{1,2,3,4,5,7} 12 | */ 13 | import java.util.*; 14 | 15 | /* 16 | public class ListNode { 17 | int val; 18 | ListNode next = null; 19 | 20 | ListNode(int val) { 21 | this.val = val; 22 | } 23 | }*/ 24 | public class InsertValue { 25 | public ListNode insert(int[] A, int[] nxt, int val) { 26 | // write code here 27 | if (A == null || A.length == 0) { 28 | return new ListNode(val); 29 | } 30 | // 建立环形链表 31 | ListNode root = new ListNode(A[0]); 32 | root.next = root; 33 | ListNode cur = root; 34 | for (int i = 0; i < A.length - 1; i++) { 35 | ListNode node = new ListNode(A[nxt[i]]); 36 | // 在这个题目这里并不需要设置next指针,否则出现“输出超限:您的程序打印了太多的内容” 的奇怪错误。 37 | //node.next = cur.next; 38 | cur.next = node; 39 | cur = cur.next; 40 | } 41 | // 插入操作 42 | ListNode pre = root; 43 | ListNode next = root.next; 44 | ListNode node = new ListNode(val); 45 | if (root.val >= val) { 46 | node.next = root; 47 | //cur.next = node; 48 | return node; 49 | } 50 | while (next != null && val > next.val) { 51 | pre = next; 52 | next = next.next; 53 | } 54 | node.next = next; 55 | pre.next = node; 56 | return root; 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_03.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/28/17. 5 | * 实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。 6 | 7 | 给定带删除的节点,请执行删除操作,若该节点为尾节点,返回false,否则返回true 8 | 9 | 注意: 10 | 这一题题目出的有点问题。 11 | 12 | */ 13 | import java.util.*; 14 | 15 | /* 16 | public class ListNode { 17 | int val; 18 | ListNode next = null; 19 | 20 | ListNode(int val) { 21 | this.val = val; 22 | } 23 | }*/ 24 | public class Remove { 25 | public boolean removeNode(ListNode pNode) { 26 | // write code here 27 | if (pNode == null || pNode.next == null) { 28 | return false; 29 | } 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_05.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/28/17. 5 | * 对于一个链表,我们需要用一个特定阈值完成对它的分化,使得小于等于这个值的结点移到前面,大于该值的结点在后面,同时保证两类结点内部的位置关系不变。 6 | 7 | 给定一个链表的头结点head,同时给定阈值val,请返回一个链表,使小于等于它的结点在前,大于等于它的在后,保证结点值不重复。 8 | 9 | 测试样例: 10 | {1,4,2,5},3 11 | {1,2,4,5} 12 | */ 13 | import java.util.*; 14 | 15 | /* 16 | public class ListNode { 17 | int val; 18 | ListNode next = null; 19 | 20 | ListNode(int val) { 21 | this.val = val; 22 | } 23 | }*/ 24 | public class Divide { 25 | public ListNode listDivide(ListNode head, int val) { 26 | // write code here 27 | // 为原始链表建立dummy节点 28 | ListNode dummy = new ListNode(-1); 29 | ListNode pre = dummy; 30 | dummy.next = head; 31 | // 为大于值的链表建立dummy节点 32 | ListNode dummyMax = new ListNode(-1); 33 | ListNode large = dummyMax; 34 | while (head != null) { 35 | if (head.val > val) { 36 | // 移动大于值的链表 37 | large.next = head; 38 | large = large.next; 39 | // 处理小于值的链表 40 | pre.next = head.next; 41 | } else { 42 | pre = head; 43 | } 44 | head = head.next; 45 | } 46 | large.next = null; 47 | pre.next = dummyMax.next; 48 | return dummy.next; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_06.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/28/17. 5 | * 现有两个升序链表,且链表中均无重复元素。请设计一个高效的算法,打印两个链表的公共值部分。 6 | 7 | 给定两个链表的头指针headA和headB,请返回一个vector,元素为两个链表的公共部分。请保证返回数组的升序。两个链表的元素个数均小于等于500。保证一定有公共值 8 | 9 | 测试样例: 10 | {1,2,3,4,5,6,7},{2,4,6,8,10} 11 | 返回:[2.4.6] 12 | */ 13 | import java.util.*; 14 | 15 | /* 16 | public class ListNode { 17 | int val; 18 | ListNode next = null; 19 | 20 | ListNode(int val) { 21 | this.val = val; 22 | } 23 | }*/ 24 | public class Common { 25 | public int[] findCommonParts(ListNode headA, ListNode headB) { 26 | // write code here 27 | ArrayList list = new ArrayList(); 28 | while (headA != null && headB != null) { 29 | if (headA.val == headB.val) { 30 | list.add(headA.val); 31 | headA = headA.next; 32 | headB = headB.next; 33 | } else if (headA.val < headB.val) { 34 | headA = headA.next; 35 | } else { 36 | headB = headB.next; 37 | } 38 | } 39 | int[] res = new int[list.size()]; 40 | for (int i = 0; i < list.size(); i++) { 41 | res[i] = list.get(i); 42 | } 43 | return res; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_07.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/28/17. 5 | * 有一个单链表,请设计一个算法,使得每K个节点之间逆序,如果最后不够K个节点一组,则不调整最后几个节点。例如链表1->2->3->4->5->6->7->8->null,K=3这个例子。调整后为,3->2->1->6->5->4->7->8->null。因为K==3,所以每三个节点之间逆序,但其中的7,8不调整,因为只有两个节点不够一组。 6 | 7 | 给定一个单链表的头指针head,同时给定K值,返回逆序后的链表的头指针。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class ListNode { 13 | int val; 14 | ListNode next = null; 15 | 16 | ListNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | 21 | // 递归方法求解 22 | public class KInverse { 23 | public ListNode inverse(ListNode head, int k) { 24 | // write code here 25 | ListNode cur = head; 26 | int count = 0; 27 | while(cur != null && count != k) { 28 | cur = cur.next; 29 | count++; 30 | } 31 | //此时cur为第k+1个节点 32 | if (count == k) { 33 | cur = inverse(cur,k); 34 | // 下面这个图展示了节点指向的顺序. 每次将头结点放置在cur节点之前。 35 | // head tmp cur 36 | // [ 1 ] -> [ 2 ] -> .. [ n ] -> [ y ] -> ... 37 | // cur 38 | // [ 1 ] -> [ y ] -> ... 39 | // head 40 | // [ 2 ] -> .. -> [ n ] 41 | while(count-- >0) { 42 | ListNode tmp = head.next; 43 | head.next = cur; 44 | cur = head; 45 | head = tmp; 46 | } 47 | //cur为翻转后的第一个节点 48 | head = cur; 49 | } 50 | return head; 51 | } 52 | } 53 | 54 | // 这是不符合题目的代码,只逆序了前面k个节点。节点不够时候依然反转 55 | public class KInverse { 56 | public ListNode inverse(ListNode head, int k) { 57 | // write code here 58 | ListNode dummy = new ListNode(-1); 59 | ListNode last = dummy; 60 | while (k > 0 && head != null) { 61 | // insert into dummy node 62 | last = dummy.next; 63 | dummy.next = head; 64 | head = head.next; 65 | dummy.next.next = last; 66 | k--; 67 | } 68 | while (last.next != null) { 69 | last = last.next; 70 | } 71 | last.next = head; 72 | return dummy.next; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_08.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 现在有一个单链表。链表中每个节点保存一个整数,再给定一个值val,把所有等于val的节点删掉。 6 | 7 | 给定一个单链表的头结点head,同时给定一个值val,请返回清除后的链表的头结点,保证链表中有不等于该值的其它值。请保证其他元素的相对顺序。 8 | 9 | 测试样例: 10 | {1,2,3,4,3,2,1},2 11 | {1,3,4,3,1} 12 | */ 13 | import java.util.*; 14 | 15 | /* 16 | public class ListNode { 17 | int val; 18 | ListNode next = null; 19 | 20 | ListNode(int val) { 21 | this.val = val; 22 | } 23 | }*/ 24 | public class ClearValue { 25 | public ListNode clear(ListNode head, int val) { 26 | // write code here 27 | ListNode dummy = new ListNode(-1); 28 | ListNode cur = dummy; 29 | while (head != null) { 30 | if (head.val == val) { 31 | head = head.next; 32 | } else { 33 | cur.next = head; 34 | head = head.next; 35 | cur = cur.next; 36 | } 37 | } 38 | cur.next = null; 39 | return dummy.next; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_09.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 请编写一个函数,检查链表是否为回文。 6 | 7 | 给定一个链表ListNode* pHead,请返回一个bool,代表链表是否为回文。 8 | 9 | 测试样例: 10 | {1,2,3,2,1} 11 | 返回:true 12 | {1,2,3,2,3} 13 | 返回:false 14 | 15 | 16 | 注意:此题有多重解法,空间复杂度有区别 17 | (1)用栈结构记录所有节点。然后一次比较。O(N) 18 | (2)快慢指针找到链表中点,然后比较。O(N/2) 19 | (3)快慢指针找到链表中点,然后后半逆序,然后判断。 20 | 21 | https://www.nowcoder.com/study/vod/1/5/4 22 | */ 23 | import java.util.*; 24 | 25 | /* 26 | public class ListNode { 27 | int val; 28 | ListNode next = null; 29 | 30 | ListNode(int val) { 31 | this.val = val; 32 | } 33 | }*/ 34 | // 方法1 35 | public class Palindrome { 36 | public boolean isPalindrome(ListNode pHead) { 37 | // write code here 38 | ListNode cur = pHead; 39 | Stack stack = new Stack(); 40 | while (cur != null) { 41 | stack.push(cur.val); 42 | cur = cur.next; 43 | } 44 | cur = pHead; 45 | while (cur != null) { 46 | if (stack.pop() != cur.val) { 47 | return false; 48 | } 49 | cur = cur.next; 50 | } 51 | return true; 52 | } 53 | } 54 | 55 | // 方法2 56 | public class Palindrome { 57 | public boolean isPalindrome(ListNode pHead) { 58 | // write code here 59 | ListNode fast = pHead; 60 | ListNode slow = pHead; 61 | Stack stack = new Stack(); 62 | while (fast != null && fast.next != null) { 63 | fast = fast.next.next; 64 | stack.push(slow.val); 65 | slow = slow.next; 66 | } 67 | if (fast != null) { 68 | slow = slow.next; 69 | } 70 | while (slow != null) { 71 | if (slow.val != stack.pop()) { 72 | return false; 73 | } 74 | slow = slow.next; 75 | } 76 | if (!stack.isEmpty()) { 77 | return false; 78 | } 79 | return true; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_12.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。 6 | 7 | 给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class ListNode { 13 | int val; 14 | ListNode next = null; 15 | 16 | ListNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | public class ChkLoop { 21 | public int chkLoop(ListNode head, int adjust) { 22 | // write code here 23 | ListNode fast = head; 24 | ListNode slow = head; 25 | while (fast != null && fast.next != null) { 26 | fast = fast.next.next; 27 | slow = slow.next; 28 | if (fast == slow) { 29 | break; 30 | } 31 | } 32 | if (fast == null || fast.next == null) { 33 | return -1; 34 | } 35 | fast = head; 36 | while (fast != slow) { 37 | fast = fast.next; 38 | slow = slow.next; 39 | } 40 | return slow.val; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_13.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 现在有两个无环单链表,若两个链表的长度分别为m和n,请设计一个时间复杂度为O(n + m),额外空间复杂度为O(1)的算法,判断这两个链表是否相交。 6 | 7 | 给定两个链表的头结点headA和headB,请返回一个bool值,代表这两个链表是否相交。保证两个链表长度小于等于500。 8 | 9 | 注意: 只需要查看最后一个节点是否相同即可。 10 | */ 11 | import java.util.*; 12 | 13 | /* 14 | public class ListNode { 15 | int val; 16 | ListNode next = null; 17 | 18 | ListNode(int val) { 19 | this.val = val; 20 | } 21 | }*/ 22 | public class CheckIntersect { 23 | public boolean chkIntersect(ListNode headA, ListNode headB) { 24 | // write code here 25 | if (headA == null || headB == null) { 26 | return false; 27 | } 28 | ListNode cur1 = headA; 29 | while (cur1.next != null) { 30 | cur1 = cur1.next; 31 | } 32 | ListNode cur2 = headB; 33 | while (cur2 != null) { 34 | cur2 = cur2.next; 35 | } 36 | return cur1 == cur2; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/list_5_15.java: -------------------------------------------------------------------------------- 1 | package chap05_linkedlist; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。 6 | 7 | 给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。 8 | 9 | 10 | */ 11 | import java.util.*; 12 | 13 | /* 14 | public class ListNode { 15 | int val; 16 | ListNode next = null; 17 | 18 | ListNode(int val) { 19 | this.val = val; 20 | } 21 | }*/ 22 | public class ChkIntersection { 23 | public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) { 24 | // write code here 25 | ListNode loop1 = getLoopNode(head1); 26 | ListNode loop2 = getLoopNode(head2); 27 | if (loop1 != null && loop2 !=null) { 28 | if (loop1 == loop2) { 29 | return true; 30 | } else { 31 | return checkLoop(loop1, loop2); 32 | } 33 | } else if (loop1 == null || loop2 == null) { 34 | return false; 35 | } else { 36 | return (getLast(head1) == getLast(head2)); 37 | } 38 | } 39 | public boolean checkLoop(ListNode loop1, ListNode loop2) { 40 | // 检查循环链表内部是否相交 41 | ListNode cur = loop1.next; 42 | while (cur != loop1) { 43 | if (cur == loop2) { 44 | return true; 45 | } 46 | cur = cur.next; 47 | } 48 | return false; 49 | } 50 | public ListNode getLast(ListNode head) { 51 | // 获得单链表最后一个节点 52 | ListNode cur = head; 53 | while (cur.next != null) { 54 | cur = cur.next; 55 | } 56 | return cur; 57 | } 58 | public ListNode getLoopNode(ListNode head) { 59 | // 获得循环链表进入循环的位置。 60 | ListNode fast = head; 61 | ListNode slow = head; 62 | while (fast != null && fast.next != null) { 63 | fast = fast.next.next; 64 | slow = slow.next; 65 | if (fast == slow) { 66 | break; 67 | } 68 | } 69 | if (fast == null || fast.next == null) { 70 | return null; 71 | } 72 | fast = head; 73 | while (fast != slow) { 74 | fast = fast.next; 75 | slow = slow.next; 76 | } 77 | return slow; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /nowcoder/chap05_linkedlist/readme.md: -------------------------------------------------------------------------------- 1 | 链表问题算法难度不高,主要是考察代码实现能力。 2 | 指针设计很多操作,需要仔细考虑,容易考虑不周。 3 | 4 | 链表和数组 5 | 6 | 都是一种线性空间 7 | 数组是一段连续的存储空间 8 | 链表空间不保证连续,临时分配空间 9 | 10 | 代码实现关键点 11 | 12 | 链表调整函数的返回值类型,根据要求往往是节点类型 13 | 处理链表过程中,先采用画图的方式理清逻辑。 14 | 链表问题对于边界条件讨论要求严格。头结点,尾节点,空节点等问题 15 | 16 | 17 | 链表插入和删除的注意事项 18 | 19 | 特殊处理链表为空,或者链表长度为1的情况 20 | 注意插入操作的调整过程 21 | 注意删除操作的调整过程 22 | 注意头尾节点和空节点需要特殊处理 23 | 双链表插入和删除类似,需要额外考虑previous指针的指向 24 | 25 | 26 | 单链表的翻转操作 27 | 28 | 大量链表问题可以使用额外数据结构来简化调整过程 29 | 链表问题的最优解往往是不适用额外数据结构的方法 -------------------------------------------------------------------------------- /nowcoder/chap06_BinarySearch/BS_6_02_local_minimum.java: -------------------------------------------------------------------------------- 1 | package chap06_BinarySearch; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 定义局部最小的概念。arr长度为1时,arr[0]是局部最小。 6 | * arr的长度为N(N>1)时,如果arr[0] num) { 24 | hi = mid - 1; 25 | } else if (arr[mid] == num) { 26 | hi = mid; 27 | } else { 28 | lo = mid + 1; 29 | } 30 | } 31 | if (arr[lo] != num) { 32 | return -1; 33 | } 34 | return lo; 35 | } 36 | } 37 | 38 | // 采用二分法模板编写 39 | import java.util.*; 40 | 41 | public class LeftMostAppearance { 42 | public int findPos(int[] arr, int n, int num) { 43 | // write code here 44 | int left = 0; 45 | int right = arr.length - 1; 46 | while (left + 1 < right) { 47 | int mid = left + (right - left) / 2; 48 | if (arr[mid] >= num) { 49 | right = mid; 50 | } else { 51 | left = mid; // left is the most likely position; 52 | } 53 | } 54 | if (arr[left] == num) { 55 | return left; 56 | } else if (arr[right] == num) { 57 | return right; 58 | } 59 | return -1; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /nowcoder/chap06_BinarySearch/BS_6_04_Min_circle.java: -------------------------------------------------------------------------------- 1 | package chap06_BinarySearch; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 对于一个有序循环数组arr,返回arr中的最小值。有序循环数组是指,有序数组左边任意长度的部分放到右边去,右边的部分拿到左边来。比如数组[1,2,3,3,4],是有序循环数组,[4,1,2,3,3]也是。 6 | 7 | 给定数组arr及它的大小n,请返回最小值。 8 | 9 | 测试样例: 10 | [4,1,2,3,3],5 11 | 返回:1 12 | */ 13 | 14 | import java.util.*; 15 | 16 | public class MinValue { 17 | public int getMin(int[] arr, int n) { 18 | // write code here 19 | if (arr == null) { 20 | return Integer.MAX_VALUE; 21 | } 22 | int lo = 0; 23 | int hi = arr.length - 1; 24 | while (lo + 1 < hi) { 25 | int mid = lo + (hi - lo) / 2; 26 | if (arr[lo] < arr[hi]) { 27 | return arr[lo]; 28 | } else if (arr[lo] <= arr[mid]) { // 注意这里必须考虑等号情况。 29 | lo = mid; // 这里可以是lo = mid + 1; 30 | } else { 31 | hi = mid; 32 | } 33 | } 34 | if (arr[lo] < arr[hi]) { 35 | return arr[lo]; 36 | } 37 | return arr[hi]; 38 | } 39 | } -------------------------------------------------------------------------------- /nowcoder/chap06_BinarySearch/BS_6_06_left_pos.java: -------------------------------------------------------------------------------- 1 | package chap06_BinarySearch; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 有一个有序数组arr,其中不含有重复元素,请找到满足arr[i]==i条件的最左的位置。如果所有位置上的数都不满足条件,返回-1。 6 | 7 | 给定有序数组arr及它的大小n,请返回所求值。 8 | 9 | 测试样例: 10 | [-1,0,2,3],4 11 | 返回:2 12 | */ 13 | import java.util.*; 14 | 15 | public class Find { 16 | public int findPos(int[] arr, int n) { 17 | // write code here 18 | int lo = 0; 19 | int hi = arr.length - 1; 20 | while (lo + 1 < hi) { 21 | int mid = lo + (hi - lo) / 2; 22 | if (arr[mid] >= mid) { 23 | hi = mid; 24 | } else { 25 | lo = mid; 26 | } 27 | } 28 | if (arr[lo] == lo) { 29 | return lo; 30 | } else if (arr[hi] == hi) { 31 | return hi; 32 | } 33 | return -1; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nowcoder/chap06_BinarySearch/BS_6_07_Complete_Binary_Tree.java: -------------------------------------------------------------------------------- 1 | package chap06_BinarySearch; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 给定一棵完全二叉树的根节点root,返回这棵树的节点个数。如果完全二叉树的节点数为N,请实现时间复杂度低于O(N)的解法。 6 | 7 | 给定树的根结点root,请返回树的大小。 8 | 9 | 时间复杂度为 O( logN ^2) 10 | */ 11 | import java.util.*; 12 | 13 | /* 14 | public class TreeNode { 15 | int val = 0; 16 | TreeNode left = null; 17 | TreeNode right = null; 18 | public TreeNode(int val) { 19 | this.val = val; 20 | } 21 | }*/ 22 | public class CountNodes { 23 | public int count(TreeNode root) { 24 | // write code here 25 | if (root == null) { 26 | return 0; 27 | } 28 | int level = 0; 29 | int num = 0; 30 | while (root != null) { 31 | level++; 32 | if (height(root.left) >= height(root.right)) { 33 | root = root.left; 34 | } else { 35 | root = root.right; 36 | num++; 37 | } 38 | } 39 | return (1 << level) - 1 + num; 40 | } 41 | public int height(TreeNode root) { 42 | int n = 0; 43 | while (root != null) { 44 | n++; 45 | root = root.left; 46 | } 47 | return n; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /nowcoder/chap06_BinarySearch/BS_Quick_Pow.java: -------------------------------------------------------------------------------- 1 | package chap06_BinarySearch; 2 | 3 | /** 4 | * Created by xing on 4/29/17. 5 | * 如果更快的求一个整数k的n次方。如果两个整数相乘并得到结果的时间复杂度为O(1),得到整数k的N次方的过程请实现时间复杂度为O(logN)的方法。 6 | 7 | 给定k和n,请返回k的n次方,为了防止溢出,请返回结果Mod 1000000007的值。 8 | 9 | 测试样例: 10 | 2,3 11 | 返回:8 12 | 13 | 注意: 如果这里去余的方式跟题目给的方式不一样,那么最后结果可能不一致。 这个OJ不是很靠谱 14 | 15 | */ 16 | import java.util.*; 17 | 18 | public class QuickPower { 19 | public int getPower(int k, int N) { 20 | // write code here 21 | if (N == 0) { 22 | return 1; 23 | } 24 | if (N == 1) { 25 | return k; 26 | } 27 | if (N % 2 == 0) { 28 | long tmp = getPower(k, N / 2); 29 | tmp = (tmp * tmp) % 1000000007; 30 | return (int)tmp; 31 | }else { 32 | long tmp = getPower(k, (N - 1) / 2); 33 | tmp = (tmp * tmp) % 1000000007; 34 | return (int)((tmp * k) % 1000000007); 35 | } 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /nowcoder/chap06_BinarySearch/readme.md: -------------------------------------------------------------------------------- 1 | 二分搜索的常见应用场景。 2 | (1) 有序序列中查找一个数 3 | (2) 只要在每次都可以减少一半的搜索范围,那么就可以用二分法 4 | 5 | 6 | 二分搜索的算法思想不难,但是实现时边界条件极易出错。不妨采用九章算法上的[二分模板](http://www.jiuzhang.com/solutions/binary-search/)进行分析。 7 | 8 | 二分搜索常见题目变化 9 | (1) 给定处理或查找对象不同 10 | (2) 判断条件不同 11 | (3) 返回内容不同 12 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/BST.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/BST.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/LongestDistance1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/LongestDistance1.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/LongestDistance2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/LongestDistance2.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_02_print.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 请用递归方式实现二叉树的先序、中序和后序的遍历打印。 6 | 7 | 给定一个二叉树的根结点root,请依次返回二叉树的先序,中序和后续遍历(二维数组的形式)。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | public TreeNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | public class TreeToSequence { 21 | public int[][] convert(TreeNode root) { 22 | // write code here 23 | ArrayList> list = new ArrayList>(); 24 | for (int i = 0; i < 3; i++) { 25 | list.add(new ArrayList()); 26 | } 27 | preOrder((root), list.get(0)); 28 | inOrder((root), list.get(1)); 29 | postOrder((root), list.get(2)); 30 | int[][] arr = new int[3][list.get(0).size()]; 31 | for (int i = 0; i < 3; i++) { 32 | for (int j = 0; j < list.get(0).size(); j++) { 33 | arr[i][j] = list.get(i).get(j); 34 | } 35 | } 36 | return arr; 37 | } 38 | public void preOrder(TreeNode root, ArrayList res) { 39 | if (root == null) { 40 | return; 41 | } 42 | res.add(root.val); 43 | preOrder(root.left, res); 44 | preOrder(root.right, res); 45 | } 46 | public void inOrder(TreeNode root, ArrayList res) { 47 | if (root == null) { 48 | return; 49 | } 50 | inOrder(root.left, res); 51 | res.add(root.val); 52 | inOrder(root.right, res); 53 | } 54 | public void postOrder(TreeNode root, ArrayList res) { 55 | if (root == null) { 56 | return; 57 | } 58 | postOrder(root.left, res); 59 | postOrder(root.right, res); 60 | res.add(root.val); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_05_LevelTraverse.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 有一棵二叉树,请设计一个算法,按照层次打印这棵二叉树。 6 | 7 | 给定二叉树的根结点root,请返回打印结果,结果按照每一层一个数组进行储存,所有数组的顺序按照层数从上往下,且每一层的数组内元素按照从左往右排列。保证结点数小于等于500。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | public TreeNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | public class TreePrinter { 21 | public int[][] printTree(TreeNode root) { 22 | // write code here 23 | if (root == null) { 24 | return null; 25 | } 26 | ArrayList> res = new ArrayList>(); 27 | levelTraverse(root, 1, res); 28 | int[][] ans = new int[res.size()][]; 29 | for (int i = 0; i < res.size(); i++) { 30 | ans[i] = new int[res.get(i).size()]; 31 | for (int j = 0; j < res.get(i).size(); j++) { 32 | ans[i][j] = res.get(i).get(j); 33 | } 34 | } 35 | return ans; 36 | } 37 | public void levelTraverse(TreeNode root, int level, ArrayList> res) { 38 | if (root == null) { 39 | return; 40 | } 41 | if (res.size() < level) { 42 | res.add(new ArrayList()); 43 | } 44 | res.get(level - 1).add(root.val); 45 | levelTraverse(root.left, level + 1, res); 46 | levelTraverse(root.right, level + 1, res); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_06_serialize.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 首先我们介绍二叉树先序序列化的方式,假设序列化的结果字符串为str,初始时str等于空字符串。先序遍历二叉树,如果遇到空节点,就在str的末尾加上“#!”,“#”表示这个节点为空,节点值不存在,当然你也可以用其他的特殊字符,“!”表示一个值的结束。如果遇到不为空的节点,假设节点值为3,就在str的末尾加上“3!”。现在请你实现树的先序序列化。 6 | 7 | 给定树的根结点root,请返回二叉树序列化后的字符串。 8 | 9 | 测试样例: 10 | */ 11 | import java.util.*; 12 | 13 | /* 14 | public class TreeNode { 15 | int val = 0; 16 | TreeNode left = null; 17 | TreeNode right = null; 18 | public TreeNode(int val) { 19 | this.val = val; 20 | } 21 | }*/ 22 | public class TreeToString { 23 | public String toString(TreeNode root) { 24 | StringBuilder sb = new StringBuilder(); 25 | serialize(root, sb); 26 | return sb.toString(); 27 | } 28 | public void serialize(TreeNode root, StringBuilder sb) { 29 | if (root == null) { 30 | sb.append("#!"); 31 | return; 32 | } 33 | sb.append(root.val + "!"); 34 | serialize(root.left, sb); 35 | serialize(root.right, sb); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_08_Balance.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 有一棵二叉树,请设计一个算法判断这棵二叉树是否为平衡二叉树。 6 | 7 | 给定二叉树的根结点root,请返回一个bool值,代表这棵树是否为平衡二叉树。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | public TreeNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | public class CheckBalance { 21 | public boolean check(TreeNode root) { 22 | // write code here 23 | if (root == null) { 24 | return false; 25 | } 26 | return balanced(root, 0) >= 0; 27 | } 28 | public int balanced(TreeNode root, int level) { 29 | if (root == null) { 30 | return level; 31 | } 32 | int left = balanced(root.left, level + 1); 33 | int right = balanced(root.right, level + 1); 34 | if ( left == -1 || right == -1 || Math.abs(left - right) > 1) { 35 | return -1; 36 | } 37 | return Math.max(left, right); 38 | } 39 | } 40 | 41 | 42 | public class CheckBalance { 43 | public static boolean check (TreeNode root){ 44 | return chk(root) >= 0; 45 | } 46 | 47 | private static int chk (TreeNode root) { 48 | if (root == null) { 49 | return 0; 50 | } 51 | int l = chk(root.left); 52 | int r = chk(root.right);//左右两边深度 53 | if (l < 0 || r < 0) { 54 | return -1; 55 | } 56 | if ((Math.abs(r - l) > 1)) { 57 | return -1;//当左右两边深度差超过1时 返回-1 58 | } 59 | return r > l ? r + 1 : l + 1; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_09_Complete.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 有一棵二叉树,请设计一个算法判断它是否是完全二叉树。 6 | 7 | 给定二叉树的根结点root,请返回一个bool值代表它是否为完全二叉树。树的结点个数小于等于500。 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | public TreeNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | public class CheckCompletion { 21 | public boolean chk(TreeNode root) { 22 | // write code here 23 | if (root == null) { 24 | return false; 25 | } 26 | Queue queue = new LinkedList(); 27 | queue.offer(root); 28 | boolean flag = false; // 表征前面的节点是否已经是叶子节点 29 | while (!queue.isEmpty()) { 30 | int size = queue.size(); 31 | while (size-- != 0) { 32 | TreeNode node = queue.poll(); 33 | if (node.left != null) { 34 | if (flag == true) { 35 | return false; 36 | } 37 | queue.offer(node.left); 38 | if (node.right != null) { 39 | queue.offer(node.right); 40 | } else { 41 | flag = true; 42 | } 43 | } else if (node.right != null) { 44 | return false; 45 | } 46 | } 47 | } 48 | return true; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_11_paper.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 请把纸条竖着放在桌⼦上,然后从纸条的下边向上⽅对折,压出折痕后再展 开。此时有1条折痕,突起的⽅向指向纸条的背⾯,这条折痕叫做“下”折痕 ;突起的⽅向指向纸条正⾯的折痕叫做“上”折痕。如果每次都从下边向上⽅ 对折,对折N次。请从上到下计算出所有折痕的⽅向。 6 | 7 | 给定折的次数n,请返回从上到下的折痕的数组,若为下折痕则对应元素为"down",若为上折痕则为"up". 8 | 9 | 测试样例: 10 | 1 11 | 返回:["down"] 12 | */ 13 | import java.util.*; 14 | 15 | public class FoldPaper { 16 | public String[] foldPaper(int n) { 17 | // write code here 18 | ArrayList list = new ArrayList(); 19 | int times = 1; 20 | boolean down = true; 21 | fold(times, n, down, list); 22 | String[] res = new String[list.size()]; 23 | for (int i = 0; i < list.size(); i++) { 24 | res[i] = list.get(i); 25 | } 26 | return res; 27 | } 28 | public void fold(int times, int n, boolean down, ArrayList list) { 29 | if (times > n) { 30 | return; 31 | } 32 | // 依次加入折痕的左边有和右边 33 | fold(times + 1, n, true, list); 34 | list.add(down == true ? "down" : "up"); 35 | fold(times + 1, n, false, list); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_12_FindError.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树,请找到这两个错误节点并返回他们的值。保证二叉树中结点的值各不相同。 6 | 7 | 给定一棵树的根结点,请返回两个调换了位置的值,其中小的值在前。 8 | 9 | 注意: 此题较难。需要复习中序遍历的非递归形式 10 | */ 11 | import java.util.*; 12 | 13 | /* 14 | public class TreeNode { 15 | int val = 0; 16 | TreeNode left = null; 17 | TreeNode right = null; 18 | public TreeNode(int val) { 19 | this.val = val; 20 | } 21 | }*/ 22 | public class FindErrorNode { 23 | public int[] findError(TreeNode root) { 24 | // write code here 25 | TreeNode[] errs = new TreeNode[2]; 26 | int[] res = new int[2]; 27 | if (root == null) { 28 | return res; 29 | } 30 | Stack stack = new Stack(); 31 | TreeNode pre = null; 32 | while (!stack.isEmpty() || root != null) { 33 | // 遍历左孩子 34 | if (root != null) { 35 | stack.push(root); 36 | root = root.left; 37 | } else { 38 | // 往上遍历 39 | root = stack.pop(); 40 | if (pre != null && pre.val > root.val) { 41 | if (errs[0] == null) { 42 | errs[0] = pre; 43 | } 44 | errs[1] = root; 45 | } 46 | // 设置前驱节点,并遍历右子树 47 | pre = root; 48 | root = root.right; 49 | } 50 | } 51 | res[0] = Math.min(errs[0].val, errs[1].val); 52 | res[1] = Math.max(errs[0].val, errs[1].val); 53 | return res; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_13_LongestDistance.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 从二叉树的节点A出发,可以向上或者向下走,但沿途的节点只能经过一次,当到达节点B时,路径上的节点数叫作A到B的距离。对于给定的一棵二叉树,求整棵树上节点间的最大距离。 6 | 7 | 给定一个二叉树的头结点root,请返回最大距离。保证点数大于等于2小于等于500. 8 | */ 9 | import java.util.*; 10 | 11 | /* 12 | public class TreeNode { 13 | int val = 0; 14 | TreeNode left = null; 15 | TreeNode right = null; 16 | public TreeNode(int val) { 17 | this.val = val; 18 | } 19 | }*/ 20 | // 递归解法,比递归解法简洁很多 21 | public class LongestDistance { 22 | private int longest = 0; // save the longest distance; 23 | public int findLongest(TreeNode root) { 24 | // write code here 25 | int depth = findDist(root); 26 | return longest; 27 | } 28 | public int findDist(TreeNode root) { 29 | if (root == null) { 30 | return 0; 31 | } 32 | int left = findDist(root.left); 33 | int right = findDist(root.right); 34 | longest = Math.max(left + right + 1, longest); 35 | return Math.max(left, right) + 1; 36 | } 37 | } 38 | 39 | 40 | // 非递归解法,用后序遍历 41 | 42 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_14_MaxSubtree.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 有一棵二叉树,其中所有节点的值都不一样,找到含有节点最多 的搜索二叉子树,并返回这棵子树的头节点. 6 | 7 | 给定二叉树的头结点root,请返回所求的头结点,若出现多个节点最多的子树,返回头结点权值最大的。 8 | */ 9 | 10 | // 下面解法摘自java的参考代码,与书商代码相同。 11 | 12 | /** 13 | 以节点node为头的树中,最大的搜索二叉子树只可能来自以下两种情况: 14 | 1.来自node左子树上的最大搜索二叉子树是以node左孩子为头的,并且来自node右子树上的最大搜索二叉子树是以node右孩子为头的 15 | node左子树上的最大搜索二叉子树的最大值小于node的节点值,node右子树上的最大搜索二叉子树的最小值大于node的节点值 16 | 那么以几点node为头的整棵树都是搜索二叉树。 17 | 2.如果不满足第一种情况,说明以节点node为头的树整体不能连城搜索二叉树,这种情况下,以node为头的树上的最大搜索二叉子树是来自node 18 | 的左子树上的最大搜索二叉子树和来自node的有字数上的最大搜索二叉子树之间,节点数较多的哪个。 19 | */ 20 | /** 21 | 具体步骤如下: 22 | 1.整体过程是二叉树的后续遍历 23 | 2.遍历到当前节点记为cur,先遍历cur的左子树并收集4个信息,分别是左子树上,最大搜索二叉子树的头结点,节点数,树上最小值,树上最大值 24 | 再遍历cur的右子树收集4个信息,分别是右子树上最大搜索二叉子树的头结点,节点数,最小值,最大值 25 | 3.根据步骤2所收集的信息,判断是否满足第一种情况,也就是是否以cur为头的子树,整体都是搜索二叉树,如果满足第一种情况,就返回cur节点 26 | 如果满足第二种情况,就返回左子树和右子树各自的最大搜索二叉树中,节点数较多的哪个树的头结点。 27 | 4.对于如何返回4个信息,可以使用全局变量更新的方式,也可以使用数组的方式 28 | */ 29 | 30 | 31 | import java.util.*; 32 | /* 33 | public class TreeNode { 34 | int val = 0; 35 | TreeNode left = null; 36 | TreeNode right = null; 37 | public TreeNode(int val) { 38 | this.val = val; 39 | } 40 | }*/ 41 | public class MaxSubtree { 42 | public TreeNode getMax(TreeNode root) { 43 | // write code here 44 | if(root == null){ 45 | return null; 46 | } 47 | int[] ret = new int[3]; 48 | return postOrder(root,ret); 49 | } 50 | 51 | public TreeNode postOrder(TreeNode root,int[]ret){ 52 | if(root == null){ 53 | ret[0] = Integer.MIN_VALUE; 54 | ret[1] = Integer.MAX_VALUE; 55 | ret[2] = 0; 56 | return null ; 57 | } 58 | TreeNode lnode = postOrder(root.left,ret); 59 | int lmax = ret[0];//0最大值,1最小值,2总结点数 60 | int lmin = ret[1]; 61 | int lnum = ret[2]; 62 | TreeNode rnode = postOrder(root.right,ret); 63 | int rmax = ret[0]; 64 | int rmin = ret[1]; 65 | int rnum = ret[2]; 66 | 67 | ret[0]=Math.max(rmax,root.val);//更新最大值 68 | ret[1]=Math.min(lmin,root.val); 69 | 70 | if(lnode == root.left && rnode == root.right 71 | && lmax < root.val && rmin > root.val){ 72 | ret[2] = rnum + lnum + 1; 73 | return root; 74 | } 75 | ret[2] = Math.max(rnum,lnum); 76 | return rnum >= lnum ? rnode : lnode; // 返回最大搜索子树的节点。 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/Tree_7_validate_BST.java: -------------------------------------------------------------------------------- 1 | package chap07_BinaryTree; 2 | /** 3 | * Definition for a binary tree node. 4 | * public class TreeNode { 5 | * int val; 6 | * TreeNode left; 7 | * TreeNode right; 8 | * TreeNode(int x) { val = x; } 9 | * } 10 | */ 11 | 12 | /** 13 | * 判断一个二叉树是否为二叉搜索树 14 | * DFS, 注意需要用长整型表示最大最小值。 15 | * Interactive method 注意条件的判断。 16 | * @author Xingxing Huang 17 | * @since 2017.04.17 18 | * @Time O(n), 19 | * @param TreeNode 20 | * @return boolean 21 | */ 22 | // recursive simple method 23 | public class Solution { 24 | private TreeNode pre; 25 | public boolean isValidBST(TreeNode root) { 26 | if (root == null) { 27 | return true; 28 | } 29 | if (!isValidBST(root.left)) { 30 | return false; 31 | } 32 | if (pre != null && root.val <= pre.val) { 33 | return false; 34 | } 35 | pre = root; 36 | if (!isValidBST(root.right)) { 37 | return false; 38 | } 39 | return true; 40 | } 41 | } 42 | // iterative method 43 | public class Solution { 44 | public boolean isValidBST(TreeNode root) { 45 | Stack stack = new Stack<>(); 46 | TreeNode pre = null; 47 | while (root != null || !stack.isEmpty()) { 48 | while (root != null) { 49 | stack.push(root); 50 | root = root.left; 51 | } 52 | root = stack.pop(); 53 | if (pre != null && root.val <= pre.val) { 54 | return false; 55 | } 56 | pre = root; 57 | root = root.right; 58 | } 59 | return true; 60 | } 61 | } 62 | // recursive method 63 | public class Solution { 64 | public boolean isValidBST(TreeNode root) { 65 | return helper(root, Long.MIN_VALUE, Long.MAX_VALUE); 66 | } 67 | public boolean helper(TreeNode root, long min, long max) { 68 | if (root == null) { 69 | return true; 70 | } 71 | if (root.val <= min || root.val >= max) { 72 | return false; 73 | } 74 | return (helper(root.left, min, root.val) 75 | && helper(root.right, root.val, max)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/balanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/balanced.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/complete.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/inorder1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/inorder1.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/inorder2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/inorder2.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/maxBST1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/maxBST1.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/maxBST2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/maxBST2.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/paper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/paper.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/postorder1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/postorder1.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/postorder2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/postorder2.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/postorder3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/postorder3.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/preorder1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/preorder1.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/preorder2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap07_BinaryTree/preorder2.png -------------------------------------------------------------------------------- /nowcoder/chap07_BinaryTree/readme.md: -------------------------------------------------------------------------------- 1 | 二叉树类型为常考题型 2 | 1. 结合其他队列,栈,链表,字符等数据结构 3 | 2. 基本遍历方式 4 | 3. 递归函数的应用 5 | 4. 其他实际工作 6 | 需要熟练掌握二叉树各种遍历方式和各种改写能力,对递归的掌握游刃有余!!! 7 | 8 | 二叉树的遍历方法,[牛客网站](https://www.nowcoder.com/study/vod/1/7/1) 9 | ![](./preorder1.png) 10 | ![](./preorder2.png) 11 | ![](./inorder1.png) 12 | ![](./inorder2.png) 13 | ![](./postorder1.png) 14 | ![](./postorder2.png) 15 | ![](./postorder3.png) 16 | 17 | 18 | 二叉树的按层遍历,按层打印 19 | 20 | 二叉树的序列化,反序列化 21 | 22 | 二叉树的类型 23 | 平衡二叉树(AVL树) 24 | 搜索二叉树 注意判断的代码 [lc98](https://leetcode.com/problems/validate-binary-search-tree/#/description) 25 | 完全二叉树 判断方法 26 | 满二叉树 N = 2^L - 1 27 | ![](./balanced.png) 28 | ![](./BST.png) 29 | ![](./complete.png) 30 | 31 | 折纸问题 7-11 32 | ![](./paper.png) 33 | 34 | 寻找错误节点 7-12 35 | 36 | 求节点间的最大距离 7-13 37 | [比较复杂,可以查看视频理解](https://www.nowcoder.com/study/vod/1/7/10) 38 | ![](LongestDistance1.png) 39 | ![](LongestDistance2.png) 40 | 41 | 二叉搜索树的最大子树 7-14 42 | ![](./maxBST1.png) 43 | ![](./maxBST2.png) -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.54.01 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.54.01 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.54.49 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.54.49 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.55.34 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.55.34 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.55.53 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.55.53 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.57.27 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 3.57.27 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 4.01.49 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 4.01.49 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 4.02.13 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 4.02.13 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 4.08.07 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap08_Bit/Screen Shot 2017-04-30 at 4.08.07 PM.png -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/bit_8_03.java: -------------------------------------------------------------------------------- 1 | package chap08_Bit; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 请编写一个算法,不用任何额外变量交换两个整数的值。 6 | 7 | 给定一个数组num,其中包含两个值,请不用任何额外变量交换这两个值,并将交换后的数组返回。 8 | 9 | 测试样例: 10 | [1,2] 11 | 返回:[2,1] 12 | */ 13 | import java.util.*; 14 | 15 | public class Swap { 16 | public int[] getSwap(int[] num) { 17 | // write code here 18 | num[0] = num[0]^num[1]; 19 | num[1] = num[0]^num[1]; 20 | num[0] = num[0]^num[1]; 21 | return num; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/bit_8_04.java: -------------------------------------------------------------------------------- 1 | package chap08_Bit; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 对于两个32位整数a和b,请设计一个算法返回a和b中较大的。但是不能用任何比较判断。若两数相同,返回任意一个。 6 | 7 | 给定两个整数a和b,请返回较大的数。 8 | 9 | 测试样例: 10 | 1,2 11 | 返回:2 12 | */ 13 | import java.util.*; 14 | 15 | public class Compare { 16 | public int sig(int c){ 17 | return ((c >>> 31) & 1)== 0 ? 1 : 0; 18 | } 19 | public int nsig(int c){ 20 | return sig(c) == 0 ? 1 : 0; 21 | } 22 | public int getMax(int a, int b) { 23 | // write code here 24 | int c = a - b; 25 | int sigc = sig(c); 26 | int nsigc = nsig(c); 27 | return a * sigc + nsigc * b; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/bit_8_05.java: -------------------------------------------------------------------------------- 1 | package chap08_Bit; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 有一个整型数组A,其中只有一个数出现了奇数次,其他的数都出现了偶数次,请打印这个数。要求时间复杂度为O(N),额外空间复杂度为O(1)。 6 | 7 | 给定整形数组A及它的大小n,请返回题目所求数字。 8 | 9 | 测试样例: 10 | [1,2,3,2,1],5 11 | 返回:3 12 | */ 13 | import java.util.*; 14 | 15 | public class OddAppearance { 16 | public int findOdd(int[] A, int n) { 17 | // write code here 18 | int num = A[0]; 19 | for (int i = 1; i < A.length; i++) { 20 | num = num ^ A[i]; 21 | } 22 | return num; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/bit_8_06.java: -------------------------------------------------------------------------------- 1 | package chap08_Bit; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 给定一个整型数组arr,其中有两个数出现了奇数次,其他的数都出现了偶数次,找到这两个数。要求时间复杂度为O(N),额外空间复杂度为O(1)。 6 | 7 | 给定一个整形数组arr及它的大小n,请返回一个数组,其中两个元素为两个出现了奇数次的元素,请将他们按从小到大排列。 8 | 9 | 测试样例: 10 | [1,2,4,4,2,1,3,5],8 11 | 返回:[3,5] 12 | */ 13 | import java.util.*; 14 | 15 | public class OddAppearance { 16 | public int[] findOdds(int[] arr, int n) { 17 | // write code here 18 | int num = 0; 19 | for (int i = 0; i < arr.length; i++) { 20 | num = num ^ arr[i]; 21 | } 22 | int bit = 1; 23 | while (((num >> bit) & 1) != 1) { 24 | bit++; 25 | } 26 | int num1 = 0; 27 | for (int i = 0; i < arr.length; i++) { 28 | if (((arr[i] >> bit) & 1) == 1) { 29 | num1 = num1 ^ arr[i]; 30 | } 31 | } 32 | int num2 = num ^ num1; 33 | int[] result = {Math.min(num1, num2), Math.max(num1, num2)}; 34 | return result; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nowcoder/chap08_Bit/readme.md: -------------------------------------------------------------------------------- 1 | 位运算的常见操作符 2 | 3 | & | ^ ~ << >> >>> 4 | 5 | 6 | 不安全网页的黑名单包含100亿个黑名单网页,每个网页的URL最多占用64字节,现在想要实现一种网页过滤系统,可以根据网页的URL判断该网页是否在黑名单上,请设计该系统。 7 | 要求该系统允许有万分之一以下的判断失误率,并且使用的额外空间不要超过30G。 8 | 9 | 一般方法: 10 | 黑名单 存入 哈希表或者数据库 11 | 布隆过滤器:可以精确代表一个集合,判断某一元素是否在集合中 12 | 网页黑名单系统 13 | 垃圾邮件过滤系统 14 | 爬虫网址判断重复系统 15 | +容忍一定的失误率。 16 | 对于给定样本个数n,允许的失误率p,结合公式求出m 17 | m = - n * ln p / (ln 2)^2 18 | 根据已经求得m,计算哈希函数的个数k 19 | k = ln 2 * (m / n) 20 | = 0.7 * (m / n) 21 | 22 | 23 | 【1】用位运算交换两个数的值。采用异或运算求解 24 | n 与 0 异或为n 25 | n 与 n 异或为0 26 | 异或满足交换律和结合律 27 | 28 | 【2】给两个32整数,返回两个数种较大 29 | 30 | 【3】找出整形数组中唯一一个出现奇数次的数。采用异或运算求解 31 | 32 | 【4】找出整形数组中两个出现奇数次的数 33 | eo = a ^ b 34 | 说明a 和 b中某一k位为0 和 1 35 | eo' = 0与arr中第k位为1的那些数进行异或,那么最终结果就为a 或者b 36 | 那么另外一个数为 eo ^ eo' 37 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_02_countWays.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 在XxY的方格中,以左上角格子为起点,右下角格子为终点,每次只能向下走或者向右走,请问一共有多少种不同的走法 6 | 7 | 给定两个正整数int x,int y,请返回走法数目。保证x+y小于等于12。 8 | 9 | 测试样例: 10 | 2,2 11 | 返回:2 12 | */ 13 | import java.util.*; 14 | 15 | public class Robot { 16 | public int countWays(int x, int y) { 17 | // write code here 18 | if (x == 1 && y == 1) { 19 | return 0; 20 | } 21 | int m = x - 1; // 可移动步数 22 | int n = y - 1; 23 | int count1 = 1; 24 | int count2 = 1; 25 | for (int i = 0; i < m; i++) { 26 | count1 *= (m + n - i); 27 | count2 *= i + 1; 28 | } 29 | return count1 / count2; 30 | } 31 | } 32 | 33 | 34 | // 同学代码中的代码 35 | import java.util.*; 36 | 37 | public class Robot { 38 | public int countWays(int x, int y) { 39 | int n = x+y-2; 40 | int m = x-1; 41 | int res = go(n)/(go(m)*go(n-m)); 42 | return res; 43 | } 44 | 45 | private int go(int n) { 46 | int res = 1; 47 | for(int i=1;i<=n;i++){ 48 | res *= i; 49 | } 50 | return res; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_03_StandInLine.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * n个人站队,他们的编号依次从1到n,要求编号为a的人必须在编号为b的人的左边,但不要求一定相邻,请问共有多少种排法?第二问如果要求a必须在b的左边,并且一定要相邻,请问一共有多少种排法? 6 | 7 | 给定人数n及两个人的编号a和b,请返回一个两个元素的数组,其中两个元素依次为两个问题的答案。保证人数小于等于10。 8 | 9 | 测试样例: 10 | 7,1,2 11 | 返回:[2520,720] 12 | */ 13 | import java.util.*; 14 | 15 | public class StandInLine { 16 | public int[] getWays(int n, int a, int b) { 17 | // write code here 18 | int num1 = 1; 19 | int num2 = 1; 20 | for (int i = 0; i < n; i++){ 21 | num1 *= i + 1; 22 | } 23 | num1 /= 2; 24 | num2 = num1 / n * 2; 25 | return new int[] {num1, num2}; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_04_getWays.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * A(A也是他的编号)是一个孤傲的人,在一个n个人(其中编号依次为1到n)的队列中,他于其中的标号为b和标号c的人都有矛盾,所以他不会和他们站在相邻的位置。现在问你满足A的要求的对列有多少种? 6 | 7 | 给定人数n和三个人的标号A,b和c,请返回所求答案,保证人数小于等于11且大于等于3。 8 | 9 | 测试样例: 10 | 6,1,2,3 11 | 288 12 | */ 13 | import java.util.*; 14 | 15 | public class LonelyA { 16 | public int getWays(int n, int A, int b, int c) { 17 | // write code here 18 | // 用总的排列方法,减去ab相邻,ac相邻再加上abc相邻的情况即可 19 | return C(n) - 4 * C(n - 1) + 2 * C(n - 2); 20 | } 21 | private int C(int n) { 22 | int num = 1; 23 | for (int i = 1; i <= n; i++) { 24 | num *= i; 25 | } 26 | return num; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_05_getWays.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * n颗相同的糖果,分给m个人,每人至少一颗,问有多少种分法。 6 | 7 | 给定n和m,请返回方案数,保证n小于等于12,且m小于等于n。 8 | 9 | 测试样例: 10 | 10,3 11 | 返回:36 12 | */ 13 | import java.util.*; 14 | 15 | public class Distribution { 16 | public int getWays(int n, int m) { 17 | // write code here 18 | int ans = 1; 19 | for(int i = 1; i < m; ++i){ 20 | ans = ans * (n - i) / i; 21 | } 22 | return ans; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_07_blanket.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 假设有n对左右括号,请求出合法的排列有多少个?合法是指每一个括号都可以找到与之配对的括号,比如n=1时,()是合法的,但是)(为不合法。 6 | 7 | 给定一个整数n,请返回所求的合法排列数。保证结果在int范围内。 8 | 9 | 测试样例: 10 | 1 11 | 返回:1 12 | */ 13 | import java.util.*; 14 | 15 | public class Parenthesis { 16 | public int countLegalWays(int n) { 17 | // write code here 18 | return C(2*n, n) / (n + 1); 19 | } 20 | public int C(int m, int n) { 21 | int num = 1; 22 | int num2 = 1; 23 | for (int i = 0; i < n; i++) { 24 | num = num * (m - i); 25 | num2 = num2 * (n - i); 26 | } 27 | return num / num2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_08_stack.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * n个数进出栈的顺序有多少种?假设栈的容量无限大。 6 | 7 | 给定一个整数n,请返回所求的进出栈顺序个数。保证结果在int范围内。 8 | 9 | 测试样例: 10 | 1 11 | 返回:1 12 | */ 13 | import java.util.*; 14 | 15 | public class Stack { 16 | public int countWays(int n) { 17 | // write code here 18 | return C(2*n, n) / (n + 1); 19 | } 20 | public int C(int m, int n) { 21 | int num = 1; 22 | int num2 = 1; 23 | for (int i = 0; i < n; i++) { 24 | num = num * (m - i); 25 | num2 = num2 * (n - i); 26 | } 27 | return num / num2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_09_ticket.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 2n个人排队买票,n个人拿5块钱,n个人拿10块钱,票价是5块钱1张,每个人买一张票,售票员手里没有零钱,问有多少种排队方法让售票员可以顺利卖票。 6 | 7 | 给定一个整数n,请返回所求的排队方案个数。保证结果在int范围内。 8 | 9 | 测试样例: 10 | 1 11 | 返回:1 12 | */ 13 | import java.util.*; 14 | 15 | public class BuyTickets { 16 | public int countWays(int n) { 17 | // write code here 18 | return C(2*n, n) / (n + 1); 19 | } 20 | public int C(int m, int n) { 21 | int num = 1; 22 | int num2 = 1; 23 | for (int i = 0; i < n; i++) { 24 | num = num * (m - i); 25 | num2 = num2 * (n - i); 26 | } 27 | return num / num2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_10_TreeCount.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 求n个无差别的节点构成的二叉树有多少种不同的结构? 6 | 7 | 给定一个整数n,请返回不同结构的二叉树的个数。保证结果在int范围内。 8 | 9 | 测试样例: 10 | 1 11 | 返回:1 12 | */ 13 | import java.util.*; 14 | 15 | public class TreeCount { 16 | public int countWays(int n) { 17 | // write code here 18 | return C(2*n, n) / (n + 1); 19 | } 20 | public int C(int m, int n) { 21 | int num = 1; 22 | int num2 = 1; 23 | for (int i = 0; i < n; i++) { 24 | num = num * (m - i); 25 | num2 = num2 * (n - i); 26 | } 27 | return num / num2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_11_HighAndShort.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种? 6 | 7 | 给定一个偶数n,请返回所求的排列方式个数。保证结果在int范围内。 8 | 9 | 测试样例: 10 | 1 11 | 返回:1 12 | */ 13 | import java.util.*; 14 | 15 | public class HighAndShort { 16 | public int countWays(int n) { 17 | // write code here 18 | return C(n, n / 2) / (n / 2 + 1); 19 | } 20 | public int C(int m, int n) { 21 | int num = 1; 22 | int num2 = 1; 23 | for (int i = 0; i < n; i++) { 24 | num = num * (m - i); 25 | num2 = num2 * (n - i); 26 | } 27 | return num / num2; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/PC_9_12_CombineByMistake.java: -------------------------------------------------------------------------------- 1 | package chap09_Permulation_Combination; 2 | 3 | /** 4 | * Created by xing on 5/1/17. 5 | * 有n个信封,包含n封信,现在把信拿出来,再装回去,要求每封信不能装回它原来的信封,问有多少种装法? 6 | 7 | 给定一个整数n,请返回装发个数,为了防止溢出,请返回结果Mod 1000000007的值。保证n的大小小于等于300。 8 | 9 | 测试样例: 10 | 2 11 | 返回:1 12 | */ 13 | import java.util.*; 14 | 15 | public class CombineByMistake { 16 | final static int RANGE = 1000000007; 17 | public int countWays(int n) { 18 | // write code here 19 | if (n == 1) { 20 | return 0; 21 | } 22 | int[] f = new int[n + 1]; 23 | f[1] = 0; 24 | f[2] = 1; 25 | //f[3] = 2 * f[2]; 26 | for (int i = 3; i <= n; i++) { 27 | // 第n个信放入第m个信封中,选择有(i - 1)种 28 | // 第m个信封中的信可以放入第n个信封中,也可以不放入。 29 | long res = (f[i - 2] + f[i - 1]) % RANGE; 30 | res = (i - 1) * res % RANGE; 31 | f[i] = (int) res; 32 | } 33 | return f[n]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/Screen Shot 2017-04-30 at 5.24.05 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap09_Permulation_Combination/Screen Shot 2017-04-30 at 5.24.05 PM.png -------------------------------------------------------------------------------- /nowcoder/chap09_Permulation_Combination/readme.md: -------------------------------------------------------------------------------- 1 | 概率组合的题目分类 2 | 古典概率题 3 | 斐波那契数和卡特兰数 4 | 5 | 【1】在6 * 9 的方格中,从左上角到右下角,共有多少种不同走法 6 | C(13, 5) 或者 C(13, 8) ~ 1287 7 | 8 | 【2】七人站队,要求A必须在B的左边,但不要求一定相邻,请问多少种排法。如果要求一定相邻,有多少种解法。 9 | 第一问: 7!/2 10 | 第二问: 6! 11 | 12 | 【3】六人排在一排,要求甲乙不相邻,并且甲丙不相邻,排法数有多少。 13 | 方法1: 14 | 全排列数目 6! = 720 15 | 甲乙相邻总数 5! * 2 = 240 16 | 甲丙相邻总数 240 17 | 甲乙丙相邻总数 4! * 2 = 48 18 | 结果为 720 - 240 - 240 + 48 = 288 19 | 20 | 方法2: 21 | 甲在开头时,符合条件总数为72 22 | 甲在右侧时,符合条件总数为72 23 | 甲在其它时,其它三人全排列,共有四种位置,C(3, 2) * 3! * 4 = 144 24 | 结果为 72 + 72 + 144 = 288 25 | 26 | 【4】10个糖果分给3人,每人至少1个糖果,多少种分法。 27 | C(9, 2) = 36 28 | 29 | 【5】10个不同球放入三个不同桶,共有多少种方法。 30 | 3^10 31 | 32 | 【6】有10颗糖,每天至少吃一颗,吃完为止,问有多少种不同吃法。 33 | 一天吃完:C(9, 0) = 1 34 | 两天吃完:C(9, 1) 35 | 三天吃完:C(9, 2) 36 | ... 37 | 答案为 C(9, i) 求和 = 2^9 = 512 38 | 39 | 40 | 【7】n对括号,求合法排列的数目 41 | C(2n, n) - C(2n, n + 1) 42 | C(2n, n) - C(2n, n - 1) = C(2n, n)/(n + 1) 43 | 上面两个计算公式结果一样,后面一个为卡特兰数重要公式 44 | 45 | 【8】n个数进出栈的顺序有多少种。 46 | 2n个人排队买票,n个人拿着5块钱,n个人拿着10块钱。票价5块一张。 47 | 每人买一张票,售票员手里没有零钱。问有多少种排队方法。 48 | 49 | 与题目7是一样的,采用卡特兰数解法 50 | 51 | 【9】求n个无差别的节点构成的二叉树有多少不同的种类 52 | f(0) = 1 53 | 以1为头结点:f(n) = 1 * f(n - 1) 54 | 以2为头结点:f(n) = 1 * f(n - 2) 55 | 以3为头结点:f(n) = f(2) * f(n - 3); 56 | ... 57 | 这是卡特兰数的另外一个重要公式 58 | f(n) = C(2n, n) / (n + 1) 59 | 60 | 【10】12个高矮不同的人,站成两排,每排必须具有从矮到高的排列 61 | 且第二排比对应第一排的人高。求排列方式有多少种 62 | 依然是卡特兰数的问题 63 | 64 | 【11】有n个信封包含n个信。把信拿出来再装回去,要求不能装回原来的信。求多少种装法。 65 | 假设第n封信放入第i信封中 66 | 情况一:第i封信也放入了第n个信封中,后续为f(n-2) 67 | 情况二:第i封信没放入了第n个信封中,后续为f(n-1) 68 | 总的方法数为 f(n) = (n - 1) * (f(n - 1) + f(n - 2)) 69 | -------------------------------------------------------------------------------- /nowcoder/chap09_arrange/Screen Shot 2017-04-30 at 5.24.05 PM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/nowcoder/chap09_arrange/Screen Shot 2017-04-30 at 5.24.05 PM.png -------------------------------------------------------------------------------- /nowcoder/chap09_arrange/readme.md: -------------------------------------------------------------------------------- 1 | 概率组合的题目分类 2 | 古典概率题 3 | 斐波那契数和卡特兰数 4 | 5 | 【1】在6 * 9 的方格中,从左上角到右下角,共有多少种不同走法 6 | C(13, 5) 或者 C(13, 8) ~ 1287 7 | 8 | 【2】七人站队,要求A必须在B的左边,但不要求一定相邻,请问多少种排法。如果要求一定相邻,有多少种解法。 9 | 第一问: 7!/2 10 | 第二问: 6! 11 | 12 | 【3】六人排在一排,要求甲乙不相邻,并且甲丙不相邻,排法数有多少。 13 | 方法1: 14 | 全排列数目 6! = 720 15 | 甲乙相邻总数 5! * 2 = 240 16 | 甲丙相邻总数 240 17 | 甲乙丙相邻总数 4! * 2 = 48 18 | 结果为 720 - 240 - 240 + 48 = 288 19 | 20 | 方法2: 21 | 甲在开头时,符合条件总数为72 22 | 甲在右侧时,符合条件总数为72 23 | 甲在其它时,其它三人全排列,共有四种位置,C(3, 2) * 3! * 4 = 144 24 | 结果为 72 + 72 + 144 = 288 25 | 26 | 【4】10个糖果分给3人,每人至少1个糖果,多少种分法。 27 | C(9, 2) = 36 28 | 29 | 【5】10个不同球放入三个不同桶,共有多少种方法。 30 | 3^10 31 | 32 | 【6】有10颗糖,每天至少吃一颗,吃完为止,问有多少种不同吃法。 33 | 一天吃完:C(9, 0) = 1 34 | 两天吃完:C(9, 1) 35 | 三天吃完:C(9, 2) 36 | ... 37 | 答案为 C(9, i) 求和 = 2^9 = 512 38 | 39 | 40 | 【7】n对括号,求合法排列的数目 41 | C(2n, n) - C(2n, n + 1) 42 | C(2n, n) - C(2n, n - 1) = C(2n, n)/(n + 1) 43 | 卡特兰数重要公式 44 | 45 | 【8】n个数进出栈的顺序有多少种。 46 | 2n个人排队买票,n个人拿着5块钱,n个人拿着10块钱。票价5块一张。 47 | 每人买一张票,售票员手里没有零钱。问有多少种排队方法。 48 | 49 | 与题目7是一样的,采用卡特兰数解法 50 | 51 | 【9】求n个无差别的节点构成的二叉树有多少不同的种类 52 | f(0) = 1 53 | 以1为头结点:f(n) = 1 * f(n - 1) 54 | 以2为头结点:f(n) = 1 * f(n - 2) 55 | 以3为头结点:f(n) = f(2) * f(n - 3); 56 | ... 57 | 这是卡特兰数的另外一个重要公式 58 | f(n) = C(2n, n) / (n + 1) 59 | 60 | 【10】12个高矮不同的人,站成两排,每排必须具有从矮到高的排列 61 | 且第二排比对应第一排的人高。求排列方式有多少种 62 | 依然是卡特兰数的问题 63 | 64 | 【11】有n个信封包含n个信。把信拿出来再装回去,要求不能装回原来的信。求多少种装法。 65 | 假设第n封信放入第i信封中 66 | 情况一:第i封信也放入了第n个信封中,后续为f(n-2) 67 | 情况二:第i封信没放入了第n个信封中,后续为f(n-1) 68 | 总的方法数为 f(n) = (n - 1) * (f(n - 1) + f(n - 2)) 69 | -------------------------------------------------------------------------------- /nowcoder/chap10_probability/pro_10_02_Championship.java: -------------------------------------------------------------------------------- 1 | package chap10_probability; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 有2k只球队,有k-1个强队,其余都是弱队,随机把它们分成k组比赛,每组两个队,问两强相遇的概率是多大? 6 | 7 | 给定一个数k,请返回一个数组,其中有两个元素,分别为最终结果的分子和分母,请化成最简分数 8 | 9 | 测试样例: 10 | 4 11 | 返回:[3,7] 12 | */ 13 | import java.util.*; 14 | 15 | public class Championship { 16 | public int[] calc(int k) { 17 | // write code here 18 | // 总数为 (2k - 1) * (2k - 3) * ... * 1 19 | // 相遇为 C(k - 1, k + 1) * A(k - 1, k - 1) 20 | int sum = 1; 21 | int a = 1; 22 | 23 | //求总的组合数 24 | for(int i = 2 * k - 1; i > 0; i -= 2){ 25 | sum *= i; 26 | } 27 | 28 | //强队不相遇 C(k+1,k-1) 29 | for(int i = 3; i <= k + 1; i++){ 30 | a *= i; 31 | } 32 | 33 | int gcd = gcd(sum, a); 34 | sum = sum / gcd; 35 | a = a / gcd; 36 | 37 | // int[]res = new int[] {sum - a, sum}; 38 | return new int[] {sum - a, sum}; 39 | 40 | 41 | } 42 | 43 | public int gcd(int a,int b){ 44 | // 分子分母化简,用辗转相除法进行求解。 辗转相除法是古希腊求两个正整数的最大公约数的,也叫欧几里德算法, 45 | // while (b > 0){ 46 | // int t = b; 47 | // b = a % b; 48 | // a = t; 49 | // } 50 | return b > 0 ? gcd(b, a % b) : a; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /nowcoder/chap10_probability/pro_10_03_collision.java: -------------------------------------------------------------------------------- 1 | package chap10_probability; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * n只蚂蚁从正n边形的n个定点沿着边移动,速度是相同的,问它们碰头的概率是多少? 6 | 7 | 给定一个正整数n,请返回一个数组,其中两个元素分别为结果的分子和分母,请化为最简分数。 8 | 9 | 测试样例: 10 | 3 11 | 返回:[3,4] 12 | */ 13 | import java.util.*; 14 | 15 | public class Ants { 16 | public int[] collision(int n) { 17 | // write code here 18 | long total = 1; 19 | for (int i = 0; i < n; i++) { 20 | total *= 2; 21 | } 22 | return new int[] {(int) total/2 - 1, (int) total/2}; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nowcoder/chap10_probability/pro_10_04_Random7.java: -------------------------------------------------------------------------------- 1 | package chap10_probability; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 给定一个等概率随机产生1~5的随机函数,除此之外,不能使用任何额外的随机机制, 6 | * 请实现等概率随机产生1~7的随机函数。(给定一个可调用的Random5::random()方法,可以等概率地随机产生1~5的随机函数) 7 | * 8 | * 注意: 提问区的回复 9 | * 其实这道题左神没有讲清楚本质,这道题本质就是得到一串均匀分布且长度大于7的连续序列即可 10 | * (甚至都不需要连续,只要保证能产生7个以上等概率的数即可),在这个序列里选中7个(或7的倍数个), 11 | * 若得到的数不是这7个中的,重新产生。这样这7个数的概率肯定是相同的。 12 | * 举例 13 | * int num = 5 * rand5() + rand5(); //生成6~25的数,选取其中7~20这14个数,非这14个数重新生成,最后取余即可 14 | * while(num > 20 || num < 7){ 15 | * num = 5 * rand5() + rand5(); 16 | * } 17 | * return num % 7 + 1; 18 | */ 19 | import java.util.*; 20 | 21 | public class Random7 { 22 | private static Random rand = new Random(123456); 23 | // 随机产生[1,5] 24 | private int rand5() { 25 | return 1 + rand.nextInt(5); 26 | } 27 | 28 | // 通过rand5实现rand7 29 | public int randomNumber() { 30 | int num = 30; 31 | while (num > 20) { 32 | num = 5 * (rand5() - 1) + (rand5() - 1); 33 | } 34 | return num % 7 + 1; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /nowcoder/chap10_probability/pro_10_05_Random01.java: -------------------------------------------------------------------------------- 1 | package chap10_probability; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 给定一个以p概率产生0,以1-p概率产生1的随机函数RandomP::f(),p是固定的值,但你并不知道是多少。 6 | * 除此之外也不能使用任何额外的随机机制,请用RandomP::f()实现等概率随机产生0和1的随机函数。 7 | */ 8 | import java.util.*; 9 | 10 | // 无法通过测试用例, 11 | public class Random01 { 12 | private static double p = new Random().nextFloat(); 13 | // 随机概率p 14 | public static int f() { 15 | return new Random().nextFloat() < p ? 0 : 1; 16 | } 17 | 18 | public int random01() { 19 | // 通过f函数实现01等概率返回 20 | boolean b1 = true; 21 | boolean b2 = true; 22 | while (b1 ^ b2) { 23 | b1 = f() == 0 ? true : false; 24 | b2 = f() == 0 ? true : false; 25 | } 26 | return b1 ? 0 : 1; 27 | } 28 | } 29 | 30 | // 要通过测试用例的话,请直接用系统的随机数产生器 31 | public int random01() { 32 | Random random= new Random(); 33 | return random.nextInt(2); 34 | } -------------------------------------------------------------------------------- /nowcoder/chap10_probability/pro_10_07_RandomSeg.java: -------------------------------------------------------------------------------- 1 | package chap10_probability; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 假设函数f()等概率随机返回一个在[0,1)范围上的浮点数, 6 | * 那么我们知道,在[0,x)区间上的数出现的概率为x(0= penny[i]) { 55 | dp[j] += dp[j - penny[i]]; 56 | } 57 | } 58 | } 59 | return dp[aim]; 60 | } 61 | } -------------------------------------------------------------------------------- /nowcoder/chap12_DaynamicProgramming/dp_12_04_GoUpStairs.java: -------------------------------------------------------------------------------- 1 | package chap12_DaynamicProgramming; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法。 6 | * 为了防止溢出,请将结果Mod 1000000007 7 | * 8 | * 给定一个正整数int n,请返回一个数,代表上楼的方式数。保证n小于等于100000。 9 | 10 | 测试样例: 11 | 1 12 | 返回:1 13 | */ 14 | import java.util.*; 15 | 16 | public class GoUpstairs { 17 | private int CONST = 1000000007; 18 | public int countWays(int n) { 19 | // write code here 20 | int last = 1; 21 | int cur = 1; 22 | if (n == 1) { 23 | return cur; 24 | } 25 | for (int i = 1; i < n; i++) { 26 | int temp = (cur + last) % CONST; 27 | last = cur; 28 | cur = temp; 29 | } 30 | return cur; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /nowcoder/chap12_DaynamicProgramming/dp_12_05_MinimumPath.java: -------------------------------------------------------------------------------- 1 | package chap12_DaynamicProgramming; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 有一个矩阵map,它每个格子有一个权值。 6 | * 从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置, 7 | * 路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。 8 | 9 | 给定一个矩阵map及它的行数n和列数m,请返回最小路径和。保证行列数均小于等于100. 10 | 11 | 测试样例: 12 | [[1,2,3],[1,1,1]],2,3 13 | 返回:4 14 | */ 15 | import java.util.*; 16 | 17 | public class MinimumPath { 18 | public int getMin(int[][] map, int n, int m) { 19 | // write code here 20 | int[][] dp = new int[n + 1][m + 1]; 21 | for (int i = 1; i <= n; i++) { 22 | for (int j = 1; j <= m; j++) { 23 | if (j - 1 == 0) { 24 | dp[i][j] = map[i - 1][j - 1] + dp[i - 1][j]; 25 | } else if (i - 1 == 0){ 26 | dp[i][j] = map[i - 1][j - 1] + dp[i][j - 1]; 27 | } else { 28 | dp[i][j] = map[i - 1][j - 1] + Math.min(dp[i][j - 1], dp[i - 1][j]); 29 | } 30 | } 31 | } 32 | return dp[n][m]; 33 | } 34 | } 35 | 36 | // 讨论区的算法 37 | import java.util.*; 38 | 39 | public class MinimumPath { 40 | public int getMin(int[][] map, int n, int m) { 41 | // write code here 42 | int[][] dp = new int[n][m]; 43 | for(int i = 0; i < n; i++){ 44 | for(int j = 0; j < m; j++){ 45 | dp[i][j] = 0; 46 | } 47 | } 48 | dp[0][0] = map[0][0]; 49 | for(int i = 1; i < n; i++){ 50 | dp[i][0] += map[i][0] + dp[i-1][0]; 51 | } 52 | for(int i = 1; i < m; i++){ 53 | dp[0][i] += map[0][i] + dp[0][i-1]; 54 | } 55 | for(int i = 1; i < n; i++){ 56 | for(int j = 1; j < m; j++){ 57 | dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + map[i][j]; 58 | } 59 | } 60 | return dp[n-1][m-1]; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /nowcoder/chap12_DaynamicProgramming/dp_12_06_LIS.java: -------------------------------------------------------------------------------- 1 | package chap12_DaynamicProgramming; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 这是一个经典的LIS(即最长上升子序列)问题, 6 | * 请设计一个尽量优的解法求出序列的最长上升子序列的长度。 7 | 8 | 给定一个序列A及它的长度n(长度小于等于500),请返回LIS的长度。 9 | 10 | 测试样例: 11 | [1,4,2,5,3],5 12 | 返回:3 13 | */ 14 | 15 | import java.util.*; 16 | 17 | public class LongestIncreasingSubsequence { 18 | public int getLIS(int[] A, int n) { 19 | // write code here 20 | int[] dp = new int[n]; 21 | int max = 0; 22 | for (int i = 0; i < n; i++) { 23 | dp[i] = 1; 24 | for (int j = 0; j < i; j++) { 25 | if (A[i] > A[j]) { 26 | dp[i] = Math.max(dp[j] + 1, dp[i]); 27 | } 28 | if (dp[i] > max) { 29 | max = dp[i]; 30 | } 31 | } 32 | } 33 | return max; 34 | } 35 | } 36 | 37 | // 这是github中其他人得方法; 38 | // https://github.com/brianway/algorithms-learning/tree/master/algorithms-lecture 39 | public class LongestIncreasingSubsequence { 40 | public int getLIS(int[] A, int n) { 41 | int[] up = new int[n]; 42 | up[0] = 1; 43 | for (int i = 1; i < n; i++) { 44 | up[i] = 1; 45 | for (int j = 0; j < i; j++) { 46 | if (A[i] > A[j] && up[j] >= up[i]) { 47 | up[i] = up[j] + 1; 48 | } 49 | } 50 | } 51 | 52 | int max = 1; 53 | for (int i = 0; i < n; i++) { 54 | if (up[i] > max) { 55 | max = up[i]; 56 | } 57 | } 58 | return max; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /nowcoder/chap12_DaynamicProgramming/dp_12_07_LCS.java: -------------------------------------------------------------------------------- 1 | package chap12_DaynamicProgramming; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。 6 | * 例如,A="1A2C3D4B56”,B="B1D23CA45B6A”,”123456"或者"12C4B6"都是最长公共子序列。 7 | 8 | 给定两个字符串A和B,同时给定两个串的长度n和m,请返回最长公共子序列的长度。保证两串长度均小于等于300。 9 | 10 | 测试样例: 11 | "1A2C3D4B56",10,"B1D23CA45B6A",12 12 | 返回:6 13 | */ 14 | public class LCS { 15 | public int findLCS(String A, int n, String B, int m) { 16 | int[][] dp = new int[n + 1][m + 1]; 17 | char[] a = A.toCharArray(); 18 | char[] b = B.toCharArray(); 19 | for (int i = 0; i < n; i++) { 20 | for (int j = 0; j < m; j++) { 21 | if (a[i] == b[j]) { 22 | dp[i + 1][j + 1] = dp[i][j] + 1; 23 | } else { 24 | dp[i + 1][j + 1] = Math.max(dp[i + 1][j], dp[i][j + 1]); 25 | } 26 | } 27 | } 28 | return dp[n][m]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /nowcoder/chap12_DaynamicProgramming/dp_12_08_backpack.java: -------------------------------------------------------------------------------- 1 | package chap12_DaynamicProgramming; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 一个背包有一定的承重cap,有N件物品, 6 | * 每件都有自己的价值,记录在数组v中,也都有自己的重量, 7 | * 记录在数组w中,每件物品只能选择要装入背包还是不装入背包, 8 | * 要求在不超过背包承重的前提下,选出物品的总价值最大。 9 | *

10 | * 给定物品的重量w价值v及物品数n和承重cap。请返回最大总价值。 11 | *

12 | * 测试样例: 13 | * [1,2,3],[1,2,3],3,6 14 | * 返回:6 15 | */ 16 | 17 | import java.util.*; 18 | 19 | public class Backpack { 20 | public int maxValue(int[] w, int[] v, int n, int cap) { 21 | // write code here 22 | int[] dp = new int[cap + 1]; 23 | 24 | for (int i = 0; i < n; i++) { 25 | for (int j = cap; j >= w[i]; j--) { 26 | dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]); 27 | } 28 | } 29 | 30 | return dp[cap]; 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /nowcoder/chap12_DaynamicProgramming/dp_12_09_minCost.java: -------------------------------------------------------------------------------- 1 | package chap12_DaynamicProgramming; 2 | 3 | /** 4 | * Created by xing on 5/2/17. 5 | * 对于两个字符串A和B,我们需要进行插入、删除和修改操作将A串变为B串, 6 | * 定义c0,c1,c2分别为三种操作的代价,请设计一个高效算法, 7 | * 求出将A串变为B串所需要的最少代价。 8 | 9 | 给定两个字符串A和B,及它们的长度和三种操作代价,请返回将A串变为B串所需要的最小代价。 10 | 保证两串长度均小于等于300,且三种代价值均小于等于100。 11 | 12 | 测试样例: 13 | "abc",3,"adc",3,5,3,100 14 | 返回:8 15 | */ 16 | import java.util.*; 17 | 18 | public class MinCost { 19 | public int findMinCost(String A, int n, String B, int m, int c0, int c1, int c2) { 20 | // write code here 21 | char[] a = A.toCharArray(); 22 | char[] b = B.toCharArray(); 23 | int[][] dp = new int[n + 1][m + 1]; 24 | // 初始化行,表示插入 25 | for (int i = 0; i <= n; i++) { 26 | dp[i][0] = c1 * i; 27 | } 28 | // 初始化列,表示删除 29 | for (int j = 0; j <= m; j++) { 30 | dp[0][j] = c0 * j; 31 | } 32 | 33 | int min = 0; 34 | for (int i = 1; i <= n; i++) { 35 | for (int j = 1; j <= m; j++) { 36 | min = Math.min(dp[i - 1][j] + c1, dp[i][j - 1] + c0); 37 | if (a[i - 1] == b[j - 1]) { 38 | dp[i][j] = Math.min(min, dp[i - 1][j - 1]); 39 | } else { 40 | dp[i][j] = Math.min(min, dp[i - 1][j - 1] + c2); 41 | } 42 | } 43 | } 44 | 45 | return dp[n][m]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /nowcoder/chap12_DaynamicProgramming/readme.md: -------------------------------------------------------------------------------- 1 | 给定数组arr, arr中所有的值为正数且不重复。 2 | 每个值代表一种货币,每种面值的货币可以使用任意张。 3 | 在给定一个正数aim代表要找的钱数,求换钱有多少种方法。 4 | 5 | 暴力搜索方法 6 | | 7 | 记忆搜索方法 8 | | 9 | 动态规划方法 10 | | 11 | 动态规划的后续简化方法 12 | 13 | 可以参考[背包问题九讲](http://love-oriented.com/pack/),思考动态规划问题的方法。 14 | 15 | 动态规划的本质 16 | 是利用申请的空间来记录每一个暴力搜索的计算结果。 17 | 下一次要用结果的时候直接使用,而不再重复计算递归过程。 18 | 动态规划规定每一种递归状态的计算顺序,依次进行计算。 19 | 20 | 动态规划的大致过程 21 | 1. 实现暴力搜索的方法 22 | 2. 找到哪些参数可以代表递归过程。 23 | 3. 找到代表递归参数的过程,记忆化搜索的方法非常容易实现。 24 | 4. 通过分析记忆化搜索的依赖路径,进而实现动态规划。 25 | 5. 根据记忆化搜索方法改出的动态规划方法,进而看看是否能简化, 26 | 如果能简化,还能实现时间复杂度更低的动态规划方法。 27 | 28 | 29 | 动态规划方法的关键点 30 | 1.最优化原理,也就是最优子结构性质,这指的是一个最优化策略具有这样的性质。 31 | 不论过去状态和策略如何,对前面的策略所形成的状态而言,余下的诸策略必须构成最优策略。 32 | 简单来说就是一个最优化策略的子策略总是最优的。 33 | 2. 无后效性。某状态下策略的收益,只与状态和策略相关,与如何到达该状态的方式无关。 34 | 3. 子问题的重叠性,动态规划将原来具有指数级别时间复杂度的暴力搜索算法改成了具有多项式时间组大度。 35 | 其中关键在于解决冗余,这是动态规划方法的本质。 36 | 37 | ![](12.1_1_暴力解法.png) 38 | ![](12.1_2_记忆化搜索.png) 39 | ![](12.1_3_动态规划.png) 40 | ![](12.1_4_动态规划的简化.png) 41 | ![](12.1_对比.png) 42 | 43 | 【1】一个台阶总共有n 级,如果一次可以跳1 级, 44 | 也可以跳2 级。求总共有多少总跳法,并分析算法的时间复杂度。 45 | ![](1.png) 46 | 47 | 【2】给定一个矩阵,从左上角开始每次只能向右或者向下移动, 48 | 最后到达右下角的位置,路径上的所有的数字累加起来作为这条路径的路劲和。 49 | 要求返回所有路径和中的最小路径和。 50 | 举例: 51 | 1 3 5 9 52 | 8 1 3 4 53 | 5 0 6 1 54 | 8 8 4 0 55 | 路径1,3,1,0,6,1,0是所有路径中路径和最小的,所以返回其和12。 56 | 57 | dp[i][j] = m[i][j] + min(dp[i-1][j], dp[i][j-1]) 58 | 59 | 【3】给定数组arr,返回arr的最长递增子序列长度。 60 | 返回arr的最长递增子序列长度。 61 | 比如arr={2,1,5,3,6,4,8,9,7},最长递增子序列为{1,3,4,8,9}, 62 | 所以返回这个子序列的长度为5。 63 | 64 | dp[i] = max{dp[j] + 1 (0<=j 9 | * 给定格子图的长n和宽m。请返回最多能涂的格子数目。 10 | *

11 | * 测试样例: 12 | * 1,2 13 | * 返回:1 14 | */ 15 | 16 | import java.util.*; 17 | 18 | public class Paint { 19 | public int getMost(int n, int m) { 20 | // write code here 21 | // 间隔着涂颜色。每次最多只能涂一半。 22 | return (m * n + 1) / 2; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /nowcoder/chap13_brain/brain_13_02.java: -------------------------------------------------------------------------------- 1 | package chap13_brain; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 作为一个马场的主人,你要安排你的n匹赛马和另一个马场的n匹马比赛。 6 | * 你已经知道了对方马场的出战表,即参加每一场的马的强壮程度。 7 | * 当然你也知道你自己的所有马的强壮程度。我们假定比赛的结果直接由马的强壮程度决定, 8 | * 即更壮的马获胜(若相同则双方均不算获胜),请你设计一个策略,使你能获得尽量多的场次的胜利。 9 | *

10 | * 给定对方每场比赛的马的强壮程度oppo及你的所有马的强壮程度horses 11 | * (强壮程度为整数,且数字越大越强壮)同时给定n,请返回最多能获胜的场次。 12 | *

13 | * 测试样例: 14 | * [1,2,3],[1,2,3],3 15 | * 返回:2 16 | */ 17 | 18 | import java.util.*; 19 | 20 | public class HorseRace { 21 | public int winMost(int[] oppo, int[] horses, int n) { 22 | // write code here 23 | int i = 0; 24 | int j = 0; 25 | int count = 0; 26 | Arrays.sort(oppo); 27 | Arrays.sort(horses); 28 | while (i < n && j < n) { 29 | if (oppo[i] < horses[j]) { 30 | i++; 31 | j++; 32 | count++; 33 | } else { 34 | j++; 35 | } 36 | } 37 | return count; 38 | } 39 | } -------------------------------------------------------------------------------- /nowcoder/chap13_brain/brain_13_03.java: -------------------------------------------------------------------------------- 1 | package chap13_brain; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 你和你的朋友正在玩棋子跳格子的游戏,而棋盘是一个由n个格子组成的长条, 6 | * 你们两人轮流移动一颗棋子,每次可以选择让棋子跳1-3格,先将棋子移出棋盘的人获得胜利。 7 | * 我们知道你们两人都会采取最优策略,现在已知格子数目,并且初始时棋子在第一格由你操作。 8 | * 请你计算你是否能获胜。 9 | *

10 | * 给定格子的数目n(n为不超过300的正整数)。返回一个整数,1代表能获胜,0代表不能获胜。 11 | *

12 | * 测试样例: 13 | * 3 14 | * 返回:1 15 | * 16 | * 注: 17 | * 经典博弈问题。需要采用逆向思维,如果对方移动n个,那么我移动4-n个,即可。 18 | * 如果对4取余得m,那么第一次取m个,然后后来每次根据对方的个数取4-n个就可以了。这时候保证最后能赢。 19 | */ 20 | 21 | import java.util.*; 22 | 23 | public class Jump { 24 | public int checkWin(int n) { 25 | // write code here 26 | return (n - 1) % 4 == 0 ? 0 : 1; 27 | } 28 | } -------------------------------------------------------------------------------- /nowcoder/chap13_brain/brain_13_04.java: -------------------------------------------------------------------------------- 1 | package chap13_brain; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * A与B做游戏。 在一个n*m的矩阵中的出发点是(1,m),终点是(n,1), 6 | * 规则是只能向左移动一格,向下一格或向左下移动一格,先走到终点的为winner。 A先走。 7 | *

8 | * 给定两个整数n和m,请返回最后的获胜者的名字(A或B)。 9 | *

10 | * 测试样例: 11 | * 5 3 12 | * 返回:B 13 | * 14 | * 注: 15 | * 参考网站的解释: http://blog.5ibc.net/p/64768.html 16 | * 只有m 和n都是奇数的时候B才能赢 17 | */ 18 | import java.util.*; 19 | 20 | public class Game { 21 | public char getWinner(int n, int m) { 22 | // write code here 23 | return (m & 1) == 1 && (n & 1) == 1 ? 'B' : 'A'; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /nowcoder/chap13_brain/brain_13_05.java: -------------------------------------------------------------------------------- 1 | package chap13_brain; 2 | 3 | /** 4 | * Created by xing on 4/30/17. 5 | * 现在有一个整数数组,其元素值均为1-n范围内的某个整数, 6 | * 现在你和你的朋友在玩一个游戏,游戏的目的是把数组清空, 7 | * 你们轮流操作,你是先手,每次操作你可以删除数组中值为某个数的元素任意多个 8 | * (当然数组中值为这个数的元素个数应大于等于你删除的个数,且你至少要删除一个数)。 9 | * 最先把数组清空的人获得胜利。假设你们都采取最优策略,请你计算你能否获得胜利。 10 | *

11 | * 给定一个整数数组A和元素个数n。请返回一个整数,1代表你能获胜,0代表你不能获胜。 12 | *

13 | * 测试样例: 14 | * [1,1,1] 15 | * 返回:1 16 | * 17 | * 注: 参考他人解答。不是很清楚 18 | */ 19 | import java.util.*; 20 | 21 | public class Clear { 22 | public int getWinner(int[] A, int n) { 23 | // write code here 24 | if (A == null || A.length == 0) { 25 | return 0; 26 | } 27 | int result = 0; 28 | int num; 29 | Arrays.sort(A); 30 | for(int i = 0; i < n; ++i){ 31 | int j = i; 32 | num = 0; 33 | while(j < n && A[i] == A[j]){ 34 | ++num; 35 | ++j; 36 | } 37 | result ^= num; 38 | } 39 | return (result == 0) ? 0 : 1; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nowcoder/nowcode_0519_test/test1.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | public class Main { 3 | private static boolean check (int[] nums) { 4 | if (nums == null || nums.length == 1) { 5 | return true; 6 | } 7 | // corner case 8 | int n = nums[0]; 9 | // bit right move 10 | if (n != 0) { 11 | while ((n & 1) != 1) { 12 | n = n >>> 1; 13 | } 14 | } 15 | for (int i = 1; i < nums.length; i++) { 16 | if (n == 0 && nums[i] != n) { 17 | return false; 18 | } 19 | if (n != 0 && nums[i] == 0) { 20 | return false; 21 | } 22 | if (n == 0 && nums[i] == 0) { 23 | continue; 24 | } else { 25 | int temp = nums[i]; 26 | while ((temp & 1) != 1) { 27 | temp = temp >>> 1; 28 | } 29 | if (n != temp) { 30 | return false; 31 | } 32 | } 33 | } 34 | return true; 35 | } 36 | public static void main(String[] args) { 37 | Scanner sc = new Scanner(System.in); 38 | int n = sc.nextInt(); 39 | int[] nums = new int[n]; 40 | for(int i = 0; i < n; i++){ 41 | nums[i] = sc.nextInt(); 42 | } 43 | if (check(nums)) { 44 | System.out.println("YES"); 45 | } else { 46 | System.out.println("NO"); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /nowcoder/nowcode_0519_test/test3.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 牛牛现在有一个n个数组成的数列,牛牛现在想取一个连续的子序列,并且这个子序列还必须得满足: 3 | * 最多只改变一个数,就可以使得这个连续的子序列是一个严格上升的子序列,牛牛想知道这个连续子序列最长的长度是多少。 4 | * 5 | * 输入描述: 6 | * 输入包括两行,第一行包括一个整数n(1 ≤ n ≤ 10^5),即数列的长度; 7 | * 第二行n个整数a_i, 表示数列中的每个数(1 ≤ a_i ≤ 10^9),以空格分割。 8 | * 9 | * 输出描述: 10 | * 输出一个整数,表示最长的长度。 11 | * 12 | * 输入例子: 13 | * 6 14 | * 7 2 3 1 5 6 15 | * 16 | * 输出例子: 17 | * 5 18 | * 19 | * 思路: 20 | * 题目要求的是最长的递增子数组,但是可以修改某一字符。因此可以求出某一字符前面最长的递增和其后面最长的递增序列。 21 | * 通过两次循环遍历可以很容易求得两个数组,记录递增序列的长度。 22 | */ 23 | import java.util.Scanner; 24 | public class Main { 25 | private static int check (int[] nums) { 26 | if (nums == null) { 27 | return 0; 28 | } 29 | int n = nums.length; 30 | if (n <= 2) { 31 | return n; 32 | } 33 | int[] inc = new int[n]; 34 | int[] dec = new int[n]; 35 | inc[0] = 1; 36 | dec[n - 1] = 1; 37 | // 计算递增,递减数目 38 | for (int i = 1; i < n; i++) { 39 | inc[i] = nums[i] > nums[i - 1] ? inc[i - 1] + 1 : 1; 40 | } 41 | for (int i = n - 2; i >= 0; i--) { 42 | dec[i] = nums[i] < nums[i + 1] ? dec[i + 1] + 1 : 1; 43 | 44 | } 45 | // combine 46 | int res = 1; 47 | for (int i = 1; i < n - 1; i++) { 48 | res = Math.max(res, inc[i - 1] + 1); 49 | res = Math.max(res, dec[i + 1] + 1); 50 | // 只有大于2中间才能插入一个新数字,保证严格上升 51 | if (nums[i + 1] - nums[i - 1] >= 2) { 52 | res = Math.max(res, inc[i - 1] + dec[i + 1] + 1); 53 | } 54 | } 55 | return res; 56 | } 57 | public static void main(String[] args) { 58 | Scanner sc = new Scanner(System.in); 59 | int n = sc.nextInt(); 60 | int[] nums = new int[n]; 61 | for(int i = 0; i < n; i++){ 62 | nums[i] = sc.nextInt(); 63 | } 64 | System.out.println(check(nums)); 65 | } 66 | } -------------------------------------------------------------------------------- /nowcoder/readme.md: -------------------------------------------------------------------------------- 1 | [牛客网](https://www.nowcoder.com/courses)中BAT面试算法精品课程参考代码。代码有我练习过程中总结而来。无特殊标示,均为本人所写。欢迎大家提出修改意见。有的题目有多种解法,尽量保证都写进来。由于时间精力有限,难免有所缺失。请指出。 2 | 3 | > 4 | 如果大家觉得课程很好,可以用我的优惠码优惠10元进行课程学习: ACRS3kM,邀请链接为:[www.nowcoder.com/courses/1?coupon=ACRS3kM](www.nowcoder.com/courses/1?coupon=ACRS3kM)。你可邀请朋友和你一起来上这门课,通过你的邀请链接购买,或在购买时手动填入你的邀请码,购课成功后,你和他都将获得10元现金奖励。奖金可无限累加哦! 5 | 6 | 7 | 本课程讲解为[左程云](https://www.zhihu.com/question/19981544/answer/135901406)。有书籍[程序员代码面试指南](https://book.douban.com/subject/26638586/),IT名企算法和数据结构题目最优解。华中科技大学(本科)、 芝加哥大学(硕士),曾就职于IBM、百度。 从2010年起专注刷题至今。《程序员代码面试指南—IT名企算法与数据结构题目最优解》 作者,已经由电子工业出版社出版发行。书籍涉及算法与数据结构编程题目近200道,并且提供最优解全部讲解和代码。 8 | 9 | 注: 10 | 这里我也收集到另外一个github账号[brianway](https://github.com/brianway/algorithms-learning/tree/master/algorithms-lecture)的java参考代码。可以参考对比不同的实现。 -------------------------------------------------------------------------------- /others/README.md: -------------------------------------------------------------------------------- 1 | ### math vs DP 2 | 3 | Find how many ways from A to B; 4 | ![](./image/25353.png) 5 | math method: 6 | A->P C(6, 2) = 15 7 | P->B C(6, 3) = 20 8 | A->p->B 15 * 20 = 300 9 | total: 10 | C(12, 5) - 300 = 492 11 | 12 | Dynamic program method 13 | ![](./image/25353_.png) -------------------------------------------------------------------------------- /others/image/25353.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/others/image/25353.png -------------------------------------------------------------------------------- /others/image/25353_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/others/image/25353_.png -------------------------------------------------------------------------------- /sort/01_insertSort.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/sort/01_insertSort.java -------------------------------------------------------------------------------- /sort/01_insertSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | #直接插入排序 6 | def insert_sort(L): 7 | #遍历数组中的所有元素,其中0号索引元素默认已排序,因此从1开始 8 | for x in range(1,len(L)): 9 | #将该元素与已排序好的前序数组依次比较,如果该元素小,则交换 10 | #range(x-1,-1,-1):从x-1倒序循环到0 11 | for i in range(x-1,-1,-1): 12 | #判断:如果符合条件则交换 13 | if L[i] > L[i+1]: 14 | L[i], L[i + 1] = L[i + 1], L[i] 15 | return L 16 | 17 | if __name__ == '__main__': 18 | nums = np.random.randint(1, 100, 10) 19 | nums2 = insert_sort(nums) 20 | print "Before: " 21 | print nums 22 | print "After: " 23 | print nums2 24 | for i in range(1, len(nums2)): 25 | if nums[i] < nums[i - 1]: 26 | print "Wrong Sort!" 27 | print "Success!" 28 | -------------------------------------------------------------------------------- /sort/02_bubbleSort.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/sort/02_bubbleSort.java -------------------------------------------------------------------------------- /sort/02_bubbleSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | #冒泡排序 6 | def bubble_sort(L): 7 | length = len(L) 8 | #序列长度为length,需要执行length-1轮交换 9 | for x in range(1, length): 10 | #对于每一轮交换,都将序列当中的左右元素进行比较 11 | #每轮交换当中,由于序列最后的元素一定是最大的,因此每轮循环到序列未排序的位置即可 12 | for i in range(0, length-x): 13 | if L[i] > L[i+1]: 14 | L[i], L[i + 1] = L[i + 1], L[i] 15 | return L 16 | 17 | if __name__ == '__main__': 18 | nums = np.random.randint(1, 100, 10) 19 | nums2 = bubble_sort(nums) 20 | print "Before: " 21 | print nums 22 | print "After: " 23 | print nums2 24 | for i in range(1, len(nums2)): 25 | if nums[i] < nums[i - 1]: 26 | print "Wrong Sort!" 27 | print "Success!" 28 | -------------------------------------------------------------------------------- /sort/03_selectionSort.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/sort/03_selectionSort.java -------------------------------------------------------------------------------- /sort/03_selectionSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | # 简单选择排序 6 | def select_sort(L): 7 | #依次遍历序列中的每一个元素 8 | for x in range(0, len(L)): 9 | #将当前位置的元素定义此轮循环当中的最小值 10 | minVal = L[x] 11 | #将该元素与剩下的元素依次比较寻找最小元素 12 | for i in range(x + 1, len(L)): 13 | if L[i] < minVal: 14 | minVal, L[i] = L[i], minVal 15 | #将比较后得到的真正的最小值赋值给当前位置 16 | L[x] = minVal 17 | return L 18 | 19 | if __name__ == '__main__': 20 | nums = np.random.randint(1, 100, 10) 21 | nums2 = select_sort(nums) 22 | print "Before: " 23 | print nums 24 | print "After: " 25 | print nums2 26 | for i in range(1, len(nums2)): 27 | if nums[i] < nums[i - 1]: 28 | print "Wrong Sort!" 29 | print "Success!" 30 | -------------------------------------------------------------------------------- /sort/04_quickSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | 6 | #快速排序 7 | #L:待排序的序列;start排序的开始index,end序列末尾的index 8 | #对于长度为length的序列:start = 0;end = length-1 9 | def quick_sort(L, start, end): 10 | i, j, pivot = start, end, L[(start + end) / 2] 11 | while i <= j: 12 | #从右开始向左寻找第一个小于pivot的值 13 | while (L[j] > pivot): 14 | j -= 1 15 | #从左开始向右寻找第一个大于pivot的值 16 | while (L[i] < pivot): 17 | i += 1 18 | #将大于pivot的值移到右边 19 | if (i <= j): 20 | L[i], L[j] = L[j], L[i] 21 | i += 1 22 | j -= 1 23 | #左侧序列继续排序 24 | if end > i: 25 | quick_sort(L, i, end) 26 | #右侧序列继续排序 27 | if start < j: 28 | quick_sort(L, start, j) 29 | return L 30 | 31 | #快速排序 32 | #L:待排序的序列;start排序的开始index,end序列末尾的index 33 | #对于长度为length的序列:start = 0;end = length-1 34 | def quick_sort2(L,start,end): 35 | if start < end: 36 | i , j , pivot = start , end , L[start] 37 | while i < j: 38 | #从右开始向左寻找第一个小于pivot的值 39 | while (i < j) and (L[j] >= pivot): 40 | j = j-1 41 | #将小于pivot的值移到左边 42 | if (i < j): 43 | L[i] = L[j] 44 | i = i+1 45 | #从左开始向右寻找第一个大于pivot的值 46 | while (i < j) and (L[i] < pivot): 47 | i = i+1 48 | #将大于pivot的值移到右边 49 | if (i < j): 50 | L[j] = L[i] 51 | j = j-1 52 | #循环结束后,说明 i=j,此时左边的值全都小于pivot,右边的值全都大于pivot 53 | #pivot的位置移动正确,那么此时只需对左右两侧的序列调用此函数进一步排序即可 54 | #递归调用函数:依次对左侧序列:从0 ~ i-1//右侧序列:从i+1 ~ end 55 | L[i] = pivot 56 | #左侧序列继续排序 57 | quick_sort(L, start, i - 1) 58 | #右侧序列继续排序 59 | quick_sort(L, i + 1, end) 60 | return L 61 | 62 | if __name__ == '__main__': 63 | nums = np.random.randint(1, 100, 10) 64 | nums2 = quick_sort(nums, 0, len(nums) - 1) 65 | nums3 = quick_sort2(nums, 0, len(nums) - 1) 66 | print "Before: " 67 | print nums 68 | print "After: " 69 | print nums2 70 | for i in range(1, len(nums2)): 71 | if nums[i] < nums[i - 1]: 72 | print "Wrong Sort!" 73 | for i in range(1, len(nums3)): 74 | if nums[i] < nums[i - 1]: 75 | print "Wrong Sort!" 76 | print "Success!" 77 | -------------------------------------------------------------------------------- /sort/05_shellSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | #希尔排序 6 | def insert_shell(L): 7 | #初始化gap值,此处利用序列长度的一般为其赋值 8 | gap = len(L)/2 9 | #第一层循环:依次改变gap值对列表进行分组 10 | while (gap >= 1): 11 | #下面:利用直接插入排序的思想对分组数据进行排序 12 | #range(gap,len(L)):从gap开始 13 | for x in range(gap,len(L)): 14 | #range(x-gap,-1,-gap):从x-gap开始与选定元素开始倒序比较,每个比较元素之间间隔gap 15 | for i in range(x-gap,-1,-gap): 16 | #如果该组当中两个元素满足交换条件,则进行交换 17 | if L[i] > L[i+gap]: 18 | L[i], L[i + gap] = L[i + gap], L[i] 19 | #while循环条件折半 20 | gap = gap/2 21 | return L 22 | 23 | if __name__ == '__main__': 24 | nums = np.random.randint(1, 100, 10) 25 | nums2 = insert_shell(nums) 26 | print "Before: " 27 | print nums 28 | print "After: " 29 | print nums2 30 | for i in range(1, len(nums2)): 31 | if nums[i] < nums[i - 1]: 32 | print "Wrong Sort!" 33 | print "Success!" 34 | -------------------------------------------------------------------------------- /sort/05_shellSort_2.java: -------------------------------------------------------------------------------- 1 | //http://www.cnblogs.com/jingmoxukong/p/4303279.html#_label6 2 | package notes.javase.algorithm.sort; 3 | 4 | public class ShellSort { 5 | public void shellSort(int[] list) { 6 | int gap = list.length / 2; 7 | 8 | while (1 <= gap) { 9 | // 把距离为 gap 的元素编为一个组,扫描所有组 10 | for (int i = gap; i < list.length; i++) { 11 | int j = 0; 12 | int temp = list[i]; 13 | 14 | // 对距离为 gap 的元素组进行排序 15 | for (j = i - gap; j >= 0 && temp < list[j]; j = j - gap) { 16 | list[j + gap] = list[j]; 17 | } 18 | list[j + gap] = temp; 19 | } 20 | 21 | System.out.format("gap = %d:\t", gap); 22 | printAll(list); 23 | gap = gap / 2; // 减小增量 24 | } 25 | } 26 | 27 | // 打印完整序列 28 | public void printAll(int[] list) { 29 | for (int value : list) { 30 | System.out.print(value + "\t"); 31 | } 32 | System.out.println(); 33 | } 34 | 35 | public static void main(String[] args) { 36 | int[] array = { 37 | 9, 1, 2, 5, 7, 4, 8, 6, 3, 5 38 | }; 39 | 40 | // 调用希尔排序方法 41 | ShellSort shell = new ShellSort(); 42 | System.out.print("排序前:\t\t"); 43 | shell.printAll(array); 44 | shell.shellSort(array); 45 | System.out.print("排序后:\t\t"); 46 | shell.printAll(array); 47 | } 48 | } -------------------------------------------------------------------------------- /sort/06_heapSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | #-------------------------堆排序-------------------------------- 6 | #**********获取左右叶子节点********** 7 | def LEFT(i): 8 | return 2*i + 1 9 | def RIGHT(i): 10 | return 2*i + 2 11 | 12 | #********** 调整大顶堆 ********** 13 | #L:待调整序列 length: 序列长度 i:需要调整的结点 14 | def adjust_max_heap(L,length,i): 15 | #定义一个int值保存当前序列最大值的下标 16 | largest = i 17 | #执行循环操作:两个任务:1 寻找最大值的下标;2.最大值与父节点交换 18 | while (1): 19 | #获得序列左右叶子节点的下标 20 | left, right = LEFT(i), RIGHT(i) 21 | #当左叶子节点的下标小于序列长度 并且 左叶子节点的值大于父节点时,将左叶子节点的下标赋值给largest 22 | if (left < length) and (L[left] > L[i]): 23 | largest = left 24 | print('左叶子节点') 25 | else: 26 | largest = i 27 | #当右叶子节点的下标小于序列长度 并且 右叶子节点的值大于父节点时,将右叶子节点的下标值赋值给largest 28 | if (right < length) and (L[right] > L[largest]): 29 | largest = right 30 | print('右叶子节点') 31 | #如果largest不等于i 说明当前的父节点不是最大值,需要交换值 32 | if (largest != i): 33 | L[i], L[largest] = L[largest], L[i] 34 | i = largest 35 | print(largest) 36 | continue 37 | else: 38 | break 39 | 40 | #********** 建立大顶堆 ********** 41 | def build_max_heap(L): 42 | length = len(L) 43 | for x in range((int)((length-1)/2),-1,-1): 44 | adjust_max_heap(L,length,x) 45 | 46 | #********** 堆排序 ********** 47 | def heap_sort(L): 48 | #先建立大顶堆,保证最大值位于根节点;并且父节点的值大于叶子结点 49 | build_max_heap(L) 50 | #i:当前堆中序列的长度.初始化为序列的长度 51 | i = len(L) 52 | #执行循环:1. 每次取出堆顶元素置于序列的最后(len-1,len-2,len-3...) 53 | # 2. 调整堆,使其继续满足大顶堆的性质,注意实时修改堆中序列的长度 54 | while (i > 0): 55 | L[0], L[i - 1] = L[i - 1], L[0] 56 | #堆中序列长度减1 57 | i = i-1 58 | #调整大顶堆 59 | adjust_max_heap(L,i,0) 60 | return L 61 | 62 | if __name__ == '__main__': 63 | nums = np.random.randint(1, 100, 10) 64 | nums2 = heap_sort(nums) 65 | print "Before: " 66 | print nums 67 | print "After: " 68 | print nums2 69 | for i in range(1, len(nums2)): 70 | if nums[i] < nums[i - 1]: 71 | print "Wrong Sort!" 72 | print "Success!" 73 | -------------------------------------------------------------------------------- /sort/06_heapSort_recursive.java: -------------------------------------------------------------------------------- 1 | public class testHeapSort { 2 | public static int[] HeapSort(int[] a, int j){ 3 | // max heap and move max to the end 4 | for (int i = a.length - 1 - j; i >= 0; i--) { 5 | if (a[i] > a[i / 2]) { 6 | swap(a, i, i / 2); 7 | } 8 | } 9 | swap(a, 0, a.length - 1 - j); 10 | j++; 11 | // max heap for the rest 12 | if(j < a.length) { 13 | HeapSort(a, j); 14 | } 15 | return a; 16 | } 17 | 18 | public static void swap(int[] a, int i, int j) { 19 | int temp = a[i]; 20 | a[i] = a[j]; 21 | a[j] = temp; 22 | } 23 | 24 | public static void main(String[] args) { 25 | // TODO Auto-generated method stub 26 | int[] a = {3,2,4,5,4,9,7,8}; 27 | int j = 0; 28 | a = HeapSort(a, j); 29 | for (int i = 0; i < a.length; i++) { 30 | System.out.print(a[i] + " "); 31 | } 32 | } 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /sort/07_mergeSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | # 归并排序 6 | 7 | #### 这是合并的函数, 将序列L[first...mid]与序列L[mid+1...last]进行合并 8 | def mergearray(L,first,mid,last,temp): 9 | #对i,j,k分别进行赋值 10 | i, j, k = first, mid + 1, 0 11 | #当左右两边都有数时进行比较,取较小的数 12 | while (i <= mid) and (j <= last): 13 | if L[i] <= L[j]: 14 | temp[k] = L[i] 15 | i = i+1 16 | k = k+1 17 | else: 18 | temp[k] = L[j] 19 | j = j+1 20 | k = k+1 21 | #如果左边序列还有数 22 | while (i <= mid): 23 | temp[k] = L[i] 24 | i = i+1 25 | k = k+1 26 | #如果右边序列还有数 27 | while (j <= last): 28 | temp[k] = L[j] 29 | j = j+1 30 | k = k+1 31 | #将temp当中该段有序元素赋值给L待排序列使之部分有序 32 | for x in range(0,k): 33 | L[first+x] = temp[x] 34 | 35 | ### 这是分组的函数 36 | def merge_sort(L, first, last, temp): 37 | if first < last: 38 | mid = (int)((first + last) / 2) 39 | #使左边序列有序 40 | merge_sort(L, first, mid,temp) 41 | #使右边序列有序 42 | merge_sort(L, mid+1, last,temp) 43 | #将两个有序序列合并 44 | mergearray(L, first, mid, last, temp) 45 | 46 | ### 归并排序的函数 47 | def merge_sort_array(L): 48 | #声明一个长度为len(L)的空列表 49 | temp = len(L)*[None] 50 | #调用归并排序 51 | merge_sort(L, 0, len(L) - 1, temp) 52 | return L 53 | 54 | if __name__ == '__main__': 55 | nums = np.random.randint(1, 100, 10) 56 | nums2 = merge_sort_array(nums) 57 | print "Before: " 58 | print nums 59 | print "After: " 60 | print nums2 61 | for i in range(1, len(nums2)): 62 | if nums[i] < nums[i - 1]: 63 | print "Wrong Sort!" 64 | print "Success!" 65 | -------------------------------------------------------------------------------- /sort/07_mergeSort_Rec.java: -------------------------------------------------------------------------------- 1 | // http://www.vogella.com/tutorials/JavaAlgorithmsMergesort/article.html 2 | public class Mergesort { 3 | private int[] numbers; 4 | private int[] helper; 5 | 6 | private int number; 7 | 8 | public void sort(int[] values) { 9 | this.numbers = values; 10 | number = values.length; 11 | this.helper = new int[number]; 12 | mergesort(0, number - 1); 13 | } 14 | 15 | private void mergesort(int low, int high) { 16 | // check if low is smaller than high, if not then the array is sorted 17 | if (low < high) { 18 | // Get the index of the element which is in the middle 19 | int middle = low + (high - low) / 2; 20 | // Sort the left side of the array 21 | mergesort(low, middle); 22 | // Sort the right side of the array 23 | mergesort(middle + 1, high); 24 | // Combine them both 25 | merge(low, middle, high); 26 | } 27 | } 28 | 29 | private void merge(int low, int middle, int high) { 30 | 31 | // Copy both parts into the helper array 32 | for (int i = low; i <= high; i++) { 33 | helper[i] = numbers[i]; 34 | } 35 | 36 | int i = low; 37 | int j = middle + 1; 38 | int k = low; 39 | // Copy the smallest values from either the left or the right side back 40 | // to the original array 41 | while (i <= middle && j <= high) { 42 | if (helper[i] <= helper[j]) { 43 | numbers[k] = helper[i]; 44 | i++; 45 | } else { 46 | numbers[k] = helper[j]; 47 | j++; 48 | } 49 | k++; 50 | } 51 | // Copy the rest of the left side of the array into the target array 52 | while (i <= middle) { 53 | numbers[k] = helper[i]; 54 | k++; 55 | i++; 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sort/08_radixSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | import numpy as np 4 | 5 | #************************基数排序**************************** 6 | #确定排序的次数 7 | #排序的顺序跟序列中最大数的位数相关 8 | def radix_sort_nums(L): 9 | maxNum = L[0] 10 | #寻找序列中的最大数 11 | for x in L: 12 | if maxNum < x: 13 | maxNum = x 14 | #确定序列中的最大元素的位数 15 | times = 0 16 | while (maxNum > 0): 17 | maxNum = (int)(maxNum/10) 18 | times = times+1 19 | return times 20 | 21 | #找到num从低到高第pos位的数据 22 | def get_num_pos(num,pos): 23 | return ((int)(num/(10**(pos-1))))%10 24 | 25 | 26 | #基数排序 27 | def radix_sort(L): 28 | count = 10*[None] #存放各个桶的数据统计个数 29 | bucket = len(L)*[None] #暂时存放排序结果 30 | #从低位到高位依次执行循环 31 | for pos in range(1,radix_sort_nums(L)+1): 32 | #置空各个桶的数据统计 33 | for x in range(0,10): 34 | count[x] = 0 35 | #统计当前该位(个位,十位,百位....)的元素数目 36 | for x in range(0,len(L)): 37 | #统计各个桶将要装进去的元素个数 38 | j = get_num_pos(int(L[x]),pos) 39 | count[j] = count[j]+1 40 | #count[i]表示第i个桶的右边界索引 41 | for x in range(1,10): 42 | count[x] = count[x] + count[x-1] 43 | #将数据依次装入桶中 44 | for x in range(len(L)-1,-1,-1): 45 | #求出元素第K位的数字 46 | j = get_num_pos(L[x],pos) 47 | #放入对应的桶中,count[j]-1是第j个桶的右边界索引 48 | bucket[count[j]-1] = L[x] 49 | #对应桶的装入数据索引-1 50 | count[j] = count[j]-1 51 | # 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表 52 | for x in range(0,len(L)): 53 | L[x] = bucket[x] 54 | return L 55 | 56 | if __name__ == '__main__': 57 | nums = np.random.randint(1, 100, 10) 58 | nums2 = radix_sort(nums) 59 | print "Before: " 60 | print nums 61 | print "After: " 62 | print nums2 63 | for i in range(1, len(nums2)): 64 | if nums[i] < nums[i - 1]: 65 | print "Wrong Sort!" 66 | print "Success!" 67 | -------------------------------------------------------------------------------- /sort/08_radixSort2.java: -------------------------------------------------------------------------------- 1 | public class RadixSort { 2 | private static void radixSort(int[] array,int d) { 3 | int n = 1;//代表位数对应的数:1,10,100... 4 | int k = 0;//保存每一位排序后的结果用于下一位的排序输入 5 | int length = array.length; 6 | int[][] bucket = new int[10][length];//排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里 7 | int[] order = new int[length];//用于保存每个桶里有多少个数字 8 | while(n < d) { 9 | for(int num : array) {//将数组array里的每个数字放在相应的桶里 10 | int digit= (num / n) % 10; 11 | bucket[digit][order[digit]] = num; 12 | order[digit]++; 13 | } 14 | for(int i = 0; i < length; i++) {//将前一个循环生成的桶里的数据覆盖到原数组中用于保存这一位的排序结果 15 | if(order[i] != 0) {//这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中 16 | for(int j = 0; j < order[i]; j++) { 17 | array[k] = bucket[i][j]; 18 | k++; 19 | } 20 | } 21 | order[i] = 0;//将桶里计数器置0,用于下一次位排序 22 | } 23 | n* = 10; 24 | k=0;//将k置0,用于下一轮保存位排序结果 25 | } 26 | } 27 | 28 | public static void main(String[] args) { 29 | int[] A = new int[]{73,22, 93, 43, 55, 14, 28, 65, 39, 81}; 30 | radixSort(A, 100); 31 | for(int num : A) { 32 | System.out.println(num); 33 | } 34 | } 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /sort/08_radixSort2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #encoding=utf-8 3 | # https://zh.wikipedia.org/wiki/%E5%9F%BA%E6%95%B0%E6%8E%92%E5%BA%8F 4 | 5 | import math 6 | def sort(a, radix=10): 7 | """a为整数列表, radix为基数""" 8 | K = int(math.ceil(math.log(max(a), radix))) # 用K位数可表示任意整数 9 | bucket = [[] for i in range(radix)] # 不能用 [[]]*radix 10 | for i in range(1, K+1): # K次循环 11 | for val in a: 12 | bucket[val%(radix**i)/(radix**(i-1))].append(val) # 析取整数第K位数字 (从低到高) 13 | del a[:] 14 | for each in bucket: 15 | a.extend(each) # 桶合并 16 | bucket = [[] for i in range(radix)] -------------------------------------------------------------------------------- /sort/09_otherSort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: UTF-8 3 | -------------------------------------------------------------------------------- /sort/Quicksort.java: -------------------------------------------------------------------------------- 1 | public class Quicksort { 2 | private int[] numbers; 3 | private int number; 4 | 5 | public void sort(int[] values) { 6 | // check for empty or null array 7 | if (values ==null || values.length==0){ 8 | return; 9 | } 10 | this.numbers = values; 11 | number = values.length; 12 | quicksort(0, number - 1); 13 | } 14 | 15 | private void quicksort(int low, int high) { 16 | int i = low, j = high; 17 | // Get the pivot element from the middle of the list 18 | int pivot = numbers[low + (high-low)/2]; 19 | 20 | // Divide into two lists 21 | while (i <= j) { 22 | // If the current value from the left list is smaller then the pivot 23 | // element then get the next element from the left list 24 | while (numbers[i] < pivot) { 25 | i++; 26 | } 27 | // If the current value from the right list is larger then the pivot 28 | // element then get the next element from the right list 29 | while (numbers[j] > pivot) { 30 | j--; 31 | } 32 | 33 | // If we have found a values in the left list which is larger then 34 | // the pivot element and if we have found a value in the right list 35 | // which is smaller then the pivot element then we exchange the 36 | // values. 37 | // As we are done we can increase i and j 38 | if (i <= j) { 39 | exchange(i, j); 40 | i++; 41 | j--; 42 | } 43 | } 44 | // Recursion 45 | if (low < j) 46 | quicksort(low, j); 47 | if (i < high) 48 | quicksort(i, high); 49 | } 50 | 51 | private void exchange(int i, int j) { 52 | int temp = numbers[i]; 53 | numbers[i] = numbers[j]; 54 | numbers[j] = temp; 55 | } 56 | } 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /sort/README.md: -------------------------------------------------------------------------------- 1 | ### 排序相关 2 | quick sort 3 | 4 | [JAVA 示范](http://www.vogella.com/tutorials/JavaAlgorithmsQuicksort/article.html) 5 | 6 | [JAVA 示范: 程序员的内功——数据结构和算法系列](http://www.cnblogs.com/jingmoxukong/p/4329079.html) 7 | 8 | [Python动图讲解](http://www.jianshu.com/p/7d037c332a9d) 9 | 10 | -- 11 | ### 二叉树相关 12 | [基本遍历方法](BinaryTree_tranverse01.java) 13 | [按层遍历](BinaryTree_tranverse02.java) 14 | >等于图的宽度优先搜索的应用。 15 | > * last: 表示正在打印当前行的最右节点,初始化为root 16 | > * nlast:表示下一行的最右节点,初始化为root 17 | > * queue:存放某一层的节点,初始化为root 18 | > 当queue不为空的时: 19 | > ---- 每次依次弹出节点打印,并且将左右孩子加入队列, 20 | > ---- nlast随着加入移动更新。 21 | > ---- 打印到last指定元素时终止。 22 | > ---- 更新last为nlast,可以加入height更新。 23 | 24 | [序列化和反序列化] 25 | > str = "12!3!#!#!" 26 | > values = ["12", "3", "#", "#", "#"] 27 | > 12 28 | > 3 null 29 | > null null 30 | 31 | -- 32 | ### 字符串相关 33 | 检查旋转词 34 | > 看是str2 是否存在str1 + str1 中。 35 | 36 | 将句子中的字符串按照空格隔开的次序翻转 37 | > 完成一个逆序函数,单词逆序,然后整个逆序 38 | 39 | 将字符串左边的n个字符完全移动到右边 40 | > 前n逆序,后m逆序,整体逆序 41 | 42 | 将N个字符串拼接成字典顺序最小的字符串 43 | > 实际上是一个排序,排序比较的是str1 + str2 和 str2 + str1 字符串的字典顺序 -------------------------------------------------------------------------------- /sort/_1156494-62f859c2ac6f95ff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/sort/_1156494-62f859c2ac6f95ff.png -------------------------------------------------------------------------------- /sort/_1156494-ab4cecff133d87b3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/sort/_1156494-ab4cecff133d87b3.png -------------------------------------------------------------------------------- /sort/_大根堆演示.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/sort/_大根堆演示.jpg -------------------------------------------------------------------------------- /sort/quick_sort.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def quickSort(nums, low, high): 4 | i = low 5 | j = high 6 | pivot = nums[(low + high) / 2] 7 | while (i <= j): 8 | while (nums[i] < pivot): 9 | i += 1 10 | while (nums[j] > pivot): 11 | j -= 1 12 | if (i <= j): 13 | temp = nums[i] 14 | nums[i] = nums[j] 15 | nums[j] = temp 16 | i += 1 17 | j -= 1 18 | if (i < high): 19 | quickSort(nums, i, high) 20 | if (j > low): 21 | quickSort(nums, low, j) 22 | return nums 23 | 24 | if __name__ == "__main__": 25 | nums = np.random.randint(0, 999, size = 10) 26 | result = quickSort(nums, 0, len(nums) - 1) 27 | print 'Before: ' 28 | print nums 29 | print 'After: ' 30 | print result 31 | 32 | -------------------------------------------------------------------------------- /sort2/HeapSort.java: -------------------------------------------------------------------------------- 1 | package notes.javase.algorithm.sort; 2 | 3 | public class HeapSort { 4 | 5 | public void HeapAdjust(int[] array, int parent, int length) { 6 | int temp = array[parent]; // temp保存当前父节点 7 | int child = 2 * parent + 1; // 先获得左孩子 8 | 9 | while (child < length) { 10 | // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点 11 | if (child + 1 < length && array[child] < array[child + 1]) { 12 | child++; 13 | } 14 | 15 | // 如果父结点的值已经大于孩子结点的值,则直接结束 16 | if (temp >= array[child]) 17 | break; 18 | 19 | // 把孩子结点的值赋给父结点 20 | array[parent] = array[child]; 21 | 22 | // 选取孩子结点的左孩子结点,继续向下筛选 23 | parent = child; 24 | child = 2 * child + 1; 25 | } 26 | 27 | array[parent] = temp; 28 | } 29 | 30 | public void heapSort(int[] list) { 31 | // 循环建立初始堆 32 | for (int i = list.length / 2; i >= 0; i--) { 33 | HeapAdjust(list, i, list.length - 1); 34 | } 35 | 36 | // 进行n-1次循环,完成排序 37 | for (int i = list.length - 1; i > 0; i--) { 38 | // 最后一个元素和第一元素进行交换 39 | int temp = list[i]; 40 | list[i] = list[0]; 41 | list[0] = temp; 42 | 43 | // 筛选 R[0] 结点,得到i-1个结点的堆 44 | HeapAdjust(list, 0, i); 45 | System.out.format("第 %d 趟: \t", list.length - i); 46 | printPart(list, 0, list.length - 1); 47 | } 48 | } 49 | 50 | // 打印序列 51 | public void printPart(int[] list, int begin, int end) { 52 | for (int i = 0; i < begin; i++) { 53 | System.out.print("\t"); 54 | } 55 | for (int i = begin; i <= end; i++) { 56 | System.out.print(list[i] + "\t"); 57 | } 58 | System.out.println(); 59 | } 60 | 61 | public static void main(String[] args) { 62 | // 初始化一个序列 63 | int[] array = { 64 | 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 65 | }; 66 | 67 | // 调用快速排序方法 68 | HeapSort heap = new HeapSort(); 69 | System.out.print("排序前:\t"); 70 | heap.printPart(array, 0, array.length - 1); 71 | heap.heapSort(array); 72 | System.out.print("排序后:\t"); 73 | heap.printPart(array, 0, array.length - 1); 74 | } 75 | } -------------------------------------------------------------------------------- /sort2/InsetSort.java: -------------------------------------------------------------------------------- 1 | package notes.javase.algorithm.sort; 2 | 3 | import java.util.Random; 4 | 5 | public class InsertSort { 6 | 7 | public void insertSort(int[] list) { 8 | // 打印第一个元素 9 | System.out.format("i = %d:\t", 0); 10 | printPart(list, 0, 0); 11 | 12 | // 第1个数肯定是有序的,从第2个数开始遍历,依次插入有序序列 13 | for (int i = 1; i < list.length; i++) { 14 | int j = 0; 15 | int temp = list[i]; // 取出第i个数,和前i-1个数比较后,插入合适位置 16 | 17 | // 因为前i-1个数都是从小到大的有序序列,所以只要当前比较的数(list[j])比temp大,就把这个数后移一位 18 | for (j = i - 1; j >= 0 && temp < list[j]; j--) { 19 | list[j + 1] = list[j]; 20 | } 21 | list[j + 1] = temp; 22 | 23 | System.out.format("i = %d:\t", i); 24 | printPart(list, 0, i); 25 | } 26 | } 27 | 28 | // 打印序列 29 | public void printPart(int[] list, int begin, int end) { 30 | for (int i = 0; i < begin; i++) { 31 | System.out.print("\t"); 32 | } 33 | for (int i = begin; i <= end; i++) { 34 | System.out.print(list[i] + "\t"); 35 | } 36 | System.out.println(); 37 | } 38 | 39 | public static void main(String[] args) { 40 | // 初始化一个随机序列 41 | final int MAX_SIZE = 10; 42 | int[] array = new int[MAX_SIZE]; 43 | Random random = new Random(); 44 | for (int i = 0; i < MAX_SIZE; i++) { 45 | array[i] = random.nextInt(MAX_SIZE); 46 | } 47 | 48 | // 调用冒泡排序方法 49 | InsertSort insert = new InsertSort(); 50 | System.out.print("排序前:\t"); 51 | insert.printPart(array, 0, array.length - 1); 52 | insert.insertSort(array); 53 | System.out.print("排序后:\t"); 54 | insert.printPart(array, 0, array.length - 1); 55 | } 56 | } -------------------------------------------------------------------------------- /sort2/QuickSort.java: -------------------------------------------------------------------------------- 1 | public class QuickSort { 2 | 3 | public int division(int[] list, int left, int right) { 4 | // 以最左边的数(left)为基准 5 | int base = list[left]; 6 | while (left < right) { 7 | // 从序列右端开始,向左遍历,直到找到小于base的数 8 | while (left < right && list[right] >= base) 9 | right--; 10 | // 找到了比base小的元素,将这个元素放到最左边的位置 11 | list[left] = list[right]; 12 | 13 | // 从序列左端开始,向右遍历,直到找到大于base的数 14 | while (left < right && list[left] <= base) 15 | left++; 16 | // 找到了比base大的元素,将这个元素放到最右边的位置 17 | list[right] = list[left]; 18 | } 19 | 20 | // 最后将base放到left位置。此时,left位置的左侧数值应该都比left小; 21 | // 而left位置的右侧数值应该都比left大。 22 | list[left] = base; 23 | return left; 24 | } 25 | 26 | private void quickSort(int[] list, int left, int right) { 27 | 28 | // 左下标一定小于右下标,否则就越界了 29 | if (left < right) { 30 | // 对数组进行分割,取出下次分割的基准标号 31 | int base = division(list, left, right); 32 | 33 | System.out.format("base = %d:\t", list[base]); 34 | printPart(list, left, right); 35 | 36 | // 对“基准标号“左侧的一组数值进行递归的切割,以至于将这些数值完整的排序 37 | quickSort(list, left, base - 1); 38 | 39 | // 对“基准标号“右侧的一组数值进行递归的切割,以至于将这些数值完整的排序 40 | quickSort(list, base + 1, right); 41 | } 42 | } 43 | 44 | // 打印序列 45 | public void printPart(int[] list, int begin, int end) { 46 | for (int i = 0; i < begin; i++) { 47 | System.out.print("\t"); 48 | } 49 | for (int i = begin; i <= end; i++) { 50 | System.out.print(list[i] + "\t"); 51 | } 52 | System.out.println(); 53 | } 54 | 55 | public static void main(String[] args) { 56 | // 初始化一个序列 57 | int[] array = { 58 | 1, 3, 4, 5, 2, 6, 9, 7, 8, 0 59 | }; 60 | 61 | // 调用快速排序方法 62 | QuickSort quick = new QuickSort(); 63 | System.out.print("排序前:\t\t"); 64 | quick.printPart(array, 0, array.length - 1); 65 | quick.quickSort(array, 0, array.length - 1); 66 | System.out.print("排序后:\t\t"); 67 | quick.printPart(array, 0, array.length - 1); 68 | } 69 | } -------------------------------------------------------------------------------- /sort2/README.md: -------------------------------------------------------------------------------- 1 | [JAVA 示范: 程序员的内功——数据结构和算法系列](http://www.cnblogs.com/jingmoxukong/p/4329079.html) 2 | 3 | 注意: 4 | 这里的[quicksort.java](./QuickSort.java)代码风格简单,但是边界条件容易出错。参考sort目录下的 [04_quickSort.java](../sort/04_quickSort.java),对比他们是如何实现的。 -------------------------------------------------------------------------------- /sort2/RadixSort.java: -------------------------------------------------------------------------------- 1 | package notes.javase.algorithm.sort; 2 | // LSD法实现 3 | 4 | public class RadixSort { 5 | // 获取x这个数的d位数上的数字 6 | // 比如获取123的1位数,结果返回3 7 | public int getDigit(int x, int d) { 8 | int a[] = { 9 | 1, 1, 10, 100 10 | }; // 本实例中的最大数是百位数,所以只要到100就可以了 11 | return ((x / a[d]) % 10); 12 | } 13 | 14 | public void radixSort(int[] list, int begin, int end, int digit) { 15 | final int radix = 10; // 基数 16 | int i = 0, j = 0; 17 | int[] count = new int[radix]; // 存放各个桶的数据统计个数 18 | int[] bucket = new int[end - begin + 1]; 19 | 20 | // 按照从低位到高位的顺序执行排序过程 21 | for (int d = 1; d <= digit; d++) { 22 | // 置空各个桶的数据统计 23 | for (i = 0; i < radix; i++) { 24 | count[i] = 0; 25 | } 26 | // 统计各个桶将要装入的数据个数 27 | for (i = begin; i <= end; i++) { 28 | j = getDigit(list[i], d); 29 | count[j]++; 30 | } 31 | // count[i]表示第i个桶的右边界索引 32 | for (i = 1; i < radix; i++) { 33 | count[i] = count[i] + count[i - 1]; 34 | } 35 | // 将数据依次装入桶中 36 | // 这里要从右向左扫描,保证排序稳定性 37 | for (i = end; i >= begin; i--) { 38 | j = getDigit(list[i], d); // 求出关键码的第k位的数字, 例如:576的第3位是5 39 | bucket[count[j] - 1] = list[i]; // 放入对应的桶中,count[j]-1是第j个桶的右边界索引 40 | count[j]--; // 对应桶的装入数据索引减一 41 | } 42 | // 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表 43 | for (i = begin, j = 0; i <= end; i++, j++) { 44 | list[i] = bucket[j]; 45 | } 46 | } 47 | } 48 | 49 | public int[] sort(int[] list) { 50 | radixSort(list, 0, list.length - 1, 3); 51 | return list; 52 | } 53 | 54 | 55 | 56 | // 打印完整序列 57 | public void printAll(int[] list) { 58 | for (int value : list) { 59 | System.out.print(value + "\t"); 60 | } 61 | System.out.println(); 62 | } 63 | 64 | 65 | 66 | public static void main(String[] args) { 67 | int[] array = { 68 | 50, 123, 543, 187, 49, 30, 0, 2, 11, 100 69 | }; 70 | RadixSort radix = new RadixSort(); 71 | System.out.print("排序前:\t\t"); 72 | radix.printAll(array); 73 | radix.sort(array); 74 | System.out.print("排序后:\t\t"); 75 | radix.printAll(array); 76 | } 77 | } -------------------------------------------------------------------------------- /sort2/SelectionSort.java: -------------------------------------------------------------------------------- 1 | package notes.javase.algorithm.sort; 2 | 3 | import java.util.Random; 4 | 5 | public class SelectionSort { 6 | 7 | public void selectionSort(int[] list) { 8 | // 需要遍历获得最小值的次数 9 | // 要注意一点,当要排序 N 个数,已经经过 N-1 次遍历后,已经是有序数列 10 | for (int i = 0; i < list.length - 1; i++) { 11 | int temp = 0; 12 | int index = i; // 用来保存最小值得索引 13 | 14 | // 寻找第i个小的数值 15 | for (int j = i + 1; j < list.length; j++) { 16 | if (list[index] > list[j]) { 17 | index = j; 18 | } 19 | } 20 | 21 | // 将找到的第i个小的数值放在第i个位置上 22 | temp = list[index]; 23 | list[index] = list[i]; 24 | list[i] = temp; 25 | 26 | System.out.format("第 %d 趟:\t", i + 1); 27 | printAll(list); 28 | } 29 | } 30 | 31 | // 打印完整序列 32 | public void printAll(int[] list) { 33 | for (int value : list) { 34 | System.out.print(value + "\t"); 35 | } 36 | System.out.println(); 37 | } 38 | 39 | public static void main(String[] args) { 40 | // 初始化一个随机序列 41 | final int MAX_SIZE = 10; 42 | int[] array = new int[MAX_SIZE]; 43 | Random random = new Random(); 44 | for (int i = 0; i < MAX_SIZE; i++) { 45 | array[i] = random.nextInt(MAX_SIZE); 46 | } 47 | 48 | // 调用冒泡排序方法 49 | SelectionSort selection = new SelectionSort(); 50 | System.out.print("排序前:\t"); 51 | selection.printAll(array); 52 | selection.selectionSort(array); 53 | System.out.print("排序后:\t"); 54 | selection.printAll(array); 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /sort2/ShellSort.java: -------------------------------------------------------------------------------- 1 | package notes.javase.algorithm.sort; 2 | 3 | public class ShellSort { 4 | public void shellSort(int[] list) { 5 | int gap = list.length / 2; 6 | 7 | while (1 <= gap) { 8 | // 把距离为 gap 的元素编为一个组,扫描所有组 9 | for (int i = gap; i < list.length; i++) { 10 | int j = 0; 11 | int temp = list[i]; 12 | 13 | // 对距离为 gap 的元素组进行排序 14 | for (j = i - gap; j >= 0 && temp < list[j]; j = j - gap) { 15 | list[j + gap] = list[j]; 16 | } 17 | list[j + gap] = temp; 18 | } 19 | 20 | System.out.format("gap = %d:\t", gap); 21 | printAll(list); 22 | gap = gap / 2; // 减小增量 23 | } 24 | } 25 | 26 | // 打印完整序列 27 | public void printAll(int[] list) { 28 | for (int value : list) { 29 | System.out.print(value + "\t"); 30 | } 31 | System.out.println(); 32 | } 33 | 34 | public static void main(String[] args) { 35 | int[] array = { 36 | 9, 1, 2, 5, 7, 4, 8, 6, 3, 5 37 | }; 38 | 39 | // 调用希尔排序方法 40 | ShellSort shell = new ShellSort(); 41 | System.out.print("排序前:\t\t"); 42 | shell.printAll(array); 43 | shell.shellSort(array); 44 | System.out.print("排序后:\t\t"); 45 | shell.printAll(array); 46 | } 47 | } -------------------------------------------------------------------------------- /stack/README.md: -------------------------------------------------------------------------------- 1 | 【题目一】 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。 2 | > 栈的常用操作为pop, peek, push, isEmpty. 完成这个题目的时候可以考虑使用两个站结构存储。其中一个栈结构存储最小的元素,另一个栈存储所有元素。 3 | 【题目二】 怎么用数组结构实现队列和栈结构? 4 | > add 增加一个元索 5 | > remove 移除并返回队列头部的元素 6 | > element 返回队列头部的元素 7 | > offer 添加一个元素并返回true 8 | > poll 移除并返问队列头部的元素 9 | > peek 返回队列头部的元素 10 | > 无put 添加一个元素 11 | > 无take 移除并返回队列头部的元素 12 | 【题目三】 由两个栈组成队列,由两个队列组成栈 13 | > 用一个push栈 + 一个pop栈 组成队列 14 | > 用一个队列 + 一个help队列 组成栈 15 | 16 | 【题目四】 一个栈依次压入1、2、3、4、5,那么从栈顶到栈底分别为5、4、3、2、1。将这个栈 转置后,从栈顶到栈底为1、2、3、4、5,也就是实现栈中元素的逆序,但是只能用 递归函数来实现,不能用其他数据结构。 17 | > 递归其实相当于一个栈结构。 18 | > 思路为,取出栈底元素(递归实现),将余下部分翻转(递归调用), 将栈底元素放回。 19 | 20 | 【题目五】 汉诺塔问题比较经典,这里修改一下游戏规则: 不能从最左侧的塔直接移动到最右侧; 不能从最右侧直接移动到最左侧; 最左到最右的互相移动必须经过中间; 求当塔有N层的时候,打印最优移动过程和最优移动总步数。 21 | > to be continue 22 | 23 | 24 | 【题目六】 给定一个整型数组arr和整数w,表示一个大小为w的窗口从数组 的最左边滑到最右边。求每次窗口内的最大值,并返回结果数组 25 | > 用一个LinkedList存储最大值,每次新的元素进来,判断是否从last加入,并且判断是否有过期元素从first弹出。 26 | > 27 | > **重要** 这是一个重要的最大值最小值的更新结构,有的题目可能需要用stack完成,根据题目的要求。例如找到数组中下一个比当前元素大的数。但是都是利用一个子结构完成最大值最小值的更新。 28 | 29 | 【题目七】 一个数组的MaxTree定义如下 30 | 1.数组必须没有重复元素 31 | 2.MaxTree是一棵二叉树,数组的每一个值对应一个二叉树节点 32 | 3.包括MaxTree树在内且在其中的每一棵子树上,值最大的节点 都是树的头。 33 | 给定一个没有重复元素的数组arr,写出生成这个数组的MaxTree 的函数,要求如果数组长度为N,则时间复杂度为O(N)、额外空 间复杂度为O(N)。 34 | > 可以用堆排序! 35 | > **重要** 可以用*最俗栈结构*, 该栈结构中始终保持由大到小的排序。 36 | 37 | 【题目八】 给定String类型的数组strArr,再给定整数k,请严格按照排名顺序 打印出现次数前k名的字符串。 【题目八扩展】 设计并实现TopKRecord结构。可以不断地向其中加入字符串。并 且可以随时打印加入次数最多前k个字符串。 38 | > to be continue 39 | 40 | 【题目九】 有N个长度不一样的数组,所有数组中的元素都是从小到大有序 排列的,请从大到小打印这N个数组整体的前K个数。 41 | 42 | 【题目十】 有一个源源不断地吐出整数的数据流,假设你有足够的空间来保 存吐出的数。请设计一个名叫MedianHolder的结构,可以方便得 到吐出所有数的中位数。 43 | > 创建大根堆和小根堆分别存储前一半和后一半。**实际上优先队列,heap可以看错stack结构**,这里用到了优先队列存储最大最小值,并放在顶部,思想可以看做是stack。 44 | 45 | 【题目十一】 给定一个整型矩阵map,其中的值只有0和1两种,求其中全是1的 所有矩形区域中,最大的矩形区域为1的数量。 例如: 1110 其中,最大的矩形区域有3个1,所以返回3。 再如: 1011 1111 1110 其中,最大的矩形区域有6个1,所以返回6。 46 | 47 | 【题目十二】 给定数组arr和整数num,返回一共有多少个子数组满足如下情况 48 | Max{arr[i..j]} – Min{arr[i..j]} <= num 其中,Max{arr[i..j]}表示子数组arr[i..j]中的最大值;Min{arr[i..j]}表 示子数组arr[i..j]中的最小值 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /tree/BinaryTree_Traversal.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 本代码由九章算法编辑提供。版权所有,转发请注明出处。 3 | * - 九章算法致力于帮助更多中国人找到好的工作,教师团队均来自硅谷和国内的一线大公司在职工程师。 4 | * - 现有的面试培训课程包括:九章算法班,系统设计班,算法强化班,Java入门与基础算法班,Android 项目实战班,Big Data 项目实战班, 5 | * - 更多详情请见官方网站:http://www.jiuzhang.com/?source=code 6 | */ 7 | 8 | Version 0: Non-Recursion (Recommend) 9 | /** 10 | * Definition for binary tree 11 | * public class TreeNode { 12 | * int val; 13 | * TreeNode left; 14 | * TreeNode right; 15 | * TreeNode(int x) { val = x; } 16 | * } 17 | */ 18 | public class Solution { 19 | public List preorderTraversal(TreeNode root) { 20 | Stack stack = new Stack(); 21 | List preorder = new ArrayList(); 22 | 23 | if (root == null) { 24 | return preorder; 25 | } 26 | 27 | stack.push(root); 28 | while (!stack.empty()) { 29 | TreeNode node = stack.pop(); 30 | preorder.add(node.val); 31 | if (node.right != null) { 32 | stack.push(node.right); 33 | } 34 | if (node.left != null) { 35 | stack.push(node.left); 36 | } 37 | } 38 | 39 | return preorder; 40 | } 41 | } 42 | 43 | //Version 1: Traverse 44 | public class Solution { 45 | public ArrayList preorderTraversal(TreeNode root) { 46 | ArrayList result = new ArrayList(); 47 | traverse(root, result); 48 | return result; 49 | } 50 | // 把root为跟的preorder加入result里面 51 | private void traverse(TreeNode root, ArrayList result) { 52 | if (root == null) { 53 | return; 54 | } 55 | 56 | result.add(root.val); 57 | traverse(root.left, result); 58 | traverse(root.right, result); 59 | } 60 | } 61 | 62 | //Version 2: Divide & Conquer 63 | public class Solution { 64 | public ArrayList preorderTraversal(TreeNode root) { 65 | ArrayList result = new ArrayList(); 66 | // null or leaf 67 | if (root == null) { 68 | return result; 69 | } 70 | 71 | // Divide 72 | ArrayList left = preorderTraversal(root.left); 73 | ArrayList right = preorderTraversal(root.right); 74 | 75 | // Conquer 76 | result.add(root.val); 77 | result.addAll(left); 78 | result.addAll(right); 79 | return result; 80 | } 81 | } -------------------------------------------------------------------------------- /tree/二叉树 review _ 岁月轻狂.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XingxingHuang/Code_Practice/dce8cf254f99253d3b26def6fc0626d95b508998/tree/二叉树 review _ 岁月轻狂.pdf --------------------------------------------------------------------------------