B站链接
细节都写在注释里了
最近想要用伪代码实现之前写过的代码
排序 交换数组中的两个数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static void swap1 (int []arr,int i,int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void swap2 (int [] arr,int i,int j) { if (arr[i] == arr[j]){ return ; } arr[i] = arr[i] ^ arr[j]; arr[j] = arr[j] ^ arr[i]; arr[i] = arr[i] ^ arr[j]; }
生成随机数组 1 2 3 4 5 6 7 8 9 public static int [] generateRandomArray(int maxSize,int maxValue){ int [] arr = new int [(int )((maxSize + 1 ) * Math.random())]; for (int i = 0 ;i < arr.length;i++) { arr[i] = (int )((maxValue+1 )*Math.random()) - (int )((maxValue+1 )*Math.random()); } return arr; }
冒泡排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static void bubbleSort (int [] arr) { if (arr == null || arr.length <2 ){ return ; } for (int i = 1 ; i < arr.length; i++){ for (int j = 0 ; j < arr.length - i; j++){ if (arr[j + 1 ] < arr[j]) { swap(arr,j + 1 ,j); } } } }
选择排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static void selectSort (int [] arr) { if (arr == null || arr.length <2 ){ return ; } for (int i = 0 ; i < arr.length - 1 ; i++){ int minIndex = i; for (int j = i + 1 ; j < arr.length; j++){ if (arr[minIndex] > arr[j]){ minIndex = j; } } swap(arr,minIndex,i); } }
插入排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static void insertSort (int [] arr) { if (arr == null || arr.length <2 ){ return ; } for (int i = 1 ;i < arr.length;i++){ for (int j = i; j > 0 && arr[j] < arr[j-1 ];j--){ swap(arr,j,j - 1 ); } } }
归并排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public static void merge (int [] arr,int L,int M,int R) { int [] help = new int [R - L + 1 ]; int p1 = L; int p2 = M + 1 ; int i = 0 ; while (p1 <= M && p2 <= R){ help[i++] = arr[p1] <= arr[p2]? arr[p1++]:arr[p2++]; } while (p1 <= M){ help[i++] = arr[p1++]; } while (p2 <= R){ help[i++] = arr[p2++]; } for (i = 0 ;i < help.length;i++){ arr[L + i] = help[i]; } }
递归实现
1 2 3 4 5 6 7 8 9 10 public void mergesort (int [] arr,int L,int R) { if (L == R){ return ; } int mid = L + ((R - L) >> 1 ); mergesort(arr,L,mid); mergesort(arr,mid +1 ,R); merge(arr,L,mid,R); }
非递归
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public static void mergesort02 (int [] arr) { if (arr == null || arr.length < 2 ){ return ; } int mergeSize = 1 ; int N = arr.length; while (mergeSize < N){ int L = 0 ; while (L < N){ int M = L + mergeSize; if (M >= N){ break ; } int R = Math.min(M + mergeSize,N - 1 ); merge(arr,L,M,R); L = R + 1 ; } if (mergeSize > (N >> 1 )){ break ; } mergeSize <<= 1 ; } }
快速排序 Partition 给一个数,把数组中小于等于这个数的数放左边,其他放右边
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static int partition (int [] arr,int L,int R) { if (L > R){ return -1 ; } if (L == R){ return L; } int less = L - 1 ; int more = R; int index = L; while (L < R){ if (arr[index] == arr[R]){ index++; }else if (arr[index] < arr[R]){ swap(arr,index++,++less); }else { swap(arr,index,--more); } } swap(arr,more,R); return more; } public static void swap (int [] arr,int i,int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
荷兰国旗问题 给一个数,把数组中小于这个数的数放左边,等于放中间,大于放右边
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static int partition (int [] arr,int L,int R) { if (L > R){ return -1 ; } if (L == R){ return L; } int less = L - 1 ; int more = R; int index = L; while (L < R){ if (arr[index] == arr[R]){ index++; }else if (arr[index] < arr[R]){ swap(arr,index++,++less); }else { swap(arr,index,--more); } } swap(arr,more,R); return more; } public static void swap (int [] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
快排1.0 用partition
1 2 3 4 5 6 7 8 public static void quicksort01 (int [] arr,int L,int R) { if (L >= R){ return ; } int M = partition(arr,L,R); quicksort01(arr,L,M); quicksort01(arr,M + 1 ,R); }
快排2.0 用荷兰国旗
1 2 3 4 5 6 7 8 public static void quicksort02 (int [] arr, int L, int R) { if (L >= R) { return ; } int [] equalArea = netherlandsFlag(arr, L, R); quicksort02(arr, L, equalArea[0 ] - 1 ); quicksort02(arr, equalArea[1 ] + 1 , R); }
快排3.0(随机快排) 在2.0的基础上加随机,达到s时间复杂度O(N*logN)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void quicksort03 (int [] arr,int L,int R) { if (L <= R){ return ; } swap(arr,L + (int ) (Math.random() * (R - L + 1 )),R); int [] equalArea = NetherlandsFlag.netherlandsFlag(arr,L,R); quicksort03(arr,L,equalArea[0 ] - 1 ); quicksort03(arr,equalArea[1 ] + 1 ,R); } public static void swap (int []arr,int i,int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
结论:每种情况出现是等概率时,所有情况的时间复杂度的期望是O(N*logN)
堆排序 见二叉树部分的堆的内容
跳转
几乎有序的数组
桶排序 不基于比较的排序
应用范围很有限,如果数据有变动,算法很可能要大规模重写
计数排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public static void countSort (int [] arr) { if (arr == null || arr.length < 2 ){ return ; } int max = Integer.MIN_VALUE; for (int i = 0 ; i < arr.length; i++){ max = Math.max(max,arr[i]); } int [] bucket = new int [max + 1 ]; for (int i = 0 ; i < arr.length; i++){ bucket[arr[i]]++; } int i = 0 ; for (int j = 0 ; j < bucket.length; j++){ while (bucket[j]-- > 0 ){ arr[i++] = j; } } }
基数排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 public class RadixSort { public static void radixSort (int [] arr) { if (arr == null || arr.length < 2 ){ return ; } radixSort(arr,0 ,arr.length - 1 ,maxBits(arr)); } public static int maxBits (int []arr) { int max = Integer.MIN_VALUE; for (int i = 0 ;i < arr.length; i++){ max = Math.max(max,arr[i]); } int res = 0 ; while (max != 0 ){ res++; max /= 10 ; } return res; } public static void radixSort (int [] arr, int L, int R, int digit) { final int radix = 10 ; int i = 0 , j = 0 ; int [] help = new int [R - L +1 ]; for (int d = 1 ; d <= digit; d++) { int [] count = new int [radix]; for (i = L;i <= R; i++){ j = getDigit(arr[i], d); count[j]++; } for (i = 1 ; i < radix; i++){ count[i] += count[i - 1 ]; } for (i = R; i >= L; i--){ j = getDigit(arr[i], d); help[count[j] - 1 ] = arr[i]; count[j]--; } for (i = L,j =0 ; i <= R; i++,j++){ arr[i] = help[j]; } } } public static int getDigit (int num, int digit) { int bits = 0 ; int cloneOfNum = num; while (cloneOfNum != 0 ){ bits++; cloneOfNum /= 10 ; } if (digit > bits || digit <= 0 ){ return 0 ; } return (num / (int )Math.pow(10 ,digit - 1 )) % 10 ; } }
总结
基于比较
时间复杂度
空间复杂度
稳定性
选择排序
O(N^2)
O(1)
无
冒泡排序
O(N^2)
O(1)
有
插入排序
O(N^2)
O(1)
有
归并排序
O(N*logN)
O(N)
有
随即快排
O(N*logN)
O(logN)
无
堆排序
O(N*logN)
O(1)
无
不基于比较
计数排序
O(N)
O(M)
有
基数排序
O(N)
O(N)
有
二分法 有序数组中查找某个数是否存在 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static boolean dichotomySearch (int [] arr,int target) { if (arr == null || arr.length ==0 ){ return false ; } int L = 0 ; int R = arr.length-1 ; int mid = 0 ; while (L < R){ mid = L + ((R - L) >> 1 ); if (arr[mid] == target){ return true ; } else if (arr[mid] > target){ R = mid - 1 ; } else { L = mid + 1 ; } } return arr[L] == target; }
有序数组中,找>=某个数最左侧的位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static int firstLeft (int []arr,int target) { int L = 0 ; int R = arr.length -1 ; int mid = 0 ; int res = -1 ; while (L <= R){ mid = L + ((R - L) >> 1 ); if (arr[mid] >= target){ res = mid; R = mid -1 ; } else { L = mid + 1 ; } } return res; }
局部最小值 无序数组中,任何相邻的两个数都不相等,找局部最小值,局部最小值定义为既小于左边数,也小于右边数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static int localMin (int [] arr) { if (arr == null || arr.length == 0 ){ return -1 ; } int L = 0 ; int R = arr.length - 1 ; if (arr.length == 1 || arr[0 ] < arr[1 ]){ return 0 ; } if (arr[R] < arr[R - 1 ]){ return R - 1 ; } while (L < R){ int mid = L + ((R - L) >> 1 ); if (arr[mid] > arr[mid + 1 ]){ L = mid + 1 ; }else if (arr[mid] > arr[mid -1 ]){ R = mid - 1 ; }else { return mid; } } return -1 ; }
位运算
0 ^ N == N N ^ N == 0
异或运算满足交换律和结合律
用无进位相加来理解异或运算
交换数组中的两个数 1 2 3 4 5 6 7 8 public static void swap2 (int [] arr,int i,int j) { if (arr[i] == arr[j]){ return ; } arr[i] = arr[i] ^ arr[j]; arr[j] = arr[j] ^ arr[i]; arr[i] = arr[i] ^ arr[j]; }
数组中只有一种数出现了奇数次,打印这种数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void onlyOne (int [] arr) { if (arr == null ){ return ; } if (arr.length < 2 ){ System.out.println(arr[0 ]); return ; } int ans = arr[0 ]; for (int i = 1 ;i < arr.length;i++){ ans ^= arr[i]; } System.out.println(ans); }
提取最右侧的1 举例:把二进制数0111100变成0000100
取反加1再相与
N&((~N)+1)
1 2 3 public static int farRightOne (int num) { return num & ((~num)+1 ); }
数组中有两种数出现了奇数次,打印这两种数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void twoOddTimes (int [] arr) { int eor = arr[0 ]; for (int i = 1 ;i < arr.length;i++){ eor ^= arr[i]; } int farRightOne = eor & ((~eor)+1 ); int eor1 = 0 ; for (int i = 0 ;i < arr.length;i++){ if ((arr[i] & farRightOne) != 0 ){ eor1 ^= arr[i]; } } System.out.println(eor1 + " " + (eor1 ^ eor)); }
数出一个数的二进制形式中有几个1 1 2 3 4 5 6 7 8 9 public static int howManyOnes (int num) { int count = 0 ; while (num != 0 ){ int farRightOne = num & ((~num)+1 ); num ^= farRightOne; count ++; } return count; }
用位运算优化N皇后 见暴力递归N皇后plus
不用比较运算符获得最大值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public static int getMax (int a, int b) { int sa = ~(a >> 31 ); int sb = ~(b >> 31 ); int ifSame = ~(sa ^ sb); int greater = ~((a - b) >> 31 ); int sameReturn = greater * a + (~ greater) * b; int diffReturn = sa * a + sb * b; return ifSame * sameReturn + (~ ifSame) * diffReturn; }
2的幂、4的幂 1 2 3 4 5 6 7 8 public static boolean powerOf2 (int num) { return (num & (num - 1 )) == 0 ; } public static boolean powerOf4 (int num) { return (num & (num - 1 )) == 0 && (num & 0x55555555 ) != 0 ; }
加减乘除 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public static int plus (int a, int b) { int sum = a; while (b != 0 ){ sum = a ^ b; b = (a & b) << 1 ; a = sum; } return sum; } public static int minus (int a, int b) { b = plus((~b),1 ); return plus(a, b); } public static int multi (int a, int b) { int res = 0 ; while (b != 0 ){ if ((b & 1 ) != 0 ){ res = plus(res, a); } a <<= 1 ; b >>>= 1 ; } return res; }
链表 单向链表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Node { public int value; public Node next; public Node (int data) { value = data; } public static Node reverseLinkedList (Node head) { Node next = null ; Node last = null ; while (head != null ){ next = head.next; head.next = last; last = head; head = next; } return last; } public static Node removeValue (Node head,int num) { while (head != null ){ if (head.value != num){ break ; } head = head.next; } Node last = head; Node cur = head; while (cur != null ){ if (cur.value == num){ last.next = cur.next; }else { last = cur; } cur = cur.next; } return head; } }
双向链表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class DoubleNode <T>{ public T value; public DoubleNode<T> next; public DoubleNode<T> last; public DoubleNode (T data) { value = data; } public DoubleNode<T> reverseDoubleList (DoubleNode<T> head) { DoubleNode<T> last = null ; DoubleNode<T> next = null ; while (head != null ){ head.next = next; head.next = last; head.last = next; last = head; head = next; } return last; } public DoubleNode<T> removeValue (DoubleNode<T> head, T num) { while (head != null ){ if (head.value != num){ break ; } head = head.next; } DoubleNode<T> last = head; DoubleNode<T> cur = head; DoubleNode<T> next = head.next; while (cur != null ){ if (cur.value == num){ last.next = next; next.last = last; } else { last = cur; } next = cur.next; cur = cur.next; } return head; } }
双向链表实现队列和栈 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public class MyNode <T>{ public DoubleNode<T> H; public DoubleNode<T> T; public void pushFromHead (T data) { DoubleNode<T> newNode = new DoubleNode <>(data); if (H == null ){ T = newNode; }else { H.last = newNode; newNode.next = H; } H = newNode; } public void pushFromTail (T data) { DoubleNode<T> newNode = new DoubleNode <>(data); if (T == null ){ H = newNode; }else { T.next = newNode; newNode.last = T; } T = newNode; } public T popFromHead () { if (H == null ){ return null ; } DoubleNode<T> popNode = H; if (H == T){ H = null ; T = null ; }else { H = H.next; H.last = null ; popNode.next = null ; } return popNode.value; } public T popFromTail () { if (T == null ){ return null ; } DoubleNode<T> popNode = T; if (H == T){ H = null ; T = null ; }else { T = T.last; T.next = null ; popNode.last = null ; } return popNode.value; } }
实现队列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ListQueue <T>{ MyNode<T> node; public ListQueue () { node = new MyNode <T>(); } public void push (T value) { node.pushFromTail(value); } public void pop () { node.popFromHead(); } }
实现栈 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class ListStack <T> { MyNode<T> node; public ListStack () { node = new MyNode <T>(); } public void push (T value) { node.pushFromTail(value); } public void pop () { node.popFromTail(); } }
返回中点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 import java.util.ArrayList;public class GetMid { public static Node getMid01 (Node head) { if (head == null ){ return null ; } ArrayList<Node> help = new ArrayList <>(); while (head.next != null ){ help.add(head); head = head.next; } return help.get((help.size() - 1 ) / 2 ); } public static Node getMid02 (Node head) { if (head == null ){ return null ; } Node f = head; Node s = head; while (f.next != null && f.next.next != null ){ f = f.next.next; s = s.next; } return s; } public static Node getMid03 (Node head) { if (head == null || head.next == null ){ return head; } Node f = head; Node s = head.next; while (f.next != null && f.next.next != null ){ f = f.next.next; s = s.next; } return s; } }
是否为回文结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class IsPalindrome { public static boolean isPalindrome (Node head) { if (head == null || head.next == null ){ return true ; } Node help = GetMid.getMid02(head); Node l = help.next; Node r = null ; while (l != null ){ r = l.next; l.next = help; help = l; l = r; } r = help; l = head; boolean res = true ; while (r != null && l != null ){ if (r.value != l.value){ res = false ; break ; } r = r.next; l = l.next; } r = help.next; help.next = null ; while (r != null ){ l = r.next; r.next = help; help = r; r = l; } return res; } }
Partition 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public static Node listPartition (Node head, int value) { Node lh = null ; Node lt = null ; Node eh = null ; Node et = null ; Node mh = null ; Node mt = null ; Node next = null ; while (head != null ){ next = head.next; head.next = null ; if (head.value < value){ if (lh == null ){ lh = head; }else { lt.next = head; } lt = head; }else if (head.value == value){ if (eh == null ){ eh = head; }else { et.next = head; } et = head; }else { if (mh == null ){ mh = head; }else { mt.next = head; } mt = head; } head = next; } if (lt != null ){ lt.next = eh; et = et == null ? lt : et; } if (et != null ){ et.next = mh; } return lh != null ? lh : eh != null ? eh : mh; }
rand克隆 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 import java.util.HashMap;public class Node { int value; Node next; Node rand; public Node (int v) { value = v; } } public class Clone { public static Node clone01 (Node head) { HashMap<Node,Node> hashMap = new HashMap <>(); Node cur = head; while (cur != null ){ hashMap.put(cur,new Node (cur.value)); cur = cur.next; } cur = head; while (cur != null ){ hashMap.get(cur).next = hashMap.get(cur.next); hashMap.get(cur).rand = hashMap.get(cur.rand); cur = cur.next; } return hashMap.get(head); } public static Node clone02 (Node head) { if (head == null ){ return null ; } Node cur = head; while (cur != null ){ Node cloneNode = new Node (cur.value); cloneNode.next = cur.next; cur.next = cloneNode; cur = cloneNode.next; } cur = head; while (cur != null ){ cur.next.rand = cur.rand == null ? null : cur.rand.next; cur = cur.next.next; } Node res = head.next; cur = head; Node help; while (cur != null ){ help = cur.next; cur.next = cur.next.next == null ? null : cur.next.next; help.next = cur.next == null ? null : cur.next.next; cur = cur.next; } return res; } }
入环节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public static Node loopInNode (Node head) { if (head == null || head.next == null || head.next.next == null ){ return null ; } Node s = head.next; Node f = head.next.next; while (!s.equals(f)){ if (f.next == null || f.next.next == null ){ return null ; } s = s.next; f = f.next.next; } f = head; while (!s.equals(f)){ f = f.next; s = s.next; } return s; }
证明: 快指针与慢指针均从X出发,在Z相遇。此时,慢指针行使距离为a+b,快指针为a+b+n(b+c)。
所以2*(a+b)=a+b+n*(b+c),推出
a=(n-1)b+n c=(n-1)(b+c)+c;
得到,将此时两指针分别放在起始位置和相遇位置,并以相同速度前进,当一个指针走完距离a时,另一个指针恰好走出 绕环n-1圈加上c的距离。
环形链表第一个入环节点
相交节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 public class IntersectionList { public static Node noLoop (Node n1, Node n2) { if (n1 == null || n2 == null ){ return null ; } int count = 0 ; Node p1 = n1; Node p2 = n2; while (p1.next != null ){ count++; p1 = p1.next; } while (p2.next != null ){ count--; p2 = p2.next; } if (p1 != p2){ return null ; } p1 = count > 0 ? n1 : n2; p2 = p1 == n1 ? n2 : n1; count = Math.abs(count); while (count != 0 ){ p1 = p1.next; count--; } while (p1 != p2){ p1 = p1.next; p2 = p2.next; } return p1; } public static Node haveLoop1 (Node n1, Node n2) { int count = 0 ; Node p1 = n1; Node p2 = n2; while (p1.next != LoopInNode.loopInNode(p1)){ count++; p1 = p1.next; } while (p2.next != LoopInNode.loopInNode(p2)){ count--; p2 = p2.next; } p1 = count > 0 ? n1 : n2; p2 = p1 == n1 ? n2 : n1; count = Math.abs(count); while (count != 0 ){ p1 = p1.next; count--; } while (p1 != p2){ p1 = p1.next; p2 = p2.next; } return p1; } public static Node haveLoop2 (Node n1, Node n2) { Node loop1 = LoopInNode.loopInNode(n1); Node loop2 = LoopInNode.loopInNode(n2); Node n = loop1.next; while (n != loop1){ if (n == loop2){ return loop1; } n = n.next; } return null ; } public static Node haveLoop (Node n1, Node n2) { Node loop1 = LoopInNode.loopInNode(n1); Node loop2 = LoopInNode.loopInNode(n2); if (loop1 == loop2){ return haveLoop1(n1,n2); } return haveLoop2(n1,n2); } public static Node intersection (Node n1, Node n2) { Node loop1 = LoopInNode.loopInNode(n1); Node loop2 = LoopInNode.loopInNode(n2); if (loop1 == null && loop2 == null ){ return noLoop(n1,n2); }else if (loop1 != null && loop2 != null ){ return haveLoop(n1, n2); }else { return null ; } } }
LRU 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 import java.util.HashMap;public class LRU <K, V> { public static class Node <K, V> { private K key; private V val; private Node<K, V> last; private Node<K, V> next; public Node (K k,V v) { val = v; key = k; } } private final HashMap<K, Node<K, V>> map; private Node<K, V> tail; private Node<K, V> head; private final int sizeLimit; private int size; public LRU (int l) { map = new HashMap <>(); sizeLimit = l; size = 0 ; tail = null ; head = null ; } public void set (K k, V v) { if (map.containsKey(k)){ map.get(k).val = v; update(k); return ; } Node<K, V> node = new Node <>(k, v); if (map.isEmpty()){ head = node; }else { node.last = tail; tail.next = node; } tail = node; map.put(k,node); if (size == sizeLimit){ map.remove(head.key); head = head.next; head.last = null ; }else { size++; } } public V get (K k) { if (!map.containsKey(k)){ return null ; } update(k); return map.get(k).val; } private void update (K k) { if (!map.containsKey(k) || map.get(k) == tail){ return ; } Node<K, V> cur = map.get(k); if (cur == head){ head = head.next; }else { cur.last.next = cur.next; cur.next.last = cur.last; } cur.next = null ; cur.last = tail; tail.next = cur; tail = cur; } }
数组和字符串 固定大小的数组实现队列和栈 实现队列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class ArrayQueue { private Object[] arr; private int size; private int H; private int T; private final int limit = 7 ; public ArrayQueue () { arr = new Object [7 ]; size = 0 ; H = 0 ; T = 0 ; } public void push (Object value) { if (size == limit){ System.out.println("Queue is full" ); return ; } if (++T >= limit){ T = 0 ; } arr[T] = value; size++; } public Object pop () { if (size == 0 ){ System.out.println("Queue is empty" ); return null ; } Object popValue = arr[H]; if (H != T){ if (++H >=limit){ H = 0 ; } } size--; return popValue; } }
实现栈 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ArrayStack { Object[] arr; int size; public ArrayStack () { arr = new Object [7 ]; size = 0 ; } public void push (Object value) { if (size == 7 ){ System.out.println("Stack is full" ); return ; } arr[size++] = value; } public Object pop () { if (size == 0 ){ System.out.println("Stack is empty" ); return null ; } return arr[--size]; } }
矩阵 之字形打印矩阵 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Zigzag { public static void zigzag (int [][] arr) { int a_row = 0 ; int a_column = 0 ; int b_row = 0 ; int b_column = 0 ; boolean formUp = false ; while (a_row != arr.length){ zigzagPrint(arr,a_row,a_column,b_row,b_column,formUp); a_row += a_column == arr[0 ].length - 1 ? 1 : 0 ; a_column += a_column == arr[0 ].length - 1 ? 0 : 1 ; b_column += b_row == arr.length - 1 ? 1 : 0 ; b_row += b_row == arr.length - 1 ? 0 : 1 ; formUp = !formUp; } } public static void zigzagPrint (int [][] arr, int a_row, int a_column, int b_row, int b_column, boolean f) { if (f){ while (a_row <= b_row){ System.out.print(arr[a_row++][a_column--] + " " ); } }else { while (b_row >= a_row){ System.out.print(arr[b_row--][b_column++] + " " ); } } } }
螺旋打印矩阵 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class Spiral { public static void spiral (int [][] arr) { int startRow = 0 ; int startColumn = 0 ; int endRow = arr.length - 1 ; int endColumn = arr[0 ].length - 1 ; while (startRow <= endRow && startColumn <= endColumn){ print(arr,startRow++,startColumn++,endRow--,endColumn--); } } public static void print (int [][] arr,int startRow, int startColumn, int endRow, int endColumn) { if (startRow == endRow){ while (startColumn <= endColumn){ System.out.print(arr[startRow][startColumn++] + " " ); } }else if (startColumn == endColumn){ while (startRow >= endRow){ System.out.print(arr[startRow++][startColumn] + " " ); } }else { int curRow = startRow; int curColumn = startColumn; while (curColumn < endColumn){ System.out.print(arr[curRow][curColumn++] + " " ); } while (curRow < endRow){ System.out.print(arr[curRow++][curColumn] + " " ); } while (curColumn > startColumn){ System.out.print(arr[curRow][curColumn--] + " " ); } while (curRow > startRow){ System.out.print(arr[curRow--][curColumn] + " " ); } } } }
原地旋转正方形矩阵 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class rotate { public static void rotate (int [][] arr) { int start = 0 ; int end = arr.length - 1 ; while (start <= end){ process(arr,start++,end--); } } public static void process (int [][] arr,int start, int end) { int num = 0 ; int tmp = 0 ; while (start + num < end){ tmp = arr[start][start + num]; arr[start][start + num] = arr[end - num][start]; arr[end - num][start] = arr[end][end - num]; arr[end][end - num] = arr[start + num][end]; arr[start + num][end] = tmp; num ++; } } }
岛的数量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class Island { public static int countIsland (int [][] arr) { if (arr == null || arr.length == 0 ){ return 0 ; } int count = 0 ; int rows = arr.length; int columns = arr[0 ].length; for (int i = 0 ; i < rows; i++){ for (int j = 0 ; j < columns; j++){ if (arr[i][j] == 1 ){ inflect(arr, i, j, rows, columns); count++; } } } return count; } public static void inflect (int [][] arr,int i,int j, int r, int c) { if (i < 0 || i >= r || j < 0 || j >= c || arr[i][j] != 1 ){ return ; } arr[i][j] = 2 ; inflect(arr, i + 1 , j, r, c); inflect(arr, i, j + 1 , r, c); inflect(arr, i - 1 , j, r, c); inflect(arr, i, j - 1 , r, c); } }
是否为子串KMP 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 public class KMP { public static int KMP (String s1, String s2) { if (s1 == null || s2 == null || s2.length() < 1 || s1.length() < s2.length()) { return -1 ; } char [] str1 = s1.toCharArray(); char [] str2 = s2.toCharArray(); int i1 = 0 ; int i2 = 0 ; int [] next = nextArr(str2); while (i1 < str1.length && i2 < str2.length) { if (str1[i1] == str2[i2]) { i1++; i2++; } else if (i2 == 0 ) { i1++; } else { i2 = next[i2]; } } return i2 == str2.length ? i1 - str2.length : -1 ; } public static int [] nextArr(char [] s) { if ( s.length == 1 ){ return new int [] {-1 }; } int [] next = new int [s.length]; next[0 ] = -1 ; next[1 ] = 0 ; int i = 2 ; int cn = 0 ; while (i < next.length){ if (s[i - 1 ] == s[cn]){ next[i++] = ++cn; } else if (cn != 0 ){ cn = next[cn]; } else { next[i++] = 0 ; } } return next; } }
最长回文子串Manacher 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public class Manacher { public static int manacher (String s) { int n = s.length() * 2 + 1 ; int [] pArr = new int [n]; char [] str = new char [n]; for (int i = 0 ; i < n; i++){ if (i % 2 == 0 ){ str[i] = '?' ; } else { str[i] = s.charAt(i / 2 ); } } int R = -1 ; int C = -1 ; int max = Integer.MIN_VALUE; for (int i = 0 ; i < n; i ++){ pArr[i] = R > i ? Math.min(pArr[2 * C - i], R - i) : 1 ; while (i + pArr[i] < n && i - pArr[i] >= 0 ){ if (str[i + pArr[i]] == str[i - pArr[i]]){ pArr[i]++; }else { break ; } } if (i + pArr[i] > R){ R = i + pArr[i]; C = i; } max = Math.max(max, pArr[i]); } return max - 1 ; } }
滑动窗口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.util.LinkedList;public class SlidingWindow { public int [] maxSlidingWindow(int [] arr, int w) { if (arr == null || w < 1 || arr.length < w){ return null ; } LinkedList<Integer> qmax = new LinkedList <>(); int [] res = new int [arr.length - w + 1 ]; int index = 0 ; for (int i = 0 ; i < arr.length; i++){ while (!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[i]){ qmax.pollLast(); } qmax.addLast(i); if (qmax.peekFirst() == i - w) { qmax.pollFirst(); } if (i >= w - 1 ){ res[index++] = arr[qmax.peekFirst()]; } } return res; } }
分割数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import java.util.HashMap;public class CutArray { public static boolean cut (int [] arr) { if (arr == null || arr.length < 7 ){ return false ; } HashMap<Integer, Integer> map = new HashMap <>(); int sum = arr[0 ]; for (int i = 1 ; i < arr.length; i++){ map.put(sum,i); sum += arr[i]; } int lsum = arr[0 ]; for (int s1 = 1 ; s1 < arr.length - 5 ; s1++){ int checkSum = lsum * 2 + arr[s1]; if (map.containsKey(checkSum)) { int s2 = map.get(checkSum); checkSum += lsum + arr[s2]; if (map.containsKey(checkSum)) { int s3 = map.get(checkSum); if (checkSum + arr[s3] + lsum == sum){ return true ; } } } lsum += arr[s1]; } return false ; } }
凑数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class MakeUp { public static int makeUp (int [] arr, int range) { int touch = 0 ; int ans = 0 ; for (int i = 0 ; i < arr.length; i++){ while (arr[i] > touch + 1 ){ touch += touch + 1 ; ans++; if (touch >= range) { return ans; } } touch += arr[i]; if (touch >= range){ return ans; } } while (range >= touch + 1 ){ touch += touch + 1 ; ans++; } return ans; } }
排序最小子数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class 最小子数组 { public static int minSubArr (int [] arr) { int last = arr[0 ]; int r = 0 ; int l = arr.length - 1 ; for (int i = 1 ; i <= l; i++){ if (arr[i] > last){ last = arr[i]; }else { r = i; } } last = arr[l]; for (int i = l; i >= 0 ; i--){ if (arr[i] < last){ last = arr[i]; }else { l = i; } } return r - l; } }
缺失的第一个正数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { public int firstMissingPositive (int [] nums) { int l = 0 ; int r = nums.length; while (l < r){ if (nums[l] == l + 1 ){ l++; }else if (nums[l] < l + 1 || nums[l] > r || nums[nums[l] - 1 ] == nums[l]){ swap(nums, l, --r); }else { swap(nums, l, nums[l] - 1 ); } } return r + 1 ; } public void swap (int [] arr, int i,int j) { if (arr[i] == arr[j]){ return ; } arr[i] = arr[i] ^ arr[j]; arr[j] = arr[j] ^ arr[i]; arr[i] = arr[i] ^ arr[j]; } }
栈和队列 可以返回最小元素的栈 实现一个特殊的栈,再基本功能的基础上,再实现返回栈中最小元素的功能
pop、push、getMin操作的时间复杂度都是O(1)
设计的栈类型可以用现成的栈结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class MinStack { private Stack<Integer> dataStack; private Stack<Integer> minStack; int min; public MinStack () { dataStack = new Stack <>(); minStack = new Stack <>(); } public void push (int value) { minStack.push(minStack.peek() > value? value:minStack.peek()); dataStack.push(value); } public int getMin () { return minStack.peek(); } public Object pop () { minStack.pop(); return dataStack.pop(); } }
用栈实现队列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class StackToQueue <T> { private Stack<T> pushStack; private Stack<T> popStack; public StackToQueue () { pushStack = new Stack <>(); popStack = new Stack <>(); } public void push (T value) { pushStack.push(value); } public T pop () { if (popStack.isEmpty() && pushStack.isEmpty()){ System.out.println("Queue is empty" ); return null ; }else if (popStack.isEmpty()){ while (!pushStack.isEmpty()){ popStack.push(pushStack.pop()); } } return popStack.pop(); } }
用队列实现栈 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class QueueToStack <T> { LinkedList<T> l1; LinkedList<T> l2; public QueueToStack () { l1 = new LinkedList <>(); l2 = new LinkedList <>(); } public void push (T value) { if (l2.isEmpty()){ l1.push(value); }else { l2.push(value); } } public T pop () { if (l1.isEmpty() && l2.isEmpty()){ System.out.println("Stack is empty" ); return null ; } if (l2.isEmpty()){ for (int i = 0 ;i < l1.size()-1 ;i++){ l2.push(l1.pop()); } return l1.pop(); }else { for (int i = 0 ;i < l2.size()-1 ;i++){ l1.push(l2.pop()); } return l2.pop(); } } }
递归与动态规划 Master公式
形如
T(N) = a * T(N/b) + O(N^d)(其中a、b、d都是常数)
的递归函数,可以直接通过Master公式来确定时间复杂度
如果log(b,a) < d,复杂度为O(N^d)
如果log(b,a) > d,复杂度为O(N^log(b,a))
如果log(b,a) = d,复杂度为O(N^d * logN)
用递归实现数组上下标L到R的最大值 1 2 3 4 5 6 7 8 9 public static int getMax (int [] arr,int L,int R) { if (L == R){ return arr[L]; } int mid = L + ((R - L) >> 1 ); int leftMax = getMax(arr,L,mid); int rightMax = getMax(arr,mid + 1 ,R); return Math.max(leftMax,rightMax); }
数组小和 在一个数组中,一个数左边比它小的数的总和,叫数的小和,数组中所有数的小和,叫数组小和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public int smallSum (int [] arr,int L,int R) { if (L == R){ return 0 ; } int M = L + ((R - L) >> 1 ); return smallSum(arr,L,M) + smallSum(arr,M + 1 ,R) + merge(arr,L,M,R); } public static int merge (int [] arr,int L,int M,int R) { int [] help = new int [R - L + 1 ]; int i = 0 ; int res = 0 ; int p1 = L; int p2 = M + 1 ; while (p1 <= M && p2 <= R){ res = arr[p1] < arr[p2]? (R - p2 + 1 ) * arr[p1]:0 ; help[i++] = arr[p1] <= arr[p2]?arr[p1++]:arr[p2++]; } while (p1 <= M){ help[i++] = arr[p1++]; } while (p2 <= R){ help[i++] = arr[p2]; } for (i = 0 ;i < help.length;i++){ arr[L + i] = help[i]; } return res; }
暴力递归 汉诺塔 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 public class ViolentRecursion { public static void hanoi1 (int n) { leftToRight(n); } public static void leftToRight (int n) { if (n == 1 ){ System.out.println("num1,left -> right" ); return ; } leftToMid(n -1 ); System.out.println("num" + n + ",left -> right" ); midToRight(n - 1 ); } public static void leftToMid (int n) { if (n == 1 ) { System.out.println("num1,left -> mid" ); } leftToRight(n - 1 ); System.out.println("num" + n + ",left -> mid" ); rightToMid(n - 1 ); } public static void midToRight (int n) { if (n == 1 ){ System.out.println("num1,mid -> right" ); return ; } midToLeft(n -1 ); System.out.println("num" + n + ",mid -> right" ); leftToRight(n - 1 ); } public static void midToLeft (int n) { if (n == 1 ){ System.out.println("num1,mid -> left" ); return ; } midToRight(n -1 ); System.out.println("num" + n + ",mid -> left" ); rightToLeft(n - 1 ); } public static void rightToLeft (int n) { if (n == 1 ){ System.out.println("num1,right -> left" ); return ; } rightToMid(n -1 ); System.out.println("num" + n + ",right -> left" ); midToLeft(n - 1 ); } public static void rightToMid (int n) { if (n == 1 ){ System.out.println("num1,right -> mid" ); return ; } rightToLeft(n -1 ); System.out.println("num" + n + ",right -> mid" ); leftToMid(n - 1 ); } public static void hanoi2 (int n) { if (n > 0 ){ func(n, "left" ,"right" ,"mid" ); } } public static void func (int n, String from, String to, String other) { if (n == 1 ){ System.out.println("num" + 1 + "," + from + " -> " + to); }else { func(n - 1 ,from,other,to); System.out.println("num" + n + "," + from + " -> " + to); func(n - 1 ,other,to,from); } } public static void main (String[] args) { int n = 3 ; hanoi1(n); System.out.println("================" ); hanoi2(n); } }
逆序栈 给你一个栈
逆序这个栈
不能申请额外数据结构
只能用递归函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.Stack;public class ReverseStackUsingRecursive { public static void reverse (Stack<Integer> stack) { if (stack.isEmpty()){ return ; } int i = f(stack); reverse(stack); stack.push(i); } public static int f (Stack<Integer> stack) { int result = stack.pop(); if (stack.isEmpty()){ return result; }else { int last = f(stack); stack.push(result); return last; } } }
N皇后和N皇后plus 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 public class N_Queens { public static int nQueens (int n) { if (n < 1 ){ return 0 ; } int [] record = new int [n]; return process(0 , record, n); } public static int process (int i,int [] record,int n) { if (i == n){ return 1 ; } int res = 0 ; for (int j = 0 ; j < n; j++){ if (isValid(record,i,j)){ record[i] = j; res += process(i + 1 , record, n); } } return res; } public static boolean isValid (int [] record,int i,int j) { for (int k = 0 ; k < i; k++){ if (j == record[k] ||Math.abs(record[k] - j) == Math.abs(i - k) ){ return false ; } } return true ; } public static int nQueensPlus (int n) { if (n < 1 || n > 32 ) { return 0 ; } int limit = n == 32 ? -1 : (1 << n) - 1 ; return process2(limit,0 ,0 ,0 ); } public static int process2 (int limit, int colLim, int leftDiaLim, int rightDiaLim) { if (colLim == limit){ return 1 ; } int pos = limit & ( ~(colLim | leftDiaLim | rightDiaLim)); int mostRightOne = 0 ; int res = 0 ; while (pos != 0 ) { mostRightOne = pos & (~pos + 1 ); res += process2(limit, colLim | mostRightOne, (leftDiaLim | mostRightOne) << 1 , (rightDiaLim | mostRightOne) >>> 1 ); pos = pos ^ mostRightOne; } return res; } }
斐波那契数列 1 2 3 4 5 6 public static int f (int n) { if ( n <= 2 ){ return 1 ; } return f(n - 1 ) + f ( n - 2 ); }
暴力递归到动态规划的套路 所有由n个可变参数写成的暴力递归都可以改成动态规划
Robot 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 public class Robot { public static int ways1 (int N,int M,int K,int P) { if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N){ return 0 ; } return walk1(N,M,K,P); } public static int walk1 (int n, int cur, int rest, int p) { if (rest == 0 ){ return cur == p ? 1 : 0 ; } if (cur == 1 ){ return walk1(n,2 ,rest - 1 ,p); } if (cur == n){ return walk1(n,n - 1 ,rest - 1 ,p); } return walk1(n,cur + 1 ,rest - 1 ,p) + walk1(n,cur - 1 ,rest - 1 ,p); } public static int waysCache (int N, int M, int K, int P) { if (N < 2 || K < 1 || M < 1 || M > N || P < 1 || P > N){ return 0 ; } int [][] dp = new int [N + 1 ][K + 1 ]; for (int [] ints : dp) { for (int anInt : ints) { anInt = -1 ; } } return walkCache(N,M,K,P,dp); } public static int walkCache (int n, int cur, int rest, int end, int [][] dp) { if (dp[cur][rest] != -1 ){ return dp[cur][rest]; } if (rest == 0 ){ dp[cur][rest] = cur == end ? 1 : 0 ; } else if (cur == 1 ){ dp[cur][rest] = walkCache(n,2 ,rest - 1 ,end,dp); } else if (cur == n){ dp[cur][rest] = walkCache(n,n - 1 ,rest - 1 ,end,dp); } else { dp[cur][rest] = walkCache(n,cur + 1 ,rest - 1 ,end,dp) + walkCache(n,cur - 1 ,rest - 1 ,end,dp); } return dp[cur][rest]; } public static int ways2 (int n,int cur,int rest,int end) { if (n < 2 || rest < 1 || cur < 1 || cur > n || end < 1 || end > n){ return 0 ; } int [][] dp = new int [n + 1 ][rest + 1 ]; dp[0 ][end] = 1 ; for (int i = 1 ; i <= n; i++){ for (int j = 1 ; j <= rest; j++){ if (j == 1 ){ dp[i][j] = dp[i - 1 ][j - 1 ]; }else if (j == rest){ dp[i][j] = dp[i - 1 ][j + 1 ]; }else { dp[i][j] = dp[i - 1 ][j - 1 ] + dp[i - 1 ][j + 1 ]; } } } return dp[cur][rest]; } }
字符串的全部子序列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 import java.util.ArrayList;import java.util.HashSet;import java.util.List;public class Subsequence { public static List<String> subsequence1 (String s) { char [] str = s.toCharArray(); String path = "" ; List<String> ans = new ArrayList <>(); process1(str,0 ,ans,path); return ans; } public static void process1 (char [] s,int index,List<String> ans,String path) { if (index == s.length) { ans.add(path); return ; } String no = path; process1(s,index + 1 , ans, no); String yes = path + s[index]; process1(s,index + 1 , ans, yes); } public static List<String> subsequenceNoRepeat (String s) { char [] str = s.toCharArray(); String path = "" ; HashSet<String> set = new HashSet <>(); process2(str,0 ,set,path); List<String> ans = new ArrayList <>(); for (String cur : set) { ans.add(cur); } return ans; } public static void process2 (char [] s,int index,HashSet<String> set,String path) { if (index == s.length) { set.add(path); return ; } String no = path; process2(s,index + 1 , set, no); String yes = path + s[index]; process2(s,index + 1 , set, yes); } }
字符串的全排列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 import java.util.ArrayList;import java.util.Arrays;import java.util.HashSet;import java.util.List;public class Permutations { public static List<String> permutations (String s) { List<String> ans = new ArrayList <>(); if (s == null || s.length() == 0 ){ return ans; } char [] str = s.toCharArray(); process1(str,ans,0 ); return ans; } public static void process1 (char [] s, List<String> ans, int index) { if (index == s.length){ ans.add(Arrays.toString(s)); } for (int i = index; i < s.length; i++){ swap(s,index,i); process1(s,ans,index + 1 ); swap(s,index,i); } } public static void swap (char [] s,int i, int j) { char temp = s[i]; s[i] = s[j]; s[j] = temp; } public static List<String> permutationsNoRepeat (String s) { List<String> ans = new ArrayList <>(); if (s == null || s.length() == 0 ){ return ans; } char [] str = s.toCharArray(); process2(str,ans,0 ); return ans; } public static void process2 (char [] s, List<String> ans, int index) { if (index == s.length){ ans.add(Arrays.toString(s)); } HashSet<Character> set = new HashSet <>(); for (int i = index; i < s.length; i++){ if (!set.contains(s[i])){ set.add(s[i]); swap(s,index,i); process2(s,ans,index + 1 ); swap(s,index,i); } } } }
转化数字字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 public class LeftToRight { public static int number (String str) { if (str == null || str.length() == 0 ){ return 0 ; } return process(str.toCharArray(),0 ); } public static int process (char [] str, int i) { if (i == str.length){ return 1 ; } if (str[i] == '0' ){ return 0 ; } if (str[i] == '1' ){ int res = process(str,i + 1 ); if (i + 1 < str.length){ res += process(str,i + 2 ); } return res; } if (str[i] == '2' ){ int res = process(str, i + 1 ); if (i + 1 < str.length && (str[i + 1 ] >= '0' && str[i + 1 ] <= '6' )) { res += process(str, i + 2 ); } return res; } return process(str, i + 1 ); } public static int dp (String s) { if (s == null || s.length() == 0 ){ return 0 ; } char [] str = s.toCharArray(); int n = str.length; int [] dp = new int [n + 1 ]; dp[n] = 1 ; for (int i = n - 1 ; i >= 0 ; i--){ if (str[i] == '0' ){ dp[i] = 0 ; } if (str[i] == '1' ){ dp[i] = dp[i + 1 ]; if (i + 1 < str.length){ dp[i] += dp[i + 2 ]; } } if (str[i] == '2' ){ dp[i] = dp[i + 1 ]; if (i + 1 < str.length && (str[i + 1 ] >= '0' && str[i + 1 ] <= '6' )) { dp[i] += dp[i + 2 ]; } } } return dp[0 ]; } }
背包问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 public class Bag { public static int bag1 (int [] w, int [] v,int bag) { return process1(w,v,0 ,0 ,bag); } public static int process1 (int [] w, int [] v, int index, int alreadyW, int bag) { if (alreadyW > bag) { return -1 ; } if (index == w.length){ return 0 ; } int v1 = process1(w,v,index + 1 ,alreadyW,bag); int v2next = process1(w,v,index + 1 ,alreadyW + w[index],bag); int v2 = -1 ; if (v2next != -1 ){ v2 = v[index] + v2next; } return Math.max(v1,v2); } public static int bag2 (int [] w, int [] v,int bag) { return process2(w,v,0 ,bag); } public static int process2 (int [] w,int [] v,int index,int rest) { if (rest < 0 ){ return -1 ; } if (index == w.length) { return 0 ; } int v1 = process2(w,v,index + 1 ,rest); int v2 = -1 ; int v2Next = process2(w,v,index + 1 ,rest - w[index]); if (v2Next != -1 ){ v2 = v[index] + v2Next; } return Math.max(v1,v2); } public static int bag3 (int [] w, int [] v, int bag) { int n = w.length; int [][] dp = new int [n + 1 ][bag + 1 ]; int v1; int v2; for (int index = n - 1 ; index >= 0 ; index--){ for (int rest = 0 ; rest <= bag; rest++){ v1 = dp[index + 1 ][rest]; v2 = -1 ; if (rest - w[index] >= 0 ){ v2 = v[index] + dp[index + 1 ][rest - w[index]]; } dp[index][rest] = Math.max(v1, v2); } } return dp[0 ][bag]; } }
纸牌博弈 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public class Scope { public static int win1 (int [] arr) { if (arr == null || arr.length == 0 ){ return 0 ; } return Math.max( firstHand(arr,0 ,arr.length-1 ), backHand(arr,0 ,arr.length -1 ) ); } public static int firstHand (int [] arr,int l, int r) { if (l == r) { return arr[l]; } return Math.max( arr[l] + backHand(arr,l + 1 ,r), arr[r] + backHand(arr,l,r-1 ) ); } public static int backHand (int [] arr,int l,int r) { if (l == r){ return 0 ; } return Math.min( firstHand(arr,l + 1 , r), firstHand(arr,l,r - 1 )); } public static int win2 (int [] arr) { if (arr == null || arr.length == 0 ){ return 0 ; } int n = arr.length; int [][] firstHand = new int [n][n]; int [][] backHand = new int [n][n]; for (int i = 0 ; i < n; i++){ firstHand[i][i] = arr[i]; } int l; int r; for (int i = 1 ; i < n; i++){ l = 0 ; r = i; while (l < n && r < n){ firstHand[l][r] = Math.max( arr[l] + backHand[l + 1 ][r], arr[r] + backHand[l][r - 1 ] ); backHand[l][r] = Math.min( firstHand[l + 1 ][r], firstHand[l][r - 1 ]); l++; r++; } } return Math.max( firstHand[0 ][n - 1 ], backHand[0 ][n -1 ] ); } }
货币面值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 public class FaceValue { public static int ways1 (int [] arr, int aim) { if (arr == null || arr.length == 0 || aim <=0 ){ return 0 ; } return process1(arr,0 ,aim); } public static int process1 (int [] arr,int index,int rest) { if (index == arr.length){ return rest == 0 ? 1 : 0 ; } int ways = 0 ; for (int i = 0 ;i * arr[index] <= rest ;i++){ ways += process1(arr,index + 1 ,rest - i * arr[index]); } return ways; } public static int ways2 (int [] arr, int aim) { if (arr == null || arr.length == 0 || aim <=0 ){ return 0 ; } int n = arr.length; int [][] dp = new int [n + 1 ][aim + 1 ]; for (int i = 0 ; i < dp.length; i++){ for (int j = 0 ; j < dp[0 ].length; j++){ dp[i][j] = -1 ; } } return process2(arr,0 ,aim,dp); } public static int process2 (int [] arr,int index,int rest,int [][] dp) { if (dp[index][rest] != -1 ){ return dp[index][rest]; } if (index == arr.length){ dp[index][rest] = rest == 0 ? 1 : 0 ; return dp[index][rest]; } int ways = 0 ; for (int i = 0 ;i * arr[index] <= rest ;i++){ ways += process2(arr,index + 1 ,rest - i * arr[index],dp); } dp[index][rest] = ways; return ways; } public static int ways3 (int [] arr, int aim) { if (arr == null || arr.length == 0 || aim <=0 ){ return 0 ; } int n = arr.length; int [][] dp = new int [n + 1 ][aim + 1 ]; dp[n][0 ] = 1 ; for (int index = n - 1 ; index >= 0 ; index--){ for (int rest = 0 ; rest < aim; rest++){ for (int i = 0 ;i * arr[index] <= rest ;i++){ dp[index][rest] += dp[index + 1 ][rest - i * arr[index]]; } } } return dp[0 ][aim]; } public static int ways4 (int [] arr, int aim) { if (arr == null || arr.length == 0 || aim <=0 ){ return 0 ; } int n = arr.length; int [][] dp = new int [n + 1 ][aim + 1 ]; dp[n][0 ] = 1 ; for (int index = n - 1 ; index >= 0 ; index--){ for (int rest = 0 ; rest < aim; rest++){ dp[index][rest] = dp[index + 1 ][rest]; if (rest - arr[index] >= 0 ){ dp[index][rest] += dp[index][rest - arr[rest]]; } } } return dp[0 ][aim]; } }
贴纸问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import java.util.HashMap;public class Paster { public static int paster (String s, String[] paster) { int n = paster.length; int [][] map = new int [n][26 ]; HashMap<String, Integer> dp = new HashMap <>(); for (int i = 0 ; i < n; i++){ char [] str = paster[i].toCharArray(); for (char c : str){ map[i][c - 'a' ]++; } } dp.put("" , 0 ); return process1(dp, map, s); } public static int process1 (HashMap<String, Integer> dp, int [][] map, String rest) { if (dp.containsKey(rest)){ return dp.get(rest); } int ans = Integer.MAX_VALUE; int n = map.length; int [] restMap = new int [26 ]; char [] target = rest.toCharArray(); for (char c : target){ restMap[c - 'a' ]++; } for (int i = 0 ; i < n; i++){ if (map[i][target[0 ] - 'a' ] == 0 ){ continue ; } StringBuilder sb = new StringBuilder (); for (int j = 0 ; j < 26 ; j ++){ if (restMap[j] > 0 ){ for (int k = 0 ; k < Math.max(0 ,restMap[j] - map[i][j]); k++){ sb.append((char )('a' + j)); } } } String s = sb.toString(); int tmp = process1(dp,map,s); if (tmp != -1 ){ ans = Math.min(ans,1 + tmp); } } dp.put(rest,ans == Integer.MAX_VALUE ? -1 : ans); return dp.get(rest); } }
最长公共子序列LCS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class LCS { public static int lcs (String s1, String s2) { int [][] dp = new int [s1.length()][s2.length()]; dp[0 ][0 ] = s1.charAt(0 ) == s2.charAt(0 ) ? 1 : 0 ; for (int i = 1 ; i < s1.length(); i++){ dp[i][0 ] = Math.max(dp[i - 1 ][0 ], s1.charAt(i) == s2.charAt(0 ) ? 1 : 0 ); } for (int j = 1 ; j < s2.length(); j++){ dp[0 ][j] = Math.max(dp[0 ][j - 1 ], s1.charAt(0 ) == s2.charAt(j) ? 1 : 0 ); } for (int i = 1 ; i < dp.length; i ++){ for (int j = 1 ; j < dp[0 ].length; j ++){ dp[i][j] = Math.max(dp[i - 1 ][j], dp[i][j - 1 ]); if (s1.charAt(i) == s2.charAt(j)){ dp[i][j] = Math.max(dp[i][j], dp[i - 1 ][j - 1 ] + 1 ); } } } return dp[s1.length() - 1 ][s2.length() - 1 ]; } }
洗杯子 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 public class WashCups { public static int wash (int [] drinks, int washTime, int dryTime) { if (drinks == null || drinks.length == 0 ){ return 0 ; } if ( washTime > dryTime){ return drinks[drinks.length - 1 ] + dryTime; } return process(drinks,washTime,dryTime,0 ,0 ); } public static int process (int [] drinks, int washTime, int dryTime, int index, int washLine) { int wash = Math.max(washLine, drinks[index]) + washTime; int dry = drinks[index] + dryTime; if (index == drinks.length - 1 ){ return Math.min( wash, dry ); } int next1 = process(drinks,washTime,dryTime,index + 1 , wash); int p1 = Math.max(wash,next1); int next2 = process(drinks,washTime,dryTime,index + 1 ,washLine); int p2 = Math.max(dry,next2); return Math.min(p1,p2); } public static int dp (int [] drinks, int washTime, int dryTime) { if (drinks == null || drinks.length == 0 ){ return 0 ; } if ( washTime > dryTime){ return drinks[drinks.length - 1 ] + dryTime; } int limit = 0 ; int n = drinks.length; for (int i = 0 ; i < n; i++){ limit = Math.max(limit, drinks[i]) + washTime; } int [][] dp = new int [n][limit + 1 ]; for (int washLine = 0 ; washLine < limit; washLine++){ dp[n - 1 ][washLine] = Math.min(Math.max(washLine, drinks[n - 1 ]) + washTime,drinks[n - 1 ] + dryTime); } for (int index = n - 2 ; index >= 0 ; index--){ for (int washLine = 0 ; washLine < limit; washLine++){ int p1 = Integer.MAX_VALUE; int wash = Math.max(washLine, drinks[index]) + washTime; if (wash <= limit){ p1 = Math.max(wash,dp[index + 1 ][wash]); } int dry = drinks[index] + dryTime; int p2 = Math.max(dry,dp[index + 1 ][washLine]); dp[index][washLine] = Math.min(p1,p2); } } return dp[0 ][0 ]; } }
马走日 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class Cheese { public static int getWays (int x,int y, int k) { int [][][] dp = new int [10 ][9 ][k + 1 ]; dp[0 ][0 ][0 ] = 1 ; for (int step = 1 ; step < k + 1 ; step++){ for (int i = 0 ; i < 10 ; i++){ for (int j = 0 ; j < 9 ; j++){ dp[i][j][step] += getVal(dp,i + 2 , j + 1 ,step - 1 ); dp[i][j][step] += getVal(dp,i + 2 , j - 1 ,step - 1 ); dp[i][j][step] += getVal(dp,i - 2 , j + 1 ,step - 1 ); dp[i][j][step] += getVal(dp,i - 2 , j - 1 ,step - 1 ); dp[i][j][step] += getVal(dp,i + 1 , j + 2 ,step - 1 ); dp[i][j][step] += getVal(dp,i + 1 , j - 2 ,step - 1 ); dp[i][j][step] += getVal(dp,i - 1 , j + 2 ,step - 1 ); dp[i][j][step] += getVal(dp,i - 1 , j - 2 ,step - 1 ); } } } return dp[x][y][k]; } public static int getVal (int [][][] dp, int i, int j,int k) { if (i < 0 || i >= 10 || j < 0 || j >= 9 ) { return 0 ; } return dp[i][j][k]; } public static void main (String[] args) { System.out.println(getWays(1 ,2 ,1 )); } }
最小不可组成和 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import java.util.Arrays;public class MinIncomposableSum { public static int minIncomposableSum (int [] arr) { int n = arr.length; int min = Integer.MAX_VALUE; int sum = 0 ; for (int i : arr) { min = Math.min(min, i); sum += i; } boolean [][] dp = new boolean [n][sum + 1 ]; dp[0 ][arr[0 ]] = true ; for (int i = 1 ; i < n; i++){ for (int j = 1 ; j < sum + 1 ; j++){ if (arr[i] == j){ dp[i][j] = true ; }else if (dp[i - 1 ][j]){ dp[i][j] = true ; }else if (j - arr[i] >= 0 && dp[i - 1 ][j- arr[i]]){ dp[i][j] = true ; } } } int ans = min; while (ans <= sum){ if (dp[n - 1 ][ans]){ return ans; } ans++; } return sum + 1 ; } public static int plus (int [] arr) { Arrays.sort(arr); int range = 1 ; for (int i = 1 ; i < arr.length; i++){ if (arr[i] <= range + 1 ) { range += arr[i]; } else { return range + 1 ; } } return range + 1 ; } }
贿赂怪兽 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class BribeMonster { public static int bribeMonster (int [] d, int [] p) { return process(d, p, 0 , 0 ); } public static int process (int [] d, int [] p, int index, int value) { if (index == d.length){ return 0 ; } if (value >= d[index]){ return Math.min(process(d, p, index + 1 , value + p[index]), process(d, p, index + 1 , value)); }else { return process(d, p, index + 1 , value + p[index]); } } public static int dp (int [] d, int [] p) { int total = 0 ; for (int j : p) { total += j; } int [][] dp = new int [d.length + 1 ][total + 1 ]; for (int index = d.length - 1 ; index >= 0 ; index--){ for (int value = 0 ; value <= total; value++){ if (value >= d[index]){ dp[index][value] = Math.min(dp[index + 1 ][value + p[index]], dp[index + 1 ][value]); }else { dp[index][value] = dp[index + 1 ][value + p[index]]; } } } return dp[0 ][0 ]; } }
成为回文最少插入次数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public int minInsertions (String s) { int n = s.length(); if (n == 1 ){ return 0 ; } if (n == 2 ){ return s.charAt(0 ) == s.charAt(1 ) ? 0 : 1 ; } int [][] dp = new int [n][n]; char [] str = s.toCharArray(); for (int i = 0 ; i < n - 1 ; i++){ if (str[i] != str[i + 1 ]){ dp[i][i + 1 ] = 1 ; } } for (int l = n - 3 ; l >= 0 ; l--){ for (int r = l + 2 ; r < n; r++){ if (str[l] == str[r]){ dp[l][r] = Math.min(Math.min(dp[l + 1 ][r], dp[l][r - 1 ]) + 1 , dp[l + 1 ][r - 1 ]); }else { dp[l][r] = Math.min(dp[l + 1 ][r], dp[l][r - 1 ]) + 1 ; } } } return dp[0 ][n - 1 ]; } }
最长递增路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public int longestIncreasingPath (int [][] matrix) { int res = 0 ; int [][] dp = new int [matrix.length][matrix[0 ].length]; for (int i = 0 ; i < matrix.length; i++){ for (int j = 0 ; j < matrix[0 ].length; j++){ res = Math.max(res, process(matrix, i, j, dp)); } } return res; } public int process (int [][] matrix, int i, int j, int [][] dp) { if (dp[i][j] != 0 ){ return dp[i][j]; } int nextUp = 0 ; if (i > 0 && matrix[i - 1 ][j] > matrix[i][j]){ nextUp = process(matrix, i - 1 , j, dp); } int nextDown = 0 ; if (i < matrix.length - 1 && matrix[i + 1 ][j] > matrix[i][j]){ nextDown = process(matrix, i + 1 , j, dp); } int nextLeft = 0 ; if (j > 0 && matrix[i][j - 1 ] > matrix[i][j]){ nextLeft = process(matrix, i, j - 1 , dp); } int nextRight = 0 ; if (j < matrix[0 ].length - 1 && matrix[i][j + 1 ] > matrix[i][j]){ nextRight = process(matrix, i, j + 1 , dp); } dp[i][j] = Math.max(Math.max(nextLeft,nextRight),Math.max(nextDown,nextUp)) + 1 ; return dp[i][j]; } }
字符串解码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Solution { public String decodeString (String s) { return process(s.toCharArray(), 0 ).res; } public class Info { private String res; private int stop; public Info (String r, int s) { res = r; stop = s; } } public Info process (char [] s, int index) { StringBuilder res = new StringBuilder (); int count = 0 ; while (index < s.length && s[index] != ']' ){ if (s[index] == '[' ){ Info info = process(s, index + 1 ); while (count > 0 ){ res.append(info.res); count--; } index = info.stop + 1 ; } else { if (s[index] >= '0' && s[index] <= '9' ){ count = count * 10 + s[index] - '0' ; } if (s[index] >= 'a' && s[index] <= 'z' ){ res.append(String.valueOf(s[index])); } index++; } } return new Info (res.toString(),index); } }
树 堆 大根堆 任何子树最大值都是头结点的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 public class BigHeap { int heapSize; int [] heap; private final int limit; public BigHeap (int limit) { heapSize = 0 ; heap = new int [limit]; this .limit = limit; } public boolean isEmpty () { return heapSize == 0 ; } public boolean isFull () { return heapSize == limit; } public void push (int value) { if (isFull()){ throw new RuntimeException ("heap is full" ); } heap[heapSize] = value; heapInsert(heap,heapSize++); } private void heapInsert (int [] arr,int index) { while (arr[index] > arr[(index - 1 ) / 2 ]){ swap(arr,index,(index - 1 ) / 2 ); index = (index - 1 ) / 2 ; } } private void swap (int [] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public int pop () { int ans = heap[0 ]; swap(heap,0 ,--heapSize); heapify(heap,0 ,heapSize); return ans; } private void heapify (int [] arr,int index,int heapSize) { int left = index * 2 + 1 ; while (left < heapSize){ int largest = left + 1 < heapSize && arr[left + 1 ] > arr[left] ? left + 1 : left; largest = arr[largest] > arr[index] ? largest : index; if (largest == index){ break ; } swap(arr,index,largest); index = largest; left = index * 2 + 1 ; } } }
堆排序 在时间复杂度O(N*logN)的情况下,额外空间复杂度可达到O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 public class HeapSort { public void heapSort1 (int [] arr) { for (int i = arr.length - 1 ; i > 0 ; i--){ heapify(arr, i, arr.length); } } public void heapSort2 (int [] arr) { for (int i = 0 ;i < arr.length; i++){ heapInsert(arr,i); } } public void bigHeapSort (int [] bigHeap) { int heapSize = bigHeap.length; while (heapSize > 0 ){ swap(bigHeap,0 ,--heapSize); heapify(bigHeap,0 ,heapSize); } } public void sort (int [] arr) { heapSort1(arr); bigHeapSort(arr); } private void heapify (int [] arr,int index,int heapSize) { int left = index * 2 + 1 ; while (left < heapSize) { int largest = left + 1 < heapSize && arr[left + 1 ] > arr[left] ? left + 1 : left; largest = arr[largest] > arr[index] ? largest : index; if (largest == index) { break ; } swap(arr, index, largest); index = largest; left = index * 2 + 1 ; } } private void heapInsert (int [] arr,int index) { while (arr[index] > arr[(index - 1 ) / 2 ]){ swap(arr,index,(index - 1 ) / 2 ); index = (index - 1 ) / 2 ; } } private void swap (int [] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
系统实现的堆PriorityQueue 几乎有序的数组 题目:已知一个几乎有序的数组。几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离一定不会超过k,并且k相对于数组长度来说是比较小的
请选择一个合适的排序策略,对这个数组进行排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.PriorityQueue;public class PriorityQueue_ { public static void AlmostOrderly (int [] arr,int k) { PriorityQueue<Integer> pq = new PriorityQueue <>(); int index = 0 ; for (int i = 0 ;i < arr.length;i++){ pq.add(arr[i]); if (pq.size() > k + 1 ){ arr[index++] = pq.poll(); } } while (!pq.isEmpty()){ arr[index++] = pq.poll(); } } }
比较器 用比较器把PriorityQueue改成大根堆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static class MyComp implements Comparator <Integer>{ @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } } public static void main (String[] args) { PriorityQueue<Integer> priorityQueue1 = new PriorityQueue <>(new MyComp ()); PriorityQueue<Integer> priorityQueue2 = new PriorityQueue <>(new Comparator <Integer>() { @Override public int compare (Integer o1, Integer o2) { return o2 - o1; } }); }
TopK 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 import java.util.Comparator;import java.util.PriorityQueue;public class TopK { public static class Node { private int ai; private int bi; private final int sum; public Node (int a, int b, int s) { ai = a; bi = b; sum = s; } } public static int [] topK(int [] a, int [] b, int k){ PriorityQueue<Node> heap = new PriorityQueue <>(new Comparator <Node>() { @Override public int compare (Node o1, Node o2) { return o2.sum - o1.sum; } }); int i = a.length - 1 ; int j = b.length - 1 ; k = Math.min(k,(i + 1 ) * (j + 1 )); boolean [][] check = new boolean [i + 1 ][j + 1 ]; int [] res = new int [k]; int index = 0 ; heap.add(new Node (i,j,a[i] + b[j])); check[i][j] = true ; while (index < k){ Node cur = heap.poll(); res[index++] = cur.sum; i = cur.ai; j = cur.bi; if (i - 1 >= 0 && !check[i - 1 ][j]){ check[i - 1 ][j] = true ; heap.add(new Node (i - 1 , j, a[i - 1 ] + b[j])); } if (j - 1 >= 0 && !check[i][j - 1 ]){ check[i][j - 1 ] = true ; heap.add(new Node (i, j - 1 , a[i] + b[j - 1 ])); } } return res; } public static int [] topK(int [][] arr, int k){ PriorityQueue<Node> heap = new PriorityQueue <>(new Comparator <Node>() { @Override public int compare (Node o1, Node o2) { return o1.sum - o2.sum; } }); boolean [][] check = new boolean [arr.length][arr[0 ].length]; int [] res = new int [k]; int index = 0 ; heap.add(new Node (0 ,0 ,arr[0 ][0 ])); check[0 ][0 ] = true ; int i = 0 ; int j = 0 ; while (index < k){ Node cur = heap.poll(); res[index++] = cur.sum; i = cur.ai; j = cur.bi; if (i + 1 < arr.length && !check[i + 1 ][j]){ check[i + 1 ][j] = true ; heap.add(new Node (i + 1 , j, arr[i + 1 ][j])); } if (j + 1 < arr.length && !check[i][j + 1 ]){ check[i][j + 1 ] = true ; heap.add(new Node (i, j + 1 , arr[i][j + 1 ])); } } return res; } }
前缀树 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 import java.util.HashMap;public class TrieTree { public static class Node { public int pass; public int end; public HashMap<Character,Node> next; public Node () { pass = 0 ; end = 0 ; next = new HashMap <>(); } } public static class Trie { private Node root; public Trie () { root = new Node (); } public void insert (String s) { if (s == null ){ return ; } Node node = root; node.pass++; for (int i = 0 ; i < s.length(); i++){ if (!node.next.containsKey(s.charAt(i))){ node.next.put(s.charAt(i),new Node ()); } node = node.next.get(s.charAt(i)); node.pass++; } node.end++; } public int search (String s) { if (s == null ){ return 0 ; } Node node = root; for (int i = 0 ; i < s.length(); i++){ if (!node.next.containsKey(s.charAt(i))){ return 0 ; } node = node.next.get(s.charAt(i)); } return node.end; } public void delete (String s) { if (search(s) == 0 ){ return ; } Node node = root; node.pass--; for (int i = 0 ; i < s.length(); i++){ if (--node.next.get(s.charAt(i)).pass == 0 ){ node.next.remove(s.charAt(i)); return ; } node = node.next.get(s.charAt(i)); } node.end--; } public int prefixNumber (String pre) { if (pre == null ){ return 0 ; } Node node = root; for (int i = 0 ; i < pre.length(); i++){ if (!node.next.containsKey(pre.charAt(i))){ return 0 ; } node = node.next.get(pre.charAt(i)); } return node.pass; } } }
AC自动机 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import java.util.LinkedList;import java.util.Queue;public class AC { public class Node { public int end; public Node fail; public Node[] nexts; public Node () { end = 0 ; fail = null ; nexts = new Node [26 ]; } } public class ACAutomation { private Node root; public ACAutomation () { root = new Node (); } public void insert (String s) { char [] str = s.toCharArray(); Node cur = root; int index = 0 ; for (char c : str) { index = c - 'a' ; if (cur.nexts[index] == null ) { Node next = new Node (); cur.nexts[index] = next; } cur = cur.nexts[index]; } cur.end++; } public void build () { Queue<Node> queue = new LinkedList <>(); queue.add(root); Node cur = null ; Node cfail = null ; while (!queue.isEmpty()){ cur = queue.poll(); for (int i = 0 ; i < 26 ; i++){ if (cur.nexts[i] != null ){ cur.nexts[i].fail = root; cfail = cur.fail; while (cfail != null ){ if (cfail.nexts[i] != null ){ cur.nexts[i].fail = cfail.nexts[i]; break ; } cfail = cfail.fail; } queue.add(cur.nexts[i]); } } } } } }
二叉树 先序中序后序遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 import java.util.Stack;public class BinaryTree { public static class Node { public int value; public Node left; public Node right; public Node (int value) { this .value = value; } } public static void pre1 (Node head) { if (head == null ){ return ; } System.out.println(head.value); pre1(head.left); pre1(head.right); } public static void pre2 (Node head) { if (head == null ){ return ; } Stack<Node> nodes = new Stack <>(); nodes.push(head); while (!nodes.isEmpty()){ head = nodes.pop(); System.out.println(head.value); if (head.right != null ){ nodes.push(head.right); } if (head.left != null ){ nodes.push(head.left); } } } public static void in1 (Node head) { if (head == null ){ return ; } in1(head.left); System.out.println(head.value); in1(head.right); } public static void in2 (Node head) { if (head == null ){ return ; } Stack<Node> nodes = new Stack <>(); while (!nodes.isEmpty() || head != null ){ if (head != null ){ nodes.push(head); head = head.left; }else { head = nodes.pop(); System.out.println(head.value); head = head.right; } } } public static void pos1 (Node head) { if (head == null ){ return ; } pos1(head.left); pos1(head.right); System.out.println(head.value); } public static void pos2 (Node head) { if (head == null ){ return ; } Stack<Node> nodes = new Stack <>(); Stack<Node> help = new Stack <>(); nodes.push(head); while (!nodes.isEmpty()){ head = nodes.pop(); help.push(head); if (head.left != null ){ nodes.push(head.left); } if (head.right != null ){ nodes.push(head.right); } } while (!help.isEmpty()){ System.out.println(help.pop().value); } } public static void pos3 (Node head) { if (head == null ){ return ; } Stack<Node> nodes = new Stack <>(); Node cur = null ; nodes.push(head); while (!nodes.isEmpty()){ cur = nodes.peek(); if (cur.left != null && cur.left != head && cur.right != head){ nodes.push(cur.left); }else if (cur.right != null && cur.right != head){ nodes.push(cur.right); }else { System.out.println(nodes.pop().value); head = cur; } } } public static void f (Node head) { if (head == null ){ return ; } System.out.println(head.value); f(head.left); System.out.println(head.value); f(head.right); System.out.println(head.value); } }
按层遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public static void byLayer (Node head) { Queue<Node> nodes = new LinkedList <>(); nodes.add(head); while (!nodes.isEmpty()){ head = nodes.poll(); System.out.println(head.value); if (head.left != null ){ nodes.add(head.left); } if (head.right != null ){ nodes.add(head.right); } } }
最大宽度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 import java.util.HashMap;import java.util.LinkedList;import java.util.Queue;public class MaxWidth { public static class Node { public int value; public Node left; public Node right; public Node (int value) { this .value = value; } } public static int maxWidth1 (Node head) { if (head == null ){ return 0 ; } Queue<Node> nodes = new LinkedList <>(); nodes.add(head); HashMap<Node,Integer> levelMap = new HashMap <>(); levelMap.put(head,1 ); int max = 0 ; int curLevel = 1 ; int curLevelNodes = 0 ; while (!nodes.isEmpty()){ Node cur = nodes.poll(); int curNodeLevel = levelMap.get(cur); if (cur.left != null ){ levelMap.put(cur.left,curNodeLevel + 1 ); nodes.add(cur.left); } if (cur.right != null ){ levelMap.put(cur.right,curNodeLevel + 1 ); nodes.add(cur.right); } if (curNodeLevel == curLevel){ curLevelNodes++; }else { curLevel++; max = Math.max(max,curLevelNodes); curLevelNodes = 1 ; } } return Math.max(max,curLevelNodes); } public static int maxWidth2 (Node head) { if (head == null ){ return 0 ; } Queue<Node> nodes = new LinkedList <>(); nodes.add(head); Node curEnd = head; Node nextEnd = null ; int max = 0 ; int curLevelNodes = 0 ; while (!nodes.isEmpty()){ Node cur = nodes.poll(); if (cur.left != null ){ nodes.add(cur.left); nextEnd = cur.left; } if (cur.right != null ){ nodes.add(cur.right); nextEnd = cur.right; } curLevelNodes++; if (cur == curEnd){ max = Math.max(max,curLevelNodes); curLevelNodes = 0 ; curEnd = nextEnd; } } return max; } }
序列化和反序列化 “#”代表null节点,”!”代表一个值的结束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 import java.util.Arrays;import java.util.LinkedList;import java.util.Queue;import java.util.Stack;public class Serialize { public static class Node { public int value; public Node left; public Node right; public Node (int value) { this .value = value; } } public static String serialize1 (Node head) { if (head == null ){ return "#!" ; } String res = "" ; res += head.value + "!" ; res += serialize1(head.left); res += serialize1(head.right); return res; } public static String serialize2 (Node head) { if (head == null ){ return "#!" ; } Queue<Node> nodes = new LinkedList <>(); nodes.add(head); String res = head.value + "!" ; while (!nodes.isEmpty()){ head = nodes.poll(); if (head.left != null ){ res += head.left.value + "!" ; nodes.add(head.left); }else { res += "#!" ; } if (head.right != null ){ res += head.right.value + "!" ; nodes.add(head.right); }else { res += "#!" ; } } return res; } public static Node preDeserialize (String tree) { String[] values = tree.split("!" ); Queue<String> queue = new LinkedList <>(Arrays.asList(values)); return preGetNode(queue); } public static Node preGetNode (Queue<String> queue) { String value = queue.poll(); if (value.equals("#" )){ return null ; } Node head = new Node (Integer.parseInt(value)); head.left = preGetNode(queue); head.right = preGetNode(queue); return head; } public static Node posDeserialize (String tree) { String[] values = tree.split("!" ); Stack<String> stack = new Stack <>(); for (String value : values) { stack.push(value); } return posGetNode(stack); } public static Node posGetNode (Stack<String> stack) { String value = stack.pop(); if (value.equals("#" )){ return null ; } Node head = new Node (Integer.parseInt(value)); head.right = posGetNode(stack); head.left = posGetNode(stack); return head; } public static Node deserializeByLevel (String tree) { String[] values = tree.split("!" ); int index = 0 ; Node head = getNode(values[index++]); Queue<Node> queue = new LinkedList <>(); if (head != null ){ queue.add(head); } Node cur = null ; while (!queue.isEmpty()){ cur = queue.poll(); cur.left = getNode(values[index++]); cur.right = getNode(values[index++]); if (cur.left != null ){ queue.add(cur.left); } if (cur.right != null ){ queue.add(cur.right); } } return head; } public static Node getNode (String value) { if (value.equals("#" )){ return null ; } return new Node (Integer.parseInt(value)); } }
直观打印二叉树 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class PrintTree { public static class Node { public int value; public Node left; public Node right; public Node (int v) { value = v; } } public static void printTree (Node head) { System.out.println("Binary Tree" ); printInOrder(head,0 ,"H" ,17 ); System.out.println(); } public static void printInOrder (Node head, int height, String to, int len) { if (head == null ){ return ; } printInOrder(head.right, height + 1 , "v" , len ); String val = to + head.value + to; int lenM = val.length(); int lenL = (len - lenM) / 2 ; int lenR = len - lenM - lenL; val = getSpace(lenL) + val + getSpace(lenR); System.out.println(getSpace(height * len) + val); printInOrder(head.left,height + 1 , "^" , len); } public static String getSpace (int num) { StringBuilder res = new StringBuilder ("" ); for (int i = 0 ; i < num; i++){ res.append(" " ); } return res.toString(); } }
后继结点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class SuccessorNode { public static class Node { public int value; public Node left; public Node right; public Node parent; public Node (int v) { value = v; } } public static Node getSuccessorNode (Node node) { if (node == null ){ return null ; } if (node.right != null ){ return getLeftMost(node.right); }else { Node parent = node.parent; while (parent != null && parent.right == node){ node = parent; parent = node.parent; } return parent; } } public static Node getLeftMost (Node node) { if (node == null ){ return null ; } while (node.left != null ){ node = node.left; } return node; } }
折纸问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 public class PaperFolding { public static void printAllFolds (int N) { printProcess(1 ,N,true ); } private static void printProcess (int i, int N, boolean down) { if (i == N){ return ; } printProcess(i + 1 , N, true ); System.out.println(down ? "down" : "up" ); printProcess(i + 1 , N, false ); } }
Morris 遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 public class Morris { static class Node { public int val; public Node left; public Node right; public Node (int v) { val = v; } } public static void morris (Node head) { if (head == null ){ return ; } Node cur = head; Node mostRight = null ; while (cur != null ){ mostRight = cur.left; if (mostRight != null ){ while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right; if (mostRight.right == null ){ mostRight.right = cur; cur = cur.left; continue ; }else { mostRight.right = null ; } } cur = cur.right; } } public static void morrisPre (Node head) { if (head == null ){ return ; } Node cur = head; Node mostRight = null ; while (cur != null ){ mostRight = cur.left; if (mostRight != null ){ while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right; if (mostRight.right == null ){ System.out.println(cur.val); mostRight.right = cur; cur = cur.left; continue ; }else { mostRight.right = null ; } } else { System.out.println(cur.val); } cur = cur.right; } } public static void morrisIn (Node head) { if (head == null ){ return ; } Node cur = head; Node mostRight = null ; while (cur != null ){ mostRight = cur.left; if (mostRight != null ){ while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right; if (mostRight.right == null ){ mostRight.right = cur; cur = cur.left; continue ; }else { mostRight.right = null ; } } System.out.println(cur.val); cur = cur.right; } } public static void morrisPos (Node head) { if (head == null ){ return ; } Node cur = head; Node mostRight = null ; while (cur != null ){ mostRight = cur.left; if (mostRight != null ){ while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right; if (mostRight.right == null ){ mostRight.right = cur; cur = cur.left; continue ; }else { mostRight.right = null ; printRight(cur.left); } } cur = cur.right; } printRight(head); } public static void printRight (Node head) { Node last = reverse(head); Node cur = last; while (cur != null ){ System.out.println(cur.val); cur = cur.right; } reverse(last); } public static Node reverse (Node head) { Node next = null ; Node pre = null ; while (head != null ){ next = head.right; head.right = pre; pre = head; head = next; } return pre; } }
是否为搜索二叉树BST 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public static boolean isBST (Node head) { if (head == null ){ return true ; } Node cur = head; Node mostRight = null ; int preVal = Integer.MIN_VALUE; while (cur != null ){ mostRight = cur.left; if (mostRight != null ){ while (mostRight.right != null && mostRight.right != cur) mostRight = mostRight.right; if (mostRight.right == null ){ mostRight.right = cur; cur = cur.left; continue ; }else { mostRight.right = null ; } } if (cur.val <= preVal){ return false ; } preVal = cur.val; cur = cur.right; } return true ; }
二叉树的递归套路 可以解决面试中绝大多数的二叉树问题尤其是树型dp问题
本质是利用递归遍历二叉树的便利性
假设以X节点为头,假设可以向X左树和X右树要任何信息
在上一步的假设下,讨论以X为头节点的树,得到答案的可能性
列出所有可能性后,确定到底需要向左树和右树要什么样的信息
把左树信息和右树信息求全集,就是任何一棵子树都需要返回的信息S
递归函数都返回S,每一棵子树都这么要求
写代码,在代码中考虑如何吧左树的信息和右树的信息整合出整棵树的信息
平衡二叉树 在一颗二叉树中每一个子树左树与右树的高度差不超过1
思路:
左树是平衡树
右树是平衡树
左树和右树高度差不超过1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class IsBalanced { public static class Info { public boolean isBalanced; public int height; public Info (boolean b,int h) { isBalanced = b; height = h; } } public static class Node { public int value; public Node left; public Node right; public Node (int v) { value = v; } } public static boolean balance (Node head) { return process(head).isBalanced; } public static Info process (Node X) { if (X == null ){ return new Info (true ,0 ); } Info leftInfo = process(X.left); Info rightInfo = process(X.right); int height = 1 + Math.max(leftInfo.height, rightInfo.height); boolean balance = leftInfo.isBalanced && rightInfo.isBalanced && Math.abs(leftInfo.height - rightInfo.height) <= 1 ; return new Info (balance,height); } }
节点最大距离 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class MaxDistance { public static class Info { public int max; public int height; public Info (int m,int h) { max = m; height = h; } } public static class Node { public int value; public Node left; public Node right; public Node (int v) { value = v; } } public static int maxDistance (Node head) { return process(head).max; } public static Info process (Node X) { if (X == null ){ return new Info (0 ,0 ); } Info leftInfo = process(X.left); Info rightInfo = process(X.right); int max = Math.max(Math.max(leftInfo.max, rightInfo.max), leftInfo.height + rightInfo.height + 1 ); int height = Math.max(leftInfo.height, rightInfo.height) + 1 ; return new Info (max,height); } }
最大二叉搜索子树 搜索二叉树BST:没有重复值的二叉树,任意节点的左树上每个节点的值比自己小,右树上每个节点的值比自己大
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public class MaxSubBST { public static class Node { public int value; public Node left; public Node right; public Node (int v) { value = v; } } public static class Info { public boolean isBST; public int maxSubBSTSize; public int max; public int min; public Info (boolean is,int size, int mi,int ma) { isBST = is; maxSubBSTSize = size; min = mi; max = ma; } } public static Info process (Node X) { if (X == null ){ return null ; } Info leftInfo = process(X.left); Info rightInfo = process(X.right); int max = X.value; int min = X.value; if (leftInfo != null ){ min = Math.min(min, leftInfo.min); max = Math.max(max, leftInfo.max); } if (rightInfo != null ){ min = Math.min(min, rightInfo.min); max = Math.max(max, rightInfo.max); } int maxSubBSTSize = 0 ; if (leftInfo != null ){ maxSubBSTSize = leftInfo.maxSubBSTSize; } if (rightInfo != null ){ maxSubBSTSize = Math.max(rightInfo.maxSubBSTSize,maxSubBSTSize); } boolean isBST = false ; if ( (leftInfo == null ? true : leftInfo.isBST) && (rightInfo == null ? true : rightInfo.isBST) && (leftInfo == null ? true : leftInfo.max < X.value) && (rightInfo == null ? true : rightInfo.min > X.value) ){ maxSubBSTSize = (leftInfo == null ? 0 : leftInfo.maxSubBSTSize) + (rightInfo == null ? 0 : rightInfo.maxSubBSTSize) + 1 ; isBST = true ; } return new Info (isBST,maxSubBSTSize,min,max); } }
派对的最大快乐值 公司里每个员工对于若干下级和唯一上级,每个员工都有一个快乐值
派对发请柬,被发到的人的下级一定不会来参加派对
求参加派对的员工的快乐值之和的最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 import java.util.ArrayList;import java.util.List;public class MaxHappy { public static class Employee { public int happy; public List<Employee> nexts; public Employee (int h) { happy = h; nexts = new ArrayList <>(); } } public static class Info { public int yes; public int no; public Info (int y, int n) { yes = y; no = n; } } public static int maxHappy (Employee boss) { Info res = process(boss); return Math.max(res.yes,res.no); } public static Info process (Employee X) { if (X.nexts.isEmpty()){ return new Info (X.happy,0 ); } int yes = X.happy; int no = 0 ; for (Employee next : X.nexts) { Info nextInfo = process(next); yes += nextInfo.no; no += Math.max(nextInfo.yes,nextInfo.no); } return new Info (yes,no); } }
贪心算法 思路就是每一步都选最优解,整体就是最优解
贪心问题没有固定套路,比较考验数学能力
贪心策略往往是类似于自然智慧的,你只能靠举反例来证明它是错的,但你很难证明它是对的
对于贪心算法的学习主要以增加阅历和经验为主
图 Node 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.util.ArrayList;public class Node { public int value; public int in; public int out; public ArrayList<Node> nexts; public ArrayList<Edge> edges; public Node (int v) { value = v; in = 0 ; out = 0 ; nexts = new ArrayList <>(); edges = new ArrayList <>(); } }
Edge 1 2 3 4 5 6 7 8 9 10 11 public class Edge { public int weight; public Node from; public Node to; public Edge (int weight, Node from, Node to) { this .weight = weight; this .from = from; this .to = to; } }
Graph 1 2 3 4 5 6 7 8 9 10 11 import java.util.HashMap;import java.util.HashSet;public class Graph { public HashMap<Integer, Node> nodes; public HashSet<Edge> edges; public Graph () { nodes = new HashMap <>(); edges = new HashSet <>(); } }
转换器CreateGraph 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class CreateGraph { public void createGraph (int [][] arr) { Graph graph = new Graph (); for (int i = 0 ; i < arr.length; i++){ int weight = arr[i][0 ]; Integer from = arr[i][1 ]; Integer to = arr[i][2 ]; if (!graph.nodes.containsKey(from)){ graph.nodes.put(from,new Node (from)); } if (!graph.nodes.containsKey(to)){ graph.nodes.put(to,new Node (to)); } Node fromNode = graph.nodes.get(from); Node toNode = graph.nodes.get(to); Edge newEdge = new Edge (weight,fromNode,toNode); fromNode.nexts.add(toNode); fromNode.out++; toNode.in++; fromNode.edges.add(newEdge); graph.edges.add(newEdge); } } }
广度优先遍历BFS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.util.HashSet;import java.util.LinkedList;import java.util.Queue;public class BFS { public static void bfs (Node node) { if (node == null ){ return ; } Queue<Node> queue = new LinkedList <>(); HashSet<Node> set = new HashSet <>(); queue.add(node); set.add(node); while (!queue.isEmpty()){ Node cur = queue.poll(); System.out.println(cur.value); for (Node next : node.nexts){ if (!set.contains(next)){ set.add(next); queue.add(next); } } } } }
深度优先遍历DFS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import java.util.HashSet;import java.util.Stack;public class DFS { public static void dfs (Node node) { if (node == null ){ return ; } Stack<Node> stack = new Stack <>(); HashSet<Node> set = new HashSet <>(); stack.add(node); set.add(node); System.out.println(node.value); while (!stack.isEmpty()){ Node cur = stack.pop(); for (Node next : node.nexts){ if (!set.contains(next)){ stack.push(cur); stack.push(next); set.add(next); System.out.println(next.value); break ; } } } } }
拓扑排序 有向无环图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import java.util.*;public class TopologySort { public static List<Node> topologySort (Graph graph) { HashMap<Node,Integer> inMap = new HashMap <>(); Queue<Node> zeroInQueue = new LinkedList <>(); for (Node node : graph.nodes.values()){ inMap.put(node,node.in); if (node.in == 0 ){ zeroInQueue.add(node); } } List<Node> result = new ArrayList <>(); while (!zeroInQueue.isEmpty()){ Node cur = zeroInQueue.poll(); result.add(cur); for (Node next : cur.nexts){ inMap.put(next,inMap.get(next) - 1 ); if (inMap.get(next) == 0 ){ zeroInQueue.add(next); } } } return result; } }
最小生成树MST Kruskal算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 import java.util.*;public class Kruskal { public static class UnionFind { public HashMap<Node,Node> fatherMap; public HashMap<Node,Integer> sizeMap; public UnionFind () { fatherMap = new HashMap <>(); sizeMap = new HashMap <>(); } public void makeSets (Collection<Node> nodes) { fatherMap.clear(); sizeMap.clear(); for (Node node : nodes){ fatherMap.put(node,node); sizeMap.put(node, 1 ); } } private Node findFather (Node n) { Stack<Node> path = new Stack <>(); while (n != fatherMap.get(n)){ path.add(n); n = fatherMap.get(n); } while (!path.isEmpty()){ fatherMap.put(path.pop(),n); } return n; } public boolean isSameSet (Node x, Node y) { return findFather(x) == findFather(y); } public void union (Node x, Node y) { if (x == null || y == null ){ return ; } Node xHead = findFather(x); Node yHead = findFather(y); if (xHead != yHead){ int xSetSize = sizeMap.get(xHead); int ySetSize = sizeMap.get(yHead); if (xSetSize >= ySetSize){ fatherMap.put(yHead,xHead); sizeMap.put(xHead, xSetSize + ySetSize); sizeMap.remove(yHead); }else { fatherMap.put(xHead, yHead); sizeMap.put(yHead, xSetSize + ySetSize); sizeMap.remove(xHead); } } } } public static class EdgeComparator implements Comparator <Edge> { @Override public int compare (Edge o1, Edge o2) { return o1.weight - o2.weight; } } public static Set<Edge> kruskalMST (Graph graph) { UnionFind unionFind = new UnionFind (); unionFind.makeSets(graph.nodes.values()); PriorityQueue<Edge> priorityQueue = new PriorityQueue <>(new EdgeComparator ()); priorityQueue.addAll(graph.edges); Set<Edge> result = new HashSet <>(); while (!priorityQueue.isEmpty()){ Edge edge = priorityQueue.poll(); if (!unionFind.isSameSet(edge.from, edge.to)){ result.add(edge); unionFind.union(edge.from, edge.to); } } return result; } }
Prim算法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.*;public class Prim { public static class EdgeComparator implements Comparator <Edge> { @Override public int compare (Edge o1, Edge o2) { return o1.weight - o2.weight; } } public static Set<Edge> primMST (Graph graph) { PriorityQueue<Edge> priorityQueue = new PriorityQueue <>(new EdgeComparator ()); HashSet<Node> nodeSet = new HashSet <>(); HashSet<Edge> edgeSet = new HashSet <>(); Set<Edge> result = new HashSet <>(); for (Node node : graph.nodes.values()){ if (!nodeSet.contains(node)) { nodeSet.add(node); for (Edge edge : node.edges) { if (!edgeSet.contains(edge)) { edgeSet.add(edge); priorityQueue.add(edge); } } while (!priorityQueue.isEmpty()){ Edge edge = priorityQueue.poll(); Node toNode = edge.to; if (!nodeSet.contains(toNode)){ nodeSet.add(toNode); result.add(edge); for (Edge nextEdge : toNode.edges) { if (!edgeSet.contains(nextEdge)){ edgeSet.add(nextEdge); priorityQueue.add(nextEdge); } } } } } } return result; } }
Dijkstra dijkstra 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import java.util.HashMap;import java.util.HashSet;import java.util.Map;public class Dijkstra { public static HashMap<Node,Integer> dijkstra1 (Node from) { HashMap<Node,Integer> distanceMap = new HashMap <>(); distanceMap.put(from,0 ); HashSet<Node> selectedNodes = new HashSet <>(); Node minNode = getMinDistanceAndUnselectedNode(distanceMap,selectedNodes); while (minNode != null ) { int distance = distanceMap.get(minNode); for (Edge edge : minNode.edges){ Node toNode = edge.to; if (!distanceMap.containsKey(toNode)){ distanceMap.put(toNode,distance + edge.weight); }else { distanceMap.put(edge.to,Math.min(distanceMap.get(toNode),distance)); } } selectedNodes.add(minNode); minNode = getMinDistanceAndUnselectedNode(distanceMap,selectedNodes); } return distanceMap; } private static Node getMinDistanceAndUnselectedNode (HashMap<Node, Integer> distanceMap, HashSet<Node> selectedNodes) { Node minNode = null ; int minDistance = Integer.MAX_VALUE; for (Map.Entry<Node,Integer> entry : distanceMap.entrySet()){ Node node = entry.getKey(); int distance = entry.getValue(); if (!selectedNodes.contains(node) && distance < minDistance) { minNode = node; minDistance = distance; } } return minNode; } }
dijkstraPlus 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 import java.util.HashMap;public class DijkstraPlus { public static class NodeRecord { public Node node; public int distance; public NodeRecord (Node node ,int distance) { this .node = node; this .distance = distance; } } public static class NodeHeap { private Node[] nodes; private HashMap<Node,Integer> heapIndexMap; private HashMap<Node,Integer> distanceMap; private int size; public NodeHeap (int size) { nodes = new Node [size]; heapIndexMap = new HashMap <>(); distanceMap = new HashMap <>(); size = 0 ; } public boolean isEmpty () { return size == 0 ; } private boolean isEntered (Node node) { return heapIndexMap.containsKey(node); } private boolean inHeap (Node node) { return isEntered(node) && heapIndexMap.get(node) != -1 ; } private void swap (int index1,int index2) { heapIndexMap.put(nodes[index1],index2); heapIndexMap.put(nodes[index2],index1); Node tmp = nodes[index1]; nodes[index1] = nodes[index2]; nodes[index2] = tmp; } private void insertHeapify (Node node, int index) { while (distanceMap.get(nodes[index]) < distanceMap.get(nodes[(index - 1 ) / 2 ])){ swap(index,(index-1 )/2 ); index = (index - 1 )/2 ; } } private void heapify (int index, int size) { int left = index * 2 + 1 ; while (left < size) { int smallest = left + 1 < size && distanceMap.get(nodes[left + 1 ]) < distanceMap.get(nodes[left]) ? left + 1 : left; smallest = distanceMap.get(nodes[smallest]) < distanceMap.get(nodes[index]) ? smallest : index; if (smallest == index) { break ; } swap(smallest,index); index = smallest; left = index * 2 + 1 ; } } public void addOrUpdateOrIgnore (Node node,int distance) { if (inHeap(node)){ distanceMap.put(node, Math.min(distanceMap.get(node),distance)); insertHeapify(node, heapIndexMap.get(node)); } if (!isEntered(node)){ nodes[size] = node; heapIndexMap.put(node,size); distanceMap.put(node,distance); insertHeapify(node,size++); } } public NodeRecord pop () { NodeRecord nodeRecord = new NodeRecord (nodes[0 ],distanceMap.get(nodes[0 ])); swap(0 ,size -1 ); heapIndexMap.put(nodes[size - 1 ], -1 ); distanceMap.remove(nodes[size - 1 ]); nodes[size - 1 ] = null ; heapify(0 , --size); return nodeRecord; } } public static HashMap<Node,Integer> dijkstra2 (Node head,int size) { NodeHeap nodeHeap = new NodeHeap (size); nodeHeap.addOrUpdateOrIgnore(head,0 ); HashMap<Node,Integer> result = new HashMap <>(); while (!nodeHeap.isEmpty()){ NodeRecord record = nodeHeap.pop(); Node cur = record.node; int distance = record.distance; for (Edge edge : cur.edges) { nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight + distance); } result.put(cur,distance); } return result; } }
其他 打表技巧 强迫症买苹果 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public class MinBags { public static int minBags (int N) { int times = N / 8 ; while (times >= 0 ){ if ((N - times * 8 ) % 6 == 0 ){ return times + (N - times * 8 ) / 6 ; } times--; } return -1 ; } public static int minBagsAwesome (int N) { if ((N & 1 ) != 0 ){ return -1 ; } if (N < 18 ){ return N == 0 ? 0 : ( N == 6 || N == 8 )? 1 : ( N == 12 || N == 14 || N == 16 ) ? 2 : -1 ; } return (N - 18 ) / 8 + 3 ; } public static void main (String[] args) { for ( int i = 0 ; i <= 100 ; i++){ System.out.println( i + " : " + minBags(i) ); } } }
谁会赢 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class Graze { public static boolean winner1 (int N) { if (N <=5 ){ return N != 2 && N != 5 ; } int base = 1 ; while (base <= N){ if (!winner1(N - base)){ return true ; } if (base > N/4 ){ break ; } base *= 4 ; } return false ; } public static boolean winner2 (int N) { return N % 5 != 2 && N % 5 != 0 ; } public static void main (String[] args) { for (int i = 1 ; i <= 50 ; i ++){ System.out.println(i + " : " + winner2(i)); } } }
连续正数和的数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class ContinuousPositiveSum { public static boolean ifContinuousPositiveSum1 (int n) { for (int i = 1 ; i < n; i++){ int sum = 0 ; for (int j = i;sum < n; j ++){ sum += j; if (sum == n){ return true ; } } } return false ; } public static boolean ifContinuousPositiveSum2 (int n) { return n != 1 && n % 2 != 0 ; } public static void main (String[] args) { for (int i = 1 ; i <= 50 ; i ++){ System.out.println(i + " : " + ifContinuousPositiveSum1(i)); } } }
并查集 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import java.util.HashMap;import java.util.List;import java.util.Stack;public class DisjointSet { public static class Node <V> { V value; public Node (V v) { value = v; } } public static class UnionSet <V> { public HashMap<V, Node<V>> nodes; public HashMap<Node<V>, Node<V>> parents; public HashMap<Node<V>, Integer> sizeMap; public UnionSet (List<V> values) { for (V value : values){ Node<V> node = new Node <>(value); nodes.put(value, node); parents.put(node, node); sizeMap.put(node, 1 ); } } public Node<V> findFather (Node<V> cur) { Stack<Node<V>> path = new Stack <>(); while (cur != parents.get(cur)) { path.push(cur); cur = parents.get(cur); } while (!path.isEmpty()){ parents.put(path.pop(),cur); } return cur; } public boolean isSameSet (V x, V y) { if (!nodes.containsKey(x) || !nodes.containsKey(y)){ return false ; } return findFather(nodes.get(x)) == findFather(nodes.get(y)); } public void union (V x, V y) { if (!nodes.containsKey(x) || !nodes.containsKey(y)){ return ; } Node<V> xHead = findFather(nodes.get(x)); Node<V> yHead = findFather(nodes.get(y)); if (xHead != yHead){ int xSetSize = sizeMap.get(xHead); int ySetSize = sizeMap.get(yHead); if (xSetSize >= ySetSize){ parents.put(yHead,xHead); sizeMap.put(xHead, xSetSize + ySetSize); sizeMap.remove(yHead); }else { parents.put(xHead,yHead); sizeMap.put(yHead, xSetSize + ySetSize); sizeMap.remove(xHead); } } } } }
调整概率 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class Adjust { public static double random (int k) { double max = 0 ; while (k > 0 ){ double a = Math.random(); if (max < a) { max = a; } k--; } return max; } public static void main (String[] args) { int testTime = 1000000 ; double x = 0.6 ; int count = 0 ; int k = 2 ; for (int i = 0 ; i < testTime; i++){ if (random(k) < x){ count++; } } System.out.println((double )count / (double ) testTime); } }
丑数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 public class UglyNumber { public boolean isUgly (int n) { if (n <= 0 ){ return false ; } while (n != 1 ){ if (n / 5 * 5 == n){ n /= 5 ; } else if (n / 3 * 3 == n){ n /= 3 ; } else if (n / 2 * 2 == n){ n >>= 1 ; } else { break ; } } return n == 1 ; } public int nthUglyNumber (int n) { int [] ans = new int [n]; ans[0 ] = 1 ; int i2 = 0 ; int i3 = 0 ; int i5 = 0 ; for (int i = 1 ; i < n; i++){ ans[i] = Math.min(ans[i2] * 2 , Math.min(ans[i3] * 3 , ans[i5] * 5 )); if (ans[i] % 2 == 0 ){ i2++; } if (ans[i] % 3 == 0 ){ i3++; } if (ans[i] % 5 == 0 ){ i5++; } } return ans[n - 1 ]; } public int nthUglyNumber (int n, int a, int b, int c) { long ans = 0 ; long l = 0 , r = (long ) Math.min(a, Math.min(b, c)) * n; long ab = this .lcm(a, b); long ac = this .lcm(a, c); long bc = this .lcm(b, c); long abc = this .lcm(b, ac); while (l <= r) { long m = l + ((r - l) >> 1 ); long N = m / a + m / b + m / c - m / ab - m / ac - m / bc + m / abc; if (N < n) { l = m + 1 ; ans = l; } else { r = m - 1 ; } } return (int ) ans; } private long gcd (long a, long b) { return b == 0 ? a : gcd(b, a % b); } private long lcm (long a, long b) { return a * b / gcd(a, b); } public int nthSuperUglyNumber (int n, int [] primes) { int [] p = new int [primes.length]; int [] ans = new int [n]; ans[0 ] = 1 ; int curr = 1 ; while (curr < n){ int next = Integer.MAX_VALUE; int nextIdx = 0 ; for (int i=0 ; i<primes.length; ++i){ int tmp = primes[i]*ans[p[i]]; if (tmp > ans[curr-1 ] && tmp < next){ next = tmp; nextIdx = i; } } ans[curr] = next; ++curr; for (int i=0 ; i<primes.length; ++i){ if (next == primes[i]*ans[p[i]]) ++p[i]; } } return ans[n-1 ]; } }
跳表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 class Skiplist { static final int MAX_LEVEL = 32 ; static final double P_FACTOR = 0.25 ; private SkiplistNode head; private int level; private Random random; public Skiplist () { this .head = new SkiplistNode (-1 , MAX_LEVEL); this .level = 0 ; this .random = new Random (); } public boolean search (int target) { SkiplistNode curr = this .head; for (int i = level - 1 ; i >= 0 ; i--) { while (curr.forward[i] != null && curr.forward[i].val < target) { curr = curr.forward[i]; } } curr = curr.forward[0 ]; if (curr != null && curr.val == target) { return true ; } return false ; } public void add (int num) { SkiplistNode[] update = new SkiplistNode [MAX_LEVEL]; Arrays.fill(update, head); SkiplistNode curr = this .head; for (int i = level - 1 ; i >= 0 ; i--) { while (curr.forward[i] != null && curr.forward[i].val < num) { curr = curr.forward[i]; } update[i] = curr; } int lv = randomLevel(); level = Math.max(level, lv); SkiplistNode newNode = new SkiplistNode (num, lv); for (int i = 0 ; i < lv; i++) { newNode.forward[i] = update[i].forward[i]; update[i].forward[i] = newNode; } } public boolean erase (int num) { SkiplistNode[] update = new SkiplistNode [MAX_LEVEL]; SkiplistNode curr = this .head; for (int i = level - 1 ; i >= 0 ; i--) { while (curr.forward[i] != null && curr.forward[i].val < num) { curr = curr.forward[i]; } update[i] = curr; } curr = curr.forward[0 ]; if (curr == null || curr.val != num) { return false ; } for (int i = 0 ; i < level; i++) { if (update[i].forward[i] != curr) { break ; } update[i].forward[i] = curr.forward[i]; } while (level > 1 && head.forward[level - 1 ] == null ) { level--; } return true ; } private int randomLevel () { int lv = 1 ; while (random.nextDouble() < P_FACTOR && lv < MAX_LEVEL) { lv++; } return lv; } } class SkiplistNode { int val; SkiplistNode[] forward; public SkiplistNode (int val, int maxLevel) { this .val = val; this .forward = new SkiplistNode [maxLevel]; } }