Repository: bjweimengshu/ProgrammerXiaohui Branch: master Commit: 5f77405fbcca Files: 33 Total size: 61.6 KB Directory structure: gitextract_79e5z20f/ ├── README.md └── src/ ├── chapter1/ │ ├── part2/ │ │ └── TimeComplex.java │ └── part3/ │ └── SpaceComplex.java ├── chapter2/ │ ├── part1/ │ │ └── MyArray.java │ ├── part2/ │ │ └── MyLinkedList.java │ └── part3/ │ └── MyQueue.java ├── chapter3/ │ ├── part2/ │ │ ├── BinaryTreeTraversal.java │ │ ├── BinaryTreeTraversalLevel.java │ │ └── BinaryTreeTraversalStack.java │ ├── part3/ │ │ └── HeapOperator.java │ └── part4/ │ └── PriorityQueue.java ├── chapter4/ │ ├── part2/ │ │ ├── BubbleSort.java │ │ └── CockTailSort.java │ ├── part3/ │ │ ├── QuickSort.java │ │ └── QuickSortWithStack.java │ ├── part4/ │ │ └── HeapSort.java │ └── part5/ │ ├── BucketSort.java │ └── CountSort.java ├── chapter5/ │ ├── part10/ │ │ └── BigNumberSum.java │ ├── part11/ │ │ └── GoldMining.java │ ├── part12/ │ │ └── FindLostNum.java │ ├── part2/ │ │ └── LinkedListCycle.java │ ├── part3/ │ │ └── MinStack.java │ ├── part4/ │ │ └── GreatestCommonDivisor.java │ ├── part5/ │ │ └── PowerOf2.java │ ├── part6/ │ │ └── MaxSortedDistance.java │ ├── part7/ │ │ └── StackQueue.java │ ├── part8/ │ │ └── FindNearestNumber.java │ └── part9/ │ └── RemoveKDigits.java └── chapter6/ ├── part2/ │ └── MyBitmap.java ├── part3/ │ └── LRUCache.java ├── part4/ │ └── AStar.java └── part5/ └── Redpackage.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ 来到这里的朋友们,很高兴你们能看到小灰的拙作。 小灰把书中各个章节所涉及到的代码,都总结到了这个项目当中,让大家可以更方便地学习和调试。 小伙伴们对代码有哪些问题和意见,也欢迎向小灰提出,在这里感谢大家的支持! 最后,欢迎大家关注小灰的技术公众号,直接在微信上搜索 “程序员小灰” 即可看到。 祝大家在算法的道路上学有所成! 针对《漫画算法》的第一次印刷版本,小灰整理了一个勘误表,欢迎大家指正:http://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=505714242&idx=1&sn=59526f45b94db2f4be750273431e8867&chksm=0c99e4983bee6d8eb4beed7f6143bbbc00659f32056b37db1d3f1b925ca6867d7d2c34d6ad64#rd ================================================ FILE: src/chapter1/part2/TimeComplex.java ================================================ package chapter1.part2; /** * Created by weimengshu on 2018/8/24. */ public class TimeComplex { void eat1(int n){ for(int i=0; i1; i/=2){ System.out.println("等待一天"); System.out.println("等待一天"); System.out.println("等待一天"); System.out.println("等待一天"); System.out.println("吃一半面包"); } } void eat3(int n){ System.out.println("等待一天"); System.out.println("吃一个鸡腿"); } void eat4(int n){ for(int i=0; isize){ throw new IndexOutOfBoundsException("超出数组实际元素范围!"); } //如果实际元素达到数组容量上线,数组扩容 if(size >= array.length){ resize(); } //从右向左循环,逐个元素向右挪一位。 for(int i=size-1; i>=index; i--){ array[i+1] = array[i]; } //腾出的位置放入新元素 array[index] = element; size++; } /** * 数组扩容 */ public void resize(){ int[] arrayNew = new int[array.length*2]; //从旧数组拷贝到新数组 System.arraycopy(array, 0, arrayNew, 0, array.length); array = arrayNew; } /** * 数组删除元素 * @param index 删除的位置 */ public int delete(int index) throws Exception { //判断访问下标是否超出范围 if(index<0 || index>=size){ throw new IndexOutOfBoundsException("超出数组实际元素范围!"); } int deletedElement = array[index]; //从左向右循环,逐个元素向左挪一位。 for(int i=index; isize) { throw new IndexOutOfBoundsException("超出链表节点范围!"); } Node insertedNode = new Node(data); if(size == 0){ //空链表 head = insertedNode; last = insertedNode; } else if(index == 0){ //插入头部 insertedNode.next = head; head = insertedNode; }else if(size == index){ //插入尾部 last.next = insertedNode; last = insertedNode; }else { //插入中间 Node prevNode = get(index-1); insertedNode.next = prevNode.next; prevNode.next = insertedNode; } size++; } /** * 链表删除元素 * @param index 删除的位置 */ public Node remove(int index) throws Exception { if (index<0 || index>=size) { throw new IndexOutOfBoundsException("超出链表节点范围!"); } Node removedNode = null; if(index == 0){ //删除头节点 removedNode = head; head = head.next; if(size == 1){ last = null; } }else if(index == size-1){ //删除尾节点 Node prevNode = get(index-1); removedNode = prevNode.next; prevNode.next = null; last = prevNode; }else { //删除中间节点 Node prevNode = get(index-1); Node nextNode = prevNode.next.next; removedNode = prevNode.next; prevNode.next = nextNode; } size--; return removedNode; } /** * 链表查找元素 * @param index 查找的位置 */ public Node get(int index) throws Exception { if (index<0 || index>=size) { throw new IndexOutOfBoundsException("超出链表节点范围!"); } Node temp = head; for(int i=0; i inputList){ TreeNode node = null; if(inputList==null || inputList.isEmpty()){ return null; } Integer data = inputList.removeFirst(); //这里的判空很关键。如果元素是空,说明该节点不存在,跳出这一层递归;如果元素非空,继续递归构建该节点的左右孩子。 if(data != null){ node = new TreeNode(data); node.leftChild = createBinaryTree(inputList); node.rightChild = createBinaryTree(inputList); } return node; } /** * 二叉树前序遍历 * @param node 二叉树节点 */ public static void preOrderTraversal(TreeNode node){ if(node == null){ return; } System.out.println(node.data); preOrderTraversal(node.leftChild); preOrderTraversal(node.rightChild); } /** * 二叉树中序遍历 * @param node 二叉树节点 */ public static void inOrderTraversal(TreeNode node){ if(node == null){ return; } inOrderTraversal(node.leftChild); System.out.println(node.data); inOrderTraversal(node.rightChild); } /** * 二叉树后序遍历 * @param node 二叉树节点 */ public static void postOrderTraversal(TreeNode node){ if(node == null){ return; } postOrderTraversal(node.leftChild); postOrderTraversal(node.rightChild); System.out.println(node.data); } /** * 二叉树节点 */ private static class TreeNode { int data; TreeNode leftChild; TreeNode rightChild; TreeNode(int data) { this.data = data; } } public static void main(String[] args) { LinkedList inputList = new LinkedList(Arrays.asList(new Integer[]{3,2,9,null,null,10,null,null,8,null,4,})); TreeNode treeNode = createBinaryTree(inputList); System.out.println("前序遍历:"); preOrderTraversal(treeNode); System.out.println("中序遍历:"); inOrderTraversal(treeNode); System.out.println("后序遍历:"); postOrderTraversal(treeNode); } } ================================================ FILE: src/chapter3/part2/BinaryTreeTraversalLevel.java ================================================ package chapter3.part2; import java.util.Arrays; import java.util.LinkedList; import java.util.Queue; /** * Created by weimengshu on 2018/9/22. */ public class BinaryTreeTraversalLevel { /** * 构建二叉树 * @param inputList 输入序列 */ public static TreeNode createBinaryTree(LinkedList inputList){ TreeNode node = null; if(inputList==null || inputList.isEmpty()){ return null; } Integer data = inputList.removeFirst(); //这里的判空很关键。如果元素是空,说明该节点不存在,跳出这一层递归;如果元素非空,继续递归构建该节点的左右孩子。 if(data != null){ node = new TreeNode(data); node.leftChild = createBinaryTree(inputList); node.rightChild = createBinaryTree(inputList); } return node; } /** * 二叉树层序遍历 * @param root 二叉树根节点 */ public static void levelOrderTraversal(TreeNode root){ Queue queue = new LinkedList(); queue.offer(root); while(!queue.isEmpty()){ TreeNode node = queue.poll(); System.out.println(node.data); if(node.leftChild != null){ queue.offer(node.leftChild); } if(node.rightChild != null){ queue.offer(node.rightChild); } } } /** * 二叉树节点 */ private static class TreeNode { int data; TreeNode leftChild; TreeNode rightChild; TreeNode(int data) { this.data = data; } } public static void main(String[] args) { LinkedList inputList = new LinkedList(Arrays.asList(new Integer[]{3,2,9,null,null,10,null,null,8,null,4,})); TreeNode treeNode = createBinaryTree(inputList); System.out.println("层序遍历:"); levelOrderTraversal(treeNode); } } ================================================ FILE: src/chapter3/part2/BinaryTreeTraversalStack.java ================================================ package chapter3.part2; import java.util.Arrays; import java.util.LinkedList; import java.util.Stack; /** * Created by weimengshu on 2018/9/22. */ public class BinaryTreeTraversalStack { /** * 构建二叉树 * @param inputList 输入序列 */ public static TreeNode createBinaryTree(LinkedList inputList){ TreeNode node = null; if(inputList==null || inputList.isEmpty()){ return null; } Integer data = inputList.removeFirst(); //这里的判空很关键。如果元素是空,说明该节点不存在,跳出这一层递归;如果元素非空,继续递归构建该节点的左右孩子。 if(data != null){ node = new TreeNode(data); node.leftChild = createBinaryTree(inputList); node.rightChild = createBinaryTree(inputList); } return node; } /** * 二叉树非递归前序遍历 * @param root 二叉树根节点 */ public static void preOrderTraveralWithStack(TreeNode root){ Stack stack = new Stack(); TreeNode treeNode = root; while(treeNode!=null || !stack.isEmpty()){ //迭代访问节点的左孩子,并入栈 while (treeNode != null){ System.out.println(treeNode.data); stack.push(treeNode); treeNode = treeNode.leftChild; } //如果节点没有左孩子,则弹出栈顶节点,访问节点右孩子 if(!stack.isEmpty()){ treeNode = stack.pop(); treeNode = treeNode.rightChild; } } } /** * 二叉树节点 */ private static class TreeNode { int data; TreeNode leftChild; TreeNode rightChild; TreeNode(int data) { this.data = data; } } public static void main(String[] args) { LinkedList inputList = new LinkedList(Arrays.asList(new Integer[]{3,2,9,null,null,10,null,null,8,null,4,})); TreeNode treeNode = createBinaryTree(inputList); preOrderTraveralWithStack(treeNode); } } ================================================ FILE: src/chapter3/part3/HeapOperator.java ================================================ package chapter3.part3; /** * Created by weimengshu on 2018/7/13. */ import java.util.Arrays; public class HeapOperator { /** * 上浮调整 * @param array 待调整的堆 */ public static void upAdjust(int[] array) { int childIndex = array.length-1; int parentIndex = (childIndex-1)/2; // temp保存插入的叶子节点值,用于最后的赋值 int temp = array[childIndex]; while (childIndex > 0 && temp < array[parentIndex]) { //无需真正交换,单向赋值即可 array[childIndex] = array[parentIndex]; childIndex = parentIndex; parentIndex = (parentIndex-1) / 2; } array[childIndex] = temp; } /** * 下沉调整 * @param array 待调整的堆 * @param parentIndex 要下沉的父节点 * @param length 堆的有效大小 */ public static void downAdjust(int[] array, int parentIndex, int length) { // temp保存父节点值,用于最后的赋值 int temp = array[parentIndex]; int childIndex = 2 * parentIndex + 1; while (childIndex < length) { // 如果有右孩子,且右孩子小于左孩子的值,则定位到右孩子 if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) { childIndex++; } // 如果父节点小于任何一个孩子的值,直接跳出 if (temp <= array[childIndex]) break; //无需真正交换,单向赋值即可 array[parentIndex] = array[childIndex]; parentIndex = childIndex; childIndex = 2 * childIndex + 1; } array[parentIndex] = temp; } /** * 构建堆 * @param array 待调整的堆 */ public static void buildHeap(int[] array) { // 从最后一个非叶子节点开始,依次下沉调整 for (int i = (array.length-2)/2; i >= 0; i--) { downAdjust(array, i, array.length); } } public static void main(String[] args) { int[] array = new int[] {1,3,2,6,5,7,8,9,10,0}; upAdjust(array); System.out.println(Arrays.toString(array)); array = new int[] {7,1,3,10,5,2,8,9,6}; buildHeap(array); System.out.println(Arrays.toString(array)); } } ================================================ FILE: src/chapter3/part4/PriorityQueue.java ================================================ package chapter3.part4; /** * Created by weimengshu on 2018/7/13. */ import java.util.Arrays; public class PriorityQueue { private int[] array; private int size; public PriorityQueue(){ //队列初始长度32 array = new int[32]; } /** * 入队 * @param key 入队元素 */ public void enQueue(int key) { //队列长度超出范围,扩容 if(size >= array.length){ resize(); } array[size++] = key; upAdjust(); } /** * 出队 */ public int deQueue() throws Exception { if(size <= 0){ throw new Exception("the queue is empty !"); } //获取堆顶元素 int head = array[0]; //最后一个元素移动到堆顶 array[0] = array[--size]; downAdjust(); return head; } /** * 上浮调整 */ private void upAdjust() { int childIndex = size-1; int parentIndex = (childIndex-1)/2; // temp保存插入的叶子节点值,用于最后的赋值 int temp = array[childIndex]; while (childIndex > 0 && temp > array[parentIndex]) { //无需真正交换,单向赋值即可 array[childIndex] = array[parentIndex]; childIndex = parentIndex; parentIndex = (parentIndex-1) / 2; } array[childIndex] = temp; } /** * 下沉调整 */ private void downAdjust() { // temp保存父节点值,用于最后的赋值 int parentIndex = 0; int temp = array[parentIndex]; int childIndex = 1; while (childIndex < size) { // 如果有右孩子,且右孩子大于左孩子的值,则定位到右孩子 if (childIndex + 1 < size && array[childIndex + 1] > array[childIndex]) { childIndex++; } // 如果父节点大于任何一个孩子的值,直接跳出 if (temp >= array[childIndex]) break; //无需真正交换,单向赋值即可 array[parentIndex] = array[childIndex]; parentIndex = childIndex; childIndex = 2 * childIndex + 1; } array[parentIndex] = temp; } /** * 队列扩容 */ private void resize() { //队列容量翻倍 int newSize = this.size * 2; this.array = Arrays.copyOf(this.array, newSize); } public static void main(String[] args) throws Exception { PriorityQueue priorityQueue = new PriorityQueue(); priorityQueue.enQueue(3); priorityQueue.enQueue(5); priorityQueue.enQueue(10); priorityQueue.enQueue(2); priorityQueue.enQueue(7); System.out.println("出队元素:" + priorityQueue.deQueue()); System.out.println("出队元素:" + priorityQueue.deQueue()); } } ================================================ FILE: src/chapter4/part2/BubbleSort.java ================================================ package chapter4.part2; import java.util.Arrays; public class BubbleSort { public static void sort(int array[]) { int tmp = 0; //记录最后一次交换的位置 int lastExchangeIndex = 0; //无序数列的边界,每次比较只需要比到这里为止 int sortBorder = array.length - 1; for(int i = 0; i < array.length; i++) { //有序标记,每一轮的初始是true boolean isSorted = true; for(int j = 0; j < sortBorder; j++) { if(array[j] > array[j+1]) { tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; //有元素交换,所以不是有序,标记变为false isSorted = false; //把无序数列的边界更新为最后一次交换元素的位置 lastExchangeIndex = j; } } sortBorder = lastExchangeIndex; if(isSorted){ break; } } } public static void main(String[] args){ int[] array = new int[]{3,4,2,1,5,6,7,8}; sort(array); System.out.println(Arrays.toString(array)); } } ================================================ FILE: src/chapter4/part2/CockTailSort.java ================================================ package chapter4.part2; import java.util.Arrays; public class CockTailSort { public static void sort(int array[]) { int tmp = 0; for(int i=0; i array[j+1]) { tmp = array[j]; array[j] = array[j+1]; array[j+1] = tmp; //有元素交换,所以不是有序,标记变为false isSorted = false; } } if(isSorted){ break; } //偶数轮之前,重新标记为true isSorted = true; //偶数轮,从右向左比较和交换 for(int j=array.length-i-1; j>i; j--) { if(array[j] < array[j-1]) { tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; //有元素交换,所以不是有序,标记变为false isSorted = false; } } if(isSorted){ break; } } } public static void main(String[] args){ int[] array = new int[]{2,3,4,5,6,7,8,1}; sort(array); System.out.println(Arrays.toString(array)); } } ================================================ FILE: src/chapter4/part3/QuickSort.java ================================================ package chapter4.part3; /** * Created by weimengshu on 2018/7/13. */ import java.util.Arrays; public class QuickSort { public static void quickSort(int[] arr, int startIndex, int endIndex) { // 递归结束条件:startIndex大等于endIndex的时候 if (startIndex >= endIndex) { return; } // 得到基准元素位置 int pivotIndex = partition(arr, startIndex, endIndex); // 根据基准元素,分成两部分递归排序 quickSort(arr, startIndex, pivotIndex - 1); quickSort(arr, pivotIndex + 1, endIndex); } /** * 分治(双边循环法) * @param arr 待交换的数组 * @param startIndex 起始下标 * @param endIndex 结束下标 */ private static int partition(int[] arr, int startIndex, int endIndex) { // 取第一个位置的元素作为基准元素(也可以选择随机位置) int pivot = arr[startIndex]; int left = startIndex; int right = endIndex; while( left != right) { //控制right指针比较并左移 while(left pivot){ right--; } //控制left指针比较并右移 while( left> quickSortStack = new Stack>(); // 整个数列的起止下标,以哈希的形式入栈 Map rootParam = new HashMap(); rootParam.put("startIndex", startIndex); rootParam.put("endIndex", endIndex); quickSortStack.push(rootParam); // 循环结束条件:栈为空时结束 while (!quickSortStack.isEmpty()) { // 栈顶元素出栈,得到起止下标 Map param = quickSortStack.pop(); // 得到基准元素位置 int pivotIndex = partition(arr, param.get("startIndex"), param.get("endIndex")); // 根据基准元素分成两部分, 把每一部分的起止下标入栈 if(param.get("startIndex") < pivotIndex -1){ Map leftParam = new HashMap(); leftParam.put("startIndex", param.get("startIndex")); leftParam.put("endIndex", pivotIndex -1); quickSortStack.push(leftParam); } if(pivotIndex + 1 < param.get("endIndex")){ Map rightParam = new HashMap(); rightParam.put("startIndex", pivotIndex + 1); rightParam.put("endIndex", param.get("endIndex")); quickSortStack.push(rightParam); } } } /** * 分治(单边循环法) * @param arr 待交换的数组 * @param startIndex 起始下标 * @param endIndex 结束下标 */ private static int partition(int[] arr, int startIndex, int endIndex) { // 取第一个位置的元素作为基准元素(也可以选择随机位置) int pivot = arr[startIndex]; int mark = startIndex; for(int i=startIndex+1; i<=endIndex; i++){ if(arr[i] array[childIndex]) { childIndex++; } // 如果父节点大于等于任何一个孩子的值,直接跳出 if (temp >= array[childIndex]) break; //无需真正交换,单向赋值即可 array[parentIndex] = array[childIndex]; parentIndex = childIndex; childIndex = 2 * childIndex + 1; } array[parentIndex] = temp; } /** * 堆排序(升序) * @param array 待调整的堆 */ public static void heapSort(int[] array) { // 1.把无序数组构建成最大堆。 for (int i = (array.length-2)/2; i >= 0; i--) { downAdjust(array, i, array.length); } System.out.println(Arrays.toString(array)); // 2.循环交换集合尾部元素到堆顶,并调节堆产生新的堆顶。 for (int i = array.length - 1; i > 0; i--) { // 最后一个元素和第一元素进行交换 int temp = array[i]; array[i] = array[0]; array[0] = temp; // 下沉调整最大堆 downAdjust(array, 0, i); } } public static void main(String[] args) { int[] arr = new int[] {1,3,2,6,5,7,8,9,10,0}; heapSort(arr); System.out.println(Arrays.toString(arr)); } } ================================================ FILE: src/chapter4/part5/BucketSort.java ================================================ package chapter4.part5; /** * Created by weimengshu on 2018/7/13. */ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; public class BucketSort { public static double[] bucketSort(double[] array){ //1.得到数列的最大值和最小值,并算出差值d double max = array[0]; double min = array[0]; for(int i=1; i max) { max = array[i]; } if(array[i] < min) { min = array[i]; } } double d = max - min; //2.初始化桶 int bucketNum = array.length; ArrayList> bucketList = new ArrayList>(bucketNum); for(int i = 0; i < bucketNum; i++){ bucketList.add(new LinkedList()); } //3.遍历原始数组,将每个元素放入桶中 for(int i = 0; i < array.length; i++){ int num = (int)((array[i] - min) * (bucketNum-1) / d); bucketList.get(num).add(array[i]); } //4.对每个桶内部进行排序 for(int i = 0; i < bucketList.size(); i++){ //JDK底层采用了归并排序或归并的优化版本 Collections.sort(bucketList.get(i)); } //5.输出全部元素 double[] sortedArray = new double[array.length]; int index = 0; for(LinkedList list : bucketList){ for(double element : list){ sortedArray[index] = element; index++; } } return sortedArray; } public static void main(String[] args) { double[] array = new double[] {4.12,6.421,0.0023,3.0,2.123,8.122,4.12, 10.09}; double[] sortedArray = bucketSort(array); System.out.println(Arrays.toString(sortedArray)); } } ================================================ FILE: src/chapter4/part5/CountSort.java ================================================ package chapter4.part5; /** * Created by weimengshu on 2018/7/13. */ import java.util.Arrays; public class CountSort { public static int[] countSort(int[] array) { //1.得到数列的最大值 int max = array[0]; for(int i=1; i max){ max = array[i]; } } //2.根据数列最大值确定统计数组的长度 int[] countArray = new int[max+1]; //3.遍历数列,填充统计数组 for(int i=0; i max) { max = array[i]; } if(array[i] < min) { min = array[i]; } } int d = max - min; //2.创建统计数组并统计对应元素个数 int[] countArray = new int[d+1]; for(int i=0; i=0;i--) { sortedArray[countArray[array[i]-min]-1]=array[i]; countArray[array[i]-min]--; } return sortedArray; } public static void main(String[] args) { int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10}; int[] sortedArray = countSort(array); System.out.println(Arrays.toString(sortedArray)); array = new int[] {95,94,91,98,99,90,99,93,91,92}; sortedArray = countSort(array); System.out.println(Arrays.toString(sortedArray)); } } ================================================ FILE: src/chapter5/part10/BigNumberSum.java ================================================ package chapter5.part10; /** * Created by weimengshu on 2018/10/20. */ public class BigNumberSum { /** * 大整数求和 * @param bigNumberA 大整数A * @param bigNumberB 大整数B */ public static String bigNumberSum(String bigNumberA, String bigNumberB) { //1.把两个大整数用数组逆序存储,数组长度等于较大整数位数+1 int maxLength = bigNumberA.length() > bigNumberB.length() ? bigNumberA.length() : bigNumberB.length(); int[] arrayA = new int[maxLength+1]; for(int i=0; i< bigNumberA.length(); i++){ arrayA[i] = bigNumberA.charAt(bigNumberA.length()-1-i) - '0'; } int[] arrayB = new int[maxLength+1]; for(int i=0; i< bigNumberB.length(); i++){ arrayB[i] = bigNumberB.charAt(bigNumberB.length()-1-i) - '0'; } //2.构建result数组,数组长度等于较大整数位数+1 int[] result = new int[maxLength+1]; //3.遍历数组,按位相加 for(int i=0; i= 10){ temp = temp-10; result[i+1] = 1; } result[i] = temp; } //4.把result数组再次逆序并转成String StringBuilder sb = new StringBuilder(); //是否找到大整数的最高有效位 boolean findFirst = false; for (int i = result.length - 1; i >= 0; i--) { if(!findFirst){ if(result[i] == 0){ continue; } findFirst = true; } sb.append(result[i]); } return sb.toString(); } public static void main(String[] args) { System.out.println(bigNumberSum("426709752318", "95481253129")); } } ================================================ FILE: src/chapter5/part11/GoldMining.java ================================================ package chapter5.part11; /** * Created by weimengshu on 2018/10/26. */ public class GoldMining { /** * 获得金矿最优收益 * @param w 工人数量 * @param p 金矿开采所需工人数量 * @param g 金矿储量 */ public static int getBestGoldMiningV3(int w, int[] p, int[] g){ //创建当前结果 int[] results = new int[w+1]; //填充一维数组 for(int i=1; i<=g.length; i++){ for(int j=w; j>=1; j--){ if(j>=p[i-1]){ results[j] = Math.max(results[j], results[j-p[i-1]]+ g[i-1]); } } } //返回最后一个格子的值 return results[w]; } /** * 获得金矿最优收益 * @param w 工人数量 * @param p 金矿开采所需工人数量 * @param g 金矿储量 */ public static int getBestGoldMiningV2(int w, int[] p, int[] g){ //创建表格 int[][] resultTable = new int[g.length+1][w+1]; //填充表格 for(int i=1; i<=g.length; i++){ for(int j=1; j<=w; j++){ if(j mainStack = new Stack(); private Stack minStack = new Stack(); /** * 入栈操作 * @param element 入栈的元素 */ public void push(int element) { mainStack.push(element); //如果辅助栈为空,或新元素小于等于辅助栈栈顶,则新元素压入辅助栈 if (minStack.empty() || element <= minStack.peek()) { minStack.push(element); } } /** * 出栈操作 */ public Integer pop() { //如果出栈元素和辅助栈栈顶元素值相等,辅助栈出栈 if (mainStack.peek().equals(minStack.peek())) { minStack.pop(); } return mainStack.pop(); } /** * 获取栈的最小元素 */ public int getMin() throws Exception { if (mainStack.empty()) { throw new Exception("stack is empty"); } return minStack.peek(); } public static void main(String[] args) throws Exception { MinStack stack = new MinStack(); stack.push(4); stack.push(9); stack.push(7); stack.push(3); stack.push(8); stack.push(5); System.out.println(stack.getMin()); stack.pop(); stack.pop(); stack.pop(); System.out.println(stack.getMin()); } } ================================================ FILE: src/chapter5/part4/GreatestCommonDivisor.java ================================================ package chapter5.part4; /** * Created by weimengshu on 2018/10/6. */ public class GreatestCommonDivisor { public static int getGreatestCommonDivisor(int a, int b){ int big = a>b ? a:b; int small = a1; i--){ if(small%i==0 && big%i==0){ return i; } } return 1; } public static int getGreatestCommonDivisorV2(int a, int b){ int big = a>b ? a:b; int small = ab ? a:b; int small = a> 1, b >> 1)<<1; } else if((a&1)==0 && (b&1)!=0){ return gcd(a >> 1, b); } else if((a&1)!=0 && (b&1)==0){ return gcd(a, b >> 1); } else { int big = a>b ? a:b; int small = a max) { max = array[i]; } if(array[i] < min) { min = array[i]; } } int d = max - min; //如果max和min相等,说明数组所有元素都相等,返回0 if(d == 0){ return 0; } //2.初始化桶 int bucketNum = array.length; Bucket[] buckets = new Bucket[bucketNum]; for(int i = 0; i < bucketNum; i++){ buckets[i] = new Bucket(); } //3.遍历原始数组,确定每个桶的最大最小值 for(int i = 0; i < array.length; i++){ //确定数组元素所归属的桶下标 int index = ((array[i] - min) * (bucketNum-1) / d); if(buckets[index].min==null || buckets[index].min>array[i]){ buckets[index].min = array[i]; } if(buckets[index].max==null || buckets[index].max maxDistance) { maxDistance = buckets[i].min - leftMax; } leftMax = buckets[i].max; } return maxDistance; } /** * 桶 */ private static class Bucket { Integer min; Integer max; } public static void main(String[] args) { int[] array = new int[] {2,6,3,4,5,10,9}; System.out.println(getMaxSortedDistance(array)); } } ================================================ FILE: src/chapter5/part7/StackQueue.java ================================================ package chapter5.part7; import java.util.Stack; /** * Created by weimengshu on 2018/8/24. */ public class StackQueue { private Stack stackA = new Stack(); private Stack stackB = new Stack(); /** * 入队操作 * @param element 入队的元素 */ public void enQueue(int element) { stackA.push(element); } /** * 出队操作 */ public Integer deQueue() { if(stackB.isEmpty()){ if(stackA.isEmpty()){ return null; } transfer(); } return stackB.pop(); } /** * 栈A元素转移到栈B */ private void transfer(){ while (!stackA.isEmpty()){ stackB.push(stackA.pop()); } } public static void main(String[] args) throws Exception { StackQueue stackQueue = new StackQueue(); stackQueue.enQueue(1); stackQueue.enQueue(2); stackQueue.enQueue(3); System.out.println(stackQueue.deQueue()); System.out.println(stackQueue.deQueue()); stackQueue.enQueue(4); System.out.println(stackQueue.deQueue()); System.out.println(stackQueue.deQueue()); } } ================================================ FILE: src/chapter5/part8/FindNearestNumber.java ================================================ package chapter5.part8; import java.util.Arrays; /** * Created by weimengshu on 2017/8/10. */ public class FindNearestNumber { public static int[] findNearestNumber(int[] numbers){ //1.从后向前查看逆序区域,找到逆序区域的前一位,也就是数字置换的边界 int index = findTransferPoint(numbers); //如果数字置换边界是0,说明整个数组已经逆序,无法得到更大的相同数字组成的整数,返回null if(index == 0){ return null; } //2.把逆序区域的前一位和逆序区域中刚刚大于它的数字交换位置 //拷贝入参,避免直接修改入参 int[] numbersCopy = Arrays.copyOf(numbers, numbers.length); exchangeHead(numbersCopy, index); //3.把原来的逆序区域转为顺序 reverse(numbersCopy, index); return numbersCopy; } private static int findTransferPoint(int[] numbers){ for(int i=numbers.length-1; i>0; i--){ if(numbers[i] > numbers[i-1]){ return i; } } return 0; } private static int[] exchangeHead(int[] numbers, int index){ int head = numbers[index-1]; for(int i=numbers.length-1; i>0; i--){ if(head < numbers[i]){ numbers[index-1] = numbers[i]; numbers[i] = head; break; } } return numbers; } private static int[] reverse(int[] num, int index){ for(int i=index,j=num.length-1; i num.charAt(j+1)){ num = num.substring(0, j) + num.substring(j+1,num.length()); hasCut = true; break; } } //如果没有找到要删除的数字,则删除最后一个数字 if(!hasCut){ num = num.substring(0, num.length()-1); } } //清除整数左侧的数字0 int start = 0; for(int j=0; j 0 && stack[top-1] > c && k > 0) { top -= 1; k -= 1; } //如果遇到数字0,且栈为空,0不入栈 if('0' == c && top == 0){ newLength--; if(newLength <= 0){ return "0"; } continue; } //遍历到的当前数字入栈 stack[top++] = c; } // 用栈构建新的整数字符串 return newLength<=0 ? "0" : new String(stack, 0, newLength); } public static void main(String[] args) { System.out.println(removeKDigits("1593212", 3)); System.out.println(removeKDigits("30200", 1)); System.out.println(removeKDigits("10", 2)); System.out.println(removeKDigits("541270936", 3)); System.out.println(removeKDigits("1593212", 4)); System.out.println(removeKDigits("1000020000000010", 2)); } } ================================================ FILE: src/chapter6/part2/MyBitmap.java ================================================ package chapter6.part2; /** * Created by weimengshu on 2017/8/10. */ public class MyBitmap { //每一个word是一个long类型元素,对应64位二进制 private long[] words; //bitmap的位数大小 private int size; public MyBitmap(int size) { this.size = size; this.words = new long[(getWordIndex(size-1) + 1)]; } /** * 判断bitmap某一位的状态 * @param bitIndex 位图的第bitIndex位 */ public boolean getBit(int bitIndex) { if(bitIndex<0 || bitIndex>size-1){ throw new IndexOutOfBoundsException("超过bitmap有效范围"); } int wordIndex = getWordIndex(bitIndex); return (words[wordIndex] & (1L << bitIndex)) != 0; } /** * 把bitmap某一位设为真 * @param bitIndex 位图的第bitIndex位 */ public void setBit(int bitIndex) { if(bitIndex<0 || bitIndex>size-1){ throw new IndexOutOfBoundsException("超过bitmap有效范围"); } int wordIndex = getWordIndex(bitIndex); words[wordIndex] |= (1L << bitIndex); } /** * 定位bitmap某一位所对应的word * @param bitIndex 位图的第bitIndex位 */ private int getWordIndex(int bitIndex) { //右移6位,相当于除以64 return bitIndex >> 6; } public static void main(String[] args) { MyBitmap bitMap = new MyBitmap(128); bitMap.setBit(126); bitMap.setBit(75); System.out.println(bitMap.getBit(126)); System.out.println(bitMap.getBit(78)); } } ================================================ FILE: src/chapter6/part3/LRUCache.java ================================================ package chapter6.part3; import java.util.HashMap; public class LRUCache { private Node head; private Node end; //缓存存储上限 private int limit; private HashMap hashMap; public LRUCache(int limit) { this.limit = limit; hashMap = new HashMap(); } public String get(String key) { Node node = hashMap.get(key); if (node == null){ return null; } refreshNode(node); return node.value; } public void put(String key, String value) { Node node = hashMap.get(key); if (node == null) { //如果key不存在,插入key-value if (hashMap.size() >= limit) { String oldKey = removeNode(head); hashMap.remove(oldKey); } node = new Node(key, value); addNode(node); hashMap.put(key, node); }else { //如果key存在,刷新key-value node.value = value; refreshNode(node); } } public void remove(String key) { Node node = hashMap.get(key); if(node == null){ return; } removeNode(node); hashMap.remove(key); } /** * 刷新被访问的节点位置 * @param node 被访问的节点 */ private void refreshNode(Node node) { //如果访问的是尾节点,无需移动节点 if (node == end) { return; } //移除节点 removeNode(node); //重新插入节点 addNode(node); } /** * 删除节点 * @param node 要删除的节点 */ private String removeNode(Node node) { if(node == head && node == end){ //移除唯一的节点 head = null; end = null; }else if(node == end){ //移除尾节点 end = end.pre; end.next = null; }else if(node == head){ //移除头节点 head = head.next; head.pre = null; }else { //移除中间节点 node.pre.next = node.next; node.next.pre = node.pre; } return node.key; } /** * 尾部插入节点 * @param node 要插入的节点 */ private void addNode(Node node) { if(end != null) { end.next = node; node.pre = end; node.next = null; } end = node; if(head == null){ head = node; } } class Node { Node(String key, String value){ this.key = key; this.value = value; } public Node pre; public Node next; public String key; public String value; } public static void main(String[] args) { LRUCache lruCache = new LRUCache(5); lruCache.put("001", "用户1信息"); lruCache.put("002", "用户2信息"); lruCache.put("003", "用户3信息"); lruCache.put("004", "用户4信息"); lruCache.put("005", "用户5信息"); lruCache.get("002"); lruCache.put("004", "用户4信息更新"); lruCache.put("006", "用户6信息"); System.out.println(lruCache.get("001")); System.out.println(lruCache.get("006")); } } ================================================ FILE: src/chapter6/part4/AStar.java ================================================ package chapter6.part4; import java.util.ArrayList; import java.util.List; public class AStar { //迷宫地图 public static final int[][] MAZE = { { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 } }; /** * A星寻路主逻辑 * @param start 迷宫起点 * @param end 迷宫终点 */ public static Grid aStarSearch(Grid start, Grid end) { ArrayList openList = new ArrayList(); ArrayList closeList = new ArrayList(); //把起点加入 openList openList.add(start); //主循环,每一轮检查一个当前方格节点 while (openList.size() > 0) { // 在openList中查找 F值最小的节点作为当前方格节点 Grid currentGrid = findMinGird(openList); // 当前方格节点从openList中移除 openList.remove(currentGrid); // 当前方格节点进入 closeList closeList.add(currentGrid); // 找到所有邻近节点 List neighbors = findNeighbors(currentGrid, openList, closeList); for (Grid grid : neighbors) { //邻近节点不在openList中,标记父亲、G、H、F,并放入openList grid.initGrid(currentGrid, end); openList.add(grid); } //如果终点在openList中,直接返回终点格子 for (Grid grid : openList){ if ((grid.x == end.x) && (grid.y == end.y)) { return grid; } } } //openList用尽,仍然找不到终点,说明终点不可到达,返回空 return null; } private static Grid findMinGird(ArrayList openList) { Grid tempGrid = openList.get(0); for (Grid grid : openList) { if (grid.f < tempGrid.f) { tempGrid = grid; } } return tempGrid; } private static ArrayList findNeighbors(Grid grid, List openList, List closeList) { ArrayList gridList = new ArrayList(); if (isValidGrid(grid.x, grid.y-1, openList, closeList)) { gridList.add(new Grid(grid.x, grid.y - 1)); } if (isValidGrid(grid.x, grid.y+1, openList, closeList)) { gridList.add(new Grid(grid.x, grid.y + 1)); } if (isValidGrid(grid.x-1, grid.y, openList, closeList)) { gridList.add(new Grid(grid.x - 1, grid.y)); } if (isValidGrid(grid.x+1, grid.y, openList, closeList)) { gridList.add(new Grid(grid.x + 1, grid.y)); } return gridList; } private static boolean isValidGrid(int x, int y, List openList, List closeList) { //是否超过边界 if (x < 0 || x >= MAZE.length || y < 0 || y >= MAZE[0].length) { return false; } //是否有障碍物 if(MAZE[x][y] == 1){ return false; } //是否已经在openList中 if(containGrid(openList, x, y)){ return false; } //是否已经在closeList中 if(containGrid(closeList, x, y)){ return false; } return true; } private static boolean containGrid(List grids, int x, int y) { for (Grid grid : grids) { if ((grid.x == x) && (grid.y == y)) { return true; } } return false; } static class Grid { public int x; public int y; public int f; public int g; public int h; public Grid parent; public Grid(int x, int y) { this.x = x; this.y = y; } public void initGrid(Grid parent, Grid end){ this.parent = parent; this.g = parent.g + 1; this.h = Math.abs(this.x - end.x) + Math.abs(this.y - end.y); this.f = this.g + this.h; } } public static void main(String[] args) { //设置起点和终点 Grid startGrid = new Grid(2, 1); Grid endGrid = new Grid(2, 5); //搜索迷宫终点 Grid resultGrid = aStarSearch(startGrid, endGrid); //回溯迷宫路径 ArrayList path = new ArrayList(); while (resultGrid != null) { path.add(new Grid(resultGrid.x, resultGrid.y)); resultGrid = resultGrid.parent; } //输出迷宫和路径,路径用星号表示 for (int i = 0; i < MAZE.length; i++) { for (int j = 0; j < MAZE[0].length; j++) { if (containGrid(path, i, j)) { System.out.print("*, "); } else { System.out.print(MAZE[i][j] + ", "); } } System.out.println(); } } } ================================================ FILE: src/chapter6/part5/Redpackage.java ================================================ package chapter6.part5; import java.math.BigDecimal; import java.util.*; /** * Created by weimengshu on 2018/4/8. */ public class Redpackage { /** * 拆分红包 * @param totalAmount 总金额(以分为单位) * @param totalPeopleNum 总人数 */ public static List divideRedPackage(Integer totalAmount, Integer totalPeopleNum){ List amountList = new ArrayList(); Integer restAmount = totalAmount; Integer restPeopleNum = totalPeopleNum; Random random = new Random(); for(int i=0; i divideRedPackageV2(Integer totalAmount, Integer totalPeopleNum){ List amountList = new ArrayList(); Set segments = new HashSet(); Random random = new Random(); for(int i = 0; i< totalPeopleNum-1; i++){ int segment = random.nextInt(totalAmount-2) + 1; int delta = random.nextInt(1)==0 ? 1 : -1; while(segments.contains(segment) || segment == 0){ segment = (segment+delta)%totalAmount; } segments.add(segment); } List segmentList = new ArrayList(segments); Collections.sort(segmentList); for(int i=0; i amountList = divideRedPackage(1000, 10); for(Integer amount : amountList){ System.out.println("抢到金额:" + new BigDecimal(amount).divide(new BigDecimal(100))); } } }