├── .gitignore ├── Top100.md ├── TopInterview.md ├── code ├── lc1.java ├── lc10.java ├── lc100.java ├── lc101.java ├── lc102.java ├── lc1025.java ├── lc1026.java ├── lc1027.java ├── lc1028.java ├── lc103.java ├── lc104.java ├── lc105.java ├── lc108.java ├── lc1093.java ├── lc1094.java ├── lc11.java ├── lc112.java ├── lc113.java ├── lc114.java ├── lc116.java ├── lc118.java ├── lc119.java ├── lc120.java ├── lc121.java ├── lc122.java ├── lc123.java ├── lc124.java ├── lc125.java ├── lc127.java ├── lc128.java ├── lc129.java ├── lc13.java ├── lc130.java ├── lc131.java ├── lc132.java ├── lc134.java ├── lc136.java ├── lc138.java ├── lc139.java ├── lc14.java ├── lc140.java ├── lc141.java ├── lc142.java ├── lc144.java ├── lc145.java ├── lc146.java ├── lc148.java ├── lc149.java ├── lc15.java ├── lc150.java ├── lc151.java ├── lc152.java ├── lc153.java ├── lc155.java ├── lc16.java ├── lc160.java ├── lc162.java ├── lc166.java ├── lc169.java ├── lc17.java ├── lc171.java ├── lc172.java ├── lc179.java ├── lc188.java ├── lc189.java ├── lc19.java ├── lc190.java ├── lc191.java ├── lc198.java ├── lc199.java ├── lc2.java ├── lc20.java ├── lc200.java ├── lc202.java ├── lc204.java ├── lc206.java ├── lc207.java ├── lc208.java ├── lc21.java ├── lc210.java ├── lc212.java ├── lc213.java ├── lc215.java ├── lc217.java ├── lc218.java ├── lc22.java ├── lc221.java ├── lc226.java ├── lc227.java ├── lc23.java ├── lc230.java ├── lc234.java ├── lc236.java ├── lc237.java ├── lc238.java ├── lc239.java ├── lc24.java ├── lc240.java ├── lc242.java ├── lc25.java ├── lc26.java ├── lc263.java ├── lc264.java ├── lc268.java ├── lc27.java ├── lc279.java ├── lc28.java ├── lc283.java ├── lc287.java ├── lc289.java ├── lc29.java ├── lc295.java ├── lc297.java ├── lc3.java ├── lc300.java ├── lc301.java ├── lc303.java ├── lc309.java ├── lc31.java ├── lc312.java ├── lc315.java ├── lc32.java ├── lc322.java ├── lc324.java ├── lc326.java ├── lc328.java ├── lc329.java ├── lc33.java ├── lc334.java ├── lc337.java ├── lc338.java ├── lc34.java ├── lc341.java ├── lc343.java ├── lc344.java ├── lc347.java ├── lc35.java ├── lc350.java ├── lc36.java ├── lc371.java ├── lc378.java ├── lc38.java ├── lc380.java ├── lc384.java ├── lc387.java ├── lc39.java ├── lc394.java ├── lc395.java ├── lc4.java ├── lc406.java ├── lc41.java ├── lc412.java ├── lc416.java ├── lc42.java ├── lc43.java ├── lc437.java ├── lc438.java ├── lc44.java ├── lc448.java ├── lc454.java ├── lc46.java ├── lc461.java ├── lc48.java ├── lc49.java ├── lc493.java ├── lc494.java ├── lc5.java ├── lc50.java ├── lc51.java ├── lc52.java ├── lc53.java ├── lc538.java ├── lc54.java ├── lc542.java ├── lc543.java ├── lc55.java ├── lc559.java ├── lc56.java ├── lc560.java ├── lc572.java ├── lc58.java ├── lc581.java ├── lc589.java ├── lc590.java ├── lc617.java ├── lc62.java ├── lc621.java ├── lc63.java ├── lc64.java ├── lc647.java ├── lc66.java ├── lc673.java ├── lc685.java ├── lc69.java ├── lc7.java ├── lc70.java ├── lc714.java ├── lc72.java ├── lc73.java ├── lc746.java ├── lc75.java ├── lc76.java ├── lc771.java ├── lc78.java ├── lc79.java ├── lc8.java ├── lc81.java ├── lc83.java ├── lc834.java ├── lc84.java ├── lc85.java ├── lc87.java ├── lc877.java ├── lc88.java ├── lc9.java ├── lc91.java ├── lc912.java ├── lc921.java ├── lc922.java ├── lc923.java ├── lc94.java ├── lc940 java ├── lc95.java ├── lc96.java ├── lc968.java ├── lc97.java ├── lc978.java ├── lc98.java ├── lc983.java └── lc99.java └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | */.DS_Store 3 | kickstart/* 4 | test.java 5 | interview/* 6 | -------------------------------------------------------------------------------- /code/lc1.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 1. Two Sum 4 | * 题意:返回数组中和为给定数的下标 5 | * 难度:Easy 6 | * 分类:Array, HashTable 7 | * 算法:题目说明了数组中一定有解,且解唯一,所以用哈希表记录已遍历的元素即可 8 | */ 9 | 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class lc1 { 14 | public static void main(String[] args) { 15 | int[] nums = {2, 7, 11, 15}; 16 | int target = 9; 17 | 18 | int[] r = twoSum(nums,target); 19 | System.out.println(r[0]); 20 | System.out.println(r[1]); 21 | } 22 | 23 | public static int[] twoSum(int[] nums, int target) { 24 | Map map = new HashMap(); 25 | int[] result = new int[2]; 26 | for (int i = 0; i 1 && dp[0][i-2]) 22 | dp[0][i] = true; 23 | } 24 | for (int i = 1; i < s.length()+1 ; i++) { 25 | for (int j = 1; j < p.length()+1 ; j++) { 26 | if(s.charAt(i-1)==p.charAt(j-1) || p.charAt(j-1)=='.') 27 | dp[i][j] = dp[i-1][j-1]; 28 | if (p.charAt(j-1)=='*') { 29 | if(s.charAt(i-1)!=p.charAt(j-2) && p.charAt(j-2)!='.'){ 30 | //判断s最后一位与 * 前一位是否匹配,若不匹配,则 char* 匹配空,*表示前边字符出现0次 31 | dp[i][j] = dp[i][j-2]; 32 | }else{ 33 | dp[i][j] = (dp[i-1][j] || dp[i-1][j-1] || dp[i][j-2]); 34 | //dp[i-1][j] * 表示前面字符出现多次 35 | //dp[i-1][j-1] * 表示前面字符出现一次 dp[i]dp[j-1]也行 36 | // dp[i][j-2] *表示前边字符出现0次,覆盖这些情况. s="ba" p="baa*"; s="a" p="ab*a*" 37 | } 38 | } 39 | } 40 | } 41 | return dp[s.length()][p.length()]; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc100.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 100. Same Tree 4 | * 题意:判断两棵树是否一样 5 | * 难度:Easy 6 | * 分类: 7 | * 思路: 8 | * Tips: 9 | */ 10 | public class lc100 { 11 | public class TreeNode { 12 | int val; 13 | TreeNode left; 14 | TreeNode right; 15 | TreeNode(int x) { 16 | val = x; 17 | } 18 | } 19 | public boolean isSameTree(TreeNode p, TreeNode q) { 20 | if(p==null&&q==null) return true; 21 | if( (p==null&&q!=null)||(q==null&&p!=null) ) return false; 22 | if(p.val!=q.val) return false; 23 | return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/lc101.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 101. Symmetric Tree 4 | * 题意:判断二叉树是否对称 5 | * 难度:Easy 6 | * 分类:Tree, DFS, BFS 7 | * Tips:递归与非递归两种方法 8 | * 注意:题目规定是二叉树,递归方法 left.left与right.right, left.right与right.left 进行比较 9 | */ 10 | import java.util.Stack; 11 | 12 | public class lc101 { 13 | public class TreeNode { 14 | int val; 15 | TreeNode left; 16 | TreeNode right; 17 | TreeNode(int x) { val = x; } 18 | } 19 | 20 | public boolean isSymmetric(TreeNode root) { 21 | //非递归方法 22 | if(root==null) 23 | return true; 24 | 25 | Stack s = new Stack(); 26 | s.push(root.left); 27 | s.push(root.right); 28 | while(!s.isEmpty()){ 29 | TreeNode tn1 = s.pop(), tn2 = s.pop(); 30 | if(tn1==null||tn2==null) 31 | if(tn1 == tn2) //都为空 32 | continue; 33 | else 34 | return false; 35 | if(tn1.val!=tn2.val) 36 | return false; 37 | s.push(tn1.left); 38 | s.push(tn2.right); 39 | s.push(tn1.right); 40 | s.push(tn2.left); 41 | } 42 | return true; 43 | } 44 | 45 | // 递归法 46 | public boolean isSymmetric2(TreeNode root) { 47 | return root==null || func(root.left, root.right); 48 | } 49 | 50 | public static boolean func(TreeNode left, TreeNode right){ 51 | if(left==null || right==null) 52 | return left == right; 53 | return (left.val==right.val) && func(left.left,right.right) && func(left.right,right.left); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /code/lc102.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 102. Binary Tree Level Order Traversal 4 | * 题意:二叉树层次遍历 5 | * 难度:Medium 6 | * 分类:Tree, Breadth-first Search 7 | * 思路:用一个队列 8 | * Tips:如何判断遍历完一层了?pop的时候先看下size 9 | */ 10 | import java.util.*; 11 | 12 | public class lc102 { 13 | public class TreeNode { 14 | int val; 15 | TreeNode left; 16 | TreeNode right; 17 | TreeNode(int x) { val = x; } 18 | } 19 | 20 | public List> levelOrder(TreeNode root) { 21 | Queue qu = new LinkedList<>(); 22 | List> res = new ArrayList<>(); 23 | if(root==null) 24 | return res; 25 | qu.add(root); 26 | while(!qu.isEmpty()){ //两个while 27 | int size = qu.size(); 28 | List temp = new ArrayList<>(); 29 | while(size>0){ 30 | TreeNode tn = qu.remove(); 31 | if(tn!=null) { 32 | if(tn.left!=null) 33 | qu.add(tn.left); 34 | if(tn.right!=null) 35 | qu.add(tn.right); 36 | } 37 | temp.add(tn.val); 38 | size--; 39 | } 40 | res.add(temp); 41 | } 42 | return res; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/lc1025.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 1025. Divisor Game 4 | * 题意: 5 | * 难度: 6 | * 分类: 7 | * 思路:先选的有主动权 8 | * Tips: 9 | */ 10 | public class lc1025 { 11 | public boolean divisorGame(int N) { 12 | if(N%2==0) return true; 13 | return false; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/lc1027.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 1027. Longest Arithmetic Sequence 4 | * 题意:最长等差数列 5 | * 难度:Medium 6 | * 分类:Dynamic Programming 7 | * 思路:还是要在每个位置上都记录一下,不是说一个大的数组就可以了。因为相同长度的等差,后续数字往上接的时候不一定接哪一个,都要保存,并不是说一定去接小的那个。 8 | * 二维dp, 一维记录位置,一维记录差分 9 | * Tips:很棒的题 10 | */ 11 | public class lc1027 { 12 | public static int longestArithSeqLength(int[] A) { 13 | int res = 0; 14 | int[][] dp = new int[A.length][20000]; 15 | for (int i = 0; i < A.length ; i++) { 16 | for (int j = 0; j < i ; j++) { 17 | int ind = A[i]-A[j]+10000; //可能是负数,做一个偏移 18 | dp[i][ind] = dp[j][ind] + 1; 19 | res = Math.max(res, dp[i][ind]); 20 | } 21 | } 22 | return res+1; //加1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/lc1028.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Stack; 4 | /* 5 | * 1028. Recover a Tree From Preorder Traversal 6 | * 题意:从先序遍历恢复二叉树 7 | * 难度:Hard 8 | * 分类:Depth-first Search 9 | * 思路:用栈存储,迭代比较就可以了 10 | * Tips: 11 | */ 12 | public class lc1028 { 13 | public class TreeNode { 14 | int val; 15 | TreeNode left; 16 | TreeNode right; 17 | TreeNode(int x) { 18 | val = x; 19 | } 20 | } 21 | public TreeNode recoverFromPreorder(String S) { 22 | int level, val; 23 | Stack stack = new Stack<>(); 24 | for (int i = 0; i < S.length();) { 25 | for (level = 0; S.charAt(i) == '-'; i++) { 26 | level++; 27 | } 28 | for (val = 0; i < S.length() && S.charAt(i) != '-'; i++) { //数字可能是大于9 29 | val = val * 10 + (S.charAt(i) - '0'); 30 | } 31 | while (stack.size() > level) { //用stack的size和depth比就可以了 32 | stack.pop(); 33 | } 34 | TreeNode node = new TreeNode(val); 35 | if (!stack.isEmpty()) { 36 | if (stack.peek().left == null) { 37 | stack.peek().left = node; 38 | } else { 39 | stack.peek().right = node; 40 | } 41 | } 42 | stack.add(node); 43 | } 44 | while (stack.size() > 1) { 45 | stack.pop(); 46 | } 47 | return stack.pop(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/lc103.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 103. Binary Tree Zigzag Level Order Traversal 4 | * 题意:蛇形层次遍历 5 | * 难度:Medium 6 | * 分类:Stack, Tree, Breadth-first Search 7 | * 思路:层次遍历,加了个flag每次是在list头添加或尾添加 8 | * Tips:Bingo! 9 | */ 10 | import java.util.ArrayDeque; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Queue; 14 | 15 | public class lc103 { 16 | 17 | public class TreeNode { 18 | int val; 19 | TreeNode left; 20 | TreeNode right; 21 | TreeNode(int x) { val = x; } 22 | } 23 | 24 | public List> zigzagLevelOrder(TreeNode root) { 25 | List> res = new ArrayList<>(); 26 | if(root==null) return res; 27 | Queue q = new ArrayDeque(); 28 | q.add(root); 29 | boolean flag = true; 30 | while(!q.isEmpty()){ 31 | int size = q.size(); 32 | List ls = new ArrayList<>(); 33 | while(size>0){ 34 | TreeNode temp = q.remove(); 35 | if(flag) ls.add(temp.val); 36 | else ls.add(0,temp.val); //在头部添加 37 | if(temp.left!=null) q.add(temp.left); 38 | if(temp.right!=null) q.add(temp.right); 39 | size--; 40 | } 41 | res.add(ls); 42 | flag = !flag; 43 | } 44 | return res; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /code/lc104.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayDeque; 4 | import java.util.Queue; 5 | 6 | /* 7 | * 104. Maximum Depth of Binary Tree 8 | * 题意:二叉树最大深度 9 | * 难度:Easy 10 | * 分类:Tree, Depth-first Search 11 | * 思路:深度优先搜索,递归实现。非递归BFS,相当于层序遍历。 12 | * Tips: 13 | */ 14 | public class lc104 { 15 | public class TreeNode { 16 | int val; 17 | TreeNode left; 18 | TreeNode right; 19 | TreeNode(int x) { val = x; } 20 | } 21 | public int maxDepth(TreeNode root) { 22 | if(root==null) return 0; 23 | return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1; 24 | } 25 | 26 | public int maxDepth2(TreeNode root) { 27 | if(root==null) return 0; 28 | Queue q = new ArrayDeque<>(); 29 | q.add(root); 30 | int depth = 0; 31 | while(!q.isEmpty()){ 32 | int size = q.size(); 33 | while(size > 0){ 34 | TreeNode tn = q.remove(); 35 | if(tn.left!=null) q.add(tn.left); 36 | if(tn.right!=null) q.add(tn.right); 37 | size--; 38 | } 39 | depth++; 40 | } 41 | return depth; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc108.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 108. Convert Sorted Array to Binary Search Tree 4 | * 题意:将有序数组转换为二叉搜索树 5 | * 难度:Easy 6 | * 分类:Tree, Depth-first Search 7 | * 思路:类似二分查找,每次把数组劈成两半 8 | * Tips:Bingo! 9 | */ 10 | public class lc108 { 11 | public class TreeNode { 12 | int val; 13 | TreeNode left; 14 | TreeNode right; 15 | TreeNode(int x) { val = x; } 16 | } 17 | public TreeNode sortedArrayToBST(int[] nums) { 18 | TreeNode tn = helper(nums, 0, nums.length-1); 19 | return tn; 20 | } 21 | public TreeNode helper(int[] nums, int left, int right){ 22 | if(left0) res[0] = i; 19 | if(count[i]>0 && i>res[1]) res[1] = i; 20 | res[2] += count[i]*i; 21 | count_num += count[i]; 22 | if(count[i]>mode_num) { 23 | res[4] = i; 24 | mode_num = count[i]; 25 | } 26 | } 27 | int medium_pos1 = (count_num+1)/2; //中位数 28 | int medium_pos2 = (count_num+2)/2; 29 | count_num = 0; 30 | for (int i = 0; i < count.length ; i++) { 31 | count_num += count[i]; 32 | if(medium_pos1>0&&medium_pos1<=count_num) { 33 | res[3]+= i; 34 | medium_pos1 = -1; 35 | } 36 | if(medium_pos2>0&&medium_pos2<=count_num) { 37 | res[3]+= i; 38 | medium_pos2 = -1; 39 | } 40 | } 41 | res[2] = res[2]/count_num; 42 | res[3] = res[3]/2; 43 | return res; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /code/lc1094.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 1094. Car Pooling 4 | * 题意: 5 | * 难度:Medium 6 | * 分类: 7 | * 思路: lc56 类似的题,但该题的集合没有传递覆盖的特性,所以遍历的时候又加了个循环,N^2 8 | * 非常巧妙的方法,每次记录上车,下车人数,然后遍历一遍进行模拟上下车 9 | * Tips:lc253, lc56 10 | */ 11 | import java.util.Arrays; 12 | import java.util.Comparator; 13 | 14 | public class lc1094 { 15 | public boolean carPooling(int[][] trips, int capacity) { 16 | Arrays.sort(trips, new Comparator() { // 记住这种写法 17 | @Override 18 | public int compare(int[] o1, int[] o2) { 19 | if(o1[1]!=o2[1]) 20 | return o1[1] - o2[1]; 21 | else 22 | return o2[2] - o1[2]; 23 | } 24 | }); 25 | for (int i = 0; i < trips.length ; i++) { 26 | int current = trips[i][0]; 27 | for (int j = i-1; j >=0 ; j--) { //往前找是否重叠 28 | if(trips[j][2]>trips[i][1]) current += trips[j][0]; 29 | } 30 | if(current>capacity) return false; 31 | } 32 | return true; 33 | } 34 | 35 | public boolean carPooling2(int[][] trips, int capacity) { 36 | int stops[] = new int[1001]; 37 | for (int t[] : trips) { 38 | stops[t[1]] += t[0]; 39 | stops[t[2]] -= t[0]; 40 | } 41 | for (int i = 0; capacity >= 0 && i < 1001; ++i) capacity -= stops[i]; 42 | return capacity >= 0; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/lc11.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 11. Container With Most Water 4 | * 题意:数组下标代表横坐标,数组中的值代表纵坐标,求最大面积 5 | * 难度:Medium 6 | * 分类:Array, Two Pointers 7 | * Tips:复杂度可以为O(N), 指针往里走, 若值也小了,则面积一定不会增大。和lc42做比较 8 | * lc11, lc42, lc84 9 | */ 10 | public class lc11 { 11 | public static void main(String[] args) { 12 | int[] arr = {1,8,6,2,5,4,8,3,7}; 13 | System.out.println(maxArea(arr)); 14 | } 15 | 16 | public static int maxArea(int[] height) { 17 | int left = 0; 18 | int right = height.length-1; 19 | int result = 0; 20 | while(left> pathSum(TreeNode root, int sum) { 23 | List> res = new ArrayList(); 24 | helper(res, new ArrayList(), root, sum); 25 | return res; 26 | } 27 | public void helper(List> res, List cur, TreeNode root, int sum){ 28 | if(root==null) return; 29 | cur.add(root.val); 30 | if(root.left==null&&root.right==null&&root.val==sum){ //到叶子节点 31 | res.add(new ArrayList(cur)); 32 | }else{ 33 | helper(res, cur, root.left, sum-root.val); 34 | helper(res, cur, root.right, sum-root.val); 35 | } 36 | cur.remove(cur.size()-1); //注意是去掉最后一个,传的是索引。传递对象的话,序列可能会变。 37 | return; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/lc114.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 114. Flatten Binary Tree to Linked List 4 | * 题意:二叉树转链表 5 | * 难度:Medium 6 | * 分类:Tree, Depth-first Search 7 | * 思路:就是节点间连接换一下,理清思路就行了,类似中序遍历 8 | * Tips:lc426 9 | */ 10 | public class lc114 { 11 | public class TreeNode { 12 | int val; 13 | TreeNode left; 14 | TreeNode right; 15 | TreeNode(int x) { val = x; } 16 | } 17 | public void flatten(TreeNode root) { 18 | if(root==null) 19 | return; 20 | flatten(root.left); 21 | flatten(root.right); 22 | TreeNode origin_r = root.right; 23 | root.right = root.left; //右节点替换为左节点 24 | TreeNode right_leaf = root; 25 | while(right_leaf.right!=null){ //右节点遍历到最后,把左节点接上 26 | right_leaf = right_leaf.right; 27 | } 28 | right_leaf.right = origin_r; 29 | root.left = null; //别忘了把left设成null 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /code/lc116.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 116. Populating Next Right Pointers in Each Node 4 | * 题意:设置二叉树的next指针,指向同层右侧节点 5 | * 难度:Medium 6 | * 分类:Tree, Depth-first Search 7 | * 思路:自己写的递归,中间有冗余。迭代方法和较优的递归会利用先前已经设置的next指针,做下一步操作 8 | * Tips:复习时多看一下,自己没想起来利用已经设置好的指针 9 | */ 10 | public class lc116 { 11 | public class TreeLinkNode { 12 | int val; 13 | TreeLinkNode left, right, next; 14 | TreeLinkNode(int x) { val = x; } 15 | } 16 | public void connect(TreeLinkNode root) { 17 | if(root==null) return; 18 | helper(root.left, root.right); 19 | } 20 | 21 | public void helper(TreeLinkNode root1, TreeLinkNode root2){//较慢,也能过 22 | if( root1==null || root2==null ) return; 23 | root1.next = root2; 24 | helper(root1.left, root1.right); 25 | helper(root1.right, root2.left); //会重复设置 26 | helper(root2.left,root2.right); 27 | } 28 | 29 | public void connect2(TreeLinkNode root) { 30 | while(root!=null){ 31 | TreeLinkNode start = root; 32 | while(start!=null){ 33 | if(start.left!=null){ 34 | start.left.next = start.right; //设置下一层的next指针 35 | if(start.next!=null){ 36 | start.right.next = start.next.left; 37 | } 38 | } 39 | start = start.next; 40 | } 41 | root = root.left; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/lc118.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 118. Pascal's Triangle 4 | * 题意:上层元素相邻的和,两边补1,得到下层元素 5 | * 难度:Easy 6 | * 分类:Array 7 | * 思路:迭代计算 8 | * Tips: 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class lc118 { 14 | public List> generate(int numRows) { 15 | List> res = new ArrayList<>(); 16 | if(numRows==0) return res; 17 | List ls = new ArrayList(); 18 | ls.add(1); //第一层1个1 19 | res.add(ls); 20 | numRows--; 21 | if(numRows==0) return res; 22 | while(numRows>0){ 23 | ArrayList temp = new ArrayList(); 24 | temp.add(1); 25 | for (int i = 0; i < ls.size()-1 ; i++) { 26 | temp.add(ls.get(i)+ls.get(i+1)); 27 | } 28 | temp.add(1); 29 | res.add(temp); 30 | ls = temp; 31 | numRows--; 32 | } 33 | return res; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc119.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /* 7 | * 119. Pascal's Triangle II 8 | * 题意:和118一样,就是输出不一样 9 | * 难度:Easy 10 | * 分类:Array 11 | * 思路:记一下 ArrayList.set 方法,不用重新 new ArrayList 12 | * Tips: 13 | */ 14 | public class lc119 { 15 | public List getRow(int rowIndex) { 16 | ArrayList res = new ArrayList<>(); 17 | res.add(0,1); 18 | while(rowIndex-->0){ 19 | res.add(0,1); 20 | for (int i = 1; i < res.size()-1 ; i++) { 21 | res.set(i, res.get(i)+res.get(i+1)); 22 | } 23 | } 24 | return res; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /code/lc120.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.List; 4 | /* 5 | * 120. Triangle 6 | * 题意:三角形的矩阵,求值最小的路径 7 | * 难度:Medium 8 | * 分类:Array, Dynamic Porgramming 9 | * 思路:动态规划 dp[i] = min(dp[i-1],dp[i]) + val 10 | * Tips: 11 | */ 12 | public class lc120 { 13 | public int minimumTotal(List> triangle) { 14 | int len = triangle.get(triangle.size()-1).size(); 15 | int[] dp = new int[len]; 16 | int[] dp2 = new int[len]; 17 | int index = 0; 18 | int res = Integer.MAX_VALUE; 19 | while(index ls = triangle.get(index); 21 | res = Integer.MAX_VALUE; 22 | for (int i = 0; i < ls.size() ; i++) { 23 | if(i==0) dp2[i] = dp[i] + ls.get(i); 24 | else if(i==ls.size()-1) dp2[i] = dp[i-1] + ls.get(i); //注意是 i==ls.size()-1 25 | else dp2[i] = Math.min(dp[i-1],dp[i]) + ls.get(i); 26 | res = Math.min(dp2[i], res); 27 | } 28 | dp = dp2; //两个一维数组 29 | dp2 = new int[len]; 30 | index++; 31 | } 32 | return res; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/lc121.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 121. Best Time to Buy and Sell Stock 4 | * 题意:股票买卖1次,最大利润 5 | * 难度:Easy 6 | * 分类:Arryas, Dynamic Programming 7 | * Tips:lc121, lc309, lc188, lc123, lc714 8 | */ 9 | public class lc121 { 10 | public int maxProfit(int[] prices) { 11 | int min = Integer.MAX_VALUE, res=0; 12 | for(int i=0; i0) 16 | res += prices[i]-prices[i-1]; 17 | } 18 | return res; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/lc123.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 123. Best Time to Buy and Sell Stock III 4 | * 题意:买卖股票最大利润,只能买卖2次 5 | * 难度:Hard 6 | * 分类:Array, Dynamic Programming 7 | * 思路:两种思路,第一种是分成两块,每块按lc121的算法进行计算,最后合并结果 8 | * 第二种思路设置4个变量,分别为第一次买,第一次卖,第二次买,第二次卖的价格 9 | * Tips:只想到了O(N^2)的方法 10 | * lc121, lc309, lc188, lc123, lc714 11 | */ 12 | public class lc123 { 13 | public int maxProfit(int[] prices) { 14 | int buy1 = Integer.MAX_VALUE, buy2 = Integer.MAX_VALUE, sell1 = 0, sell2 = 0; 15 | for (int i = 0; i < prices.length ; i++) { 16 | buy1 = Math.min(buy1, prices[i]); //第一次购买的最低价格 17 | sell1 = Math.max(sell1, prices[i] - buy1); 18 | buy2 = Math.min(buy2, prices[i]-sell1); //记住第二项 prices[i]-sell1 19 | sell2 = Math.max(sell2, prices[i]-buy2); //当只购买一次时,会传递的 20 | } 21 | return sell2; 22 | } 23 | 24 | public int maxProfit2(int[] prices) { //常规方法,分为两块,O(N^2) 25 | int res = 0; 26 | for (int i = 0; i wordList) { 17 | if(!wordList.contains(endWord)) return 0; 18 | Queue qu = new ArrayDeque(); //用一个Queue和int size类似树的层次遍历,和两个hashset效果一样 19 | qu.add(beginWord); 20 | int level = 2; 21 | while(!qu.isEmpty()){ 22 | int size = qu.size(); 23 | for (int i = 0; i < size ; i++) { 24 | char[] curr_str = qu.remove().toCharArray(); 25 | System.out.println(String.valueOf(curr_str)); 26 | for (int j = 0; j < curr_str.length ; j++) { 27 | char ch = curr_str[j]; 28 | for (char k = 'a'; k <='z' ; k++) { //如果每次比较两个字符串是否差一位,时间复杂度太大,所以直接替换一个字符 29 | curr_str[j] = k; 30 | if(String.valueOf(curr_str).equals(endWord)) return level; 31 | if(wordList.contains(String.valueOf(curr_str))){ 32 | wordList.remove(String.valueOf(curr_str)); //这要remove 33 | qu.add(String.valueOf(curr_str)); 34 | } 35 | } 36 | curr_str[j] = ch; 37 | } 38 | } 39 | level++; 40 | } 41 | return 0; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc128.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | /* 7 | * 128. Longest Consecutive Sequence 8 | * 题意:无序数组,求最长连续子序列的长度 9 | * 难度:Hard 10 | * 分类:Array, Union Find 11 | * 思路:用set先把所有元素放一遍,再遍历,每次找边界,remove掉 12 | * Tips:也可以只用一个循环,每次放进去以后,更新边界的值即可 13 | */ 14 | public class lc128 { 15 | public static void main(String[] args) { 16 | int[] nums = {100, 4, 200, 1, 3, 2}; 17 | System.out.println(longestConsecutive(nums)); 18 | } 19 | public static int longestConsecutive(int[] nums) { 20 | Set s = new HashSet(); 21 | for(int i:nums) s.add(i); 22 | int max_len = 0; 23 | for(int i:nums) { 24 | if(s.contains(i)){ 25 | s.remove((Integer)i); 26 | int left = i-1; 27 | while(s.contains(left)){ 28 | s.remove((Integer)left); 29 | left--; 30 | } 31 | int right = i+1; 32 | while(s.contains(right)){ 33 | s.remove((Integer)right); 34 | right++; 35 | } 36 | max_len = Math.max(right-left-1, max_len); 37 | } 38 | } 39 | return max_len; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/lc129.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 129. Sum Root to Leaf Numbers 4 | * 题意:一条路径上的数字组成一个数字,求所有从跟到叶子的路径和 5 | * 难度:Medium 6 | * 分类:Tree, Depth-first Search 7 | * 思路:dfs 8 | * Tips:lc112, lc113, lc437, lc129, lc124, lc337 9 | */ 10 | public class lc129 { 11 | public class TreeNode { 12 | int val; 13 | TreeNode left; 14 | TreeNode right; 15 | TreeNode(int x) { 16 | val = x; 17 | } 18 | } 19 | public int sumNumbers(TreeNode root) { 20 | if(root==null) return 0; 21 | return helper(root, 0); 22 | } 23 | public int helper(TreeNode root, int sum){ 24 | if(root==null) return 0; //一条路径,另一边返回0 25 | if(root.left==null&&root.right==null) return sum*10+root.val; //这点注意,是叶子节点直接返回了 26 | return helper(root.left, sum*10+root.val) + helper(root.right, sum*10+root.val); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/lc13.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 13. Roman to Integer 4 | * 题意:罗马数字转Int 5 | * 难度:Easy 6 | * 分类:Math, String 7 | * 注意:如何解决6种反例,两种方式: (1)判断该位置上与下一位置上大小,决定加减. (2)如何字符串中包含该情况,减去误差 8 | */ 9 | public class lc13 { 10 | public static void main(String[] args) { 11 | String s = "IV"; 12 | System.out.println(romanToInt(s)); 13 | } 14 | 15 | public static int romanToInt(String s) { 16 | int sum =0; 17 | for (int i = 0; i > partition(String s) { 25 | List> res = new ArrayList<>(); 26 | helper(s, res, new ArrayList<>()); 27 | return res; 28 | } 29 | 30 | public static void helper(String s, List> res, List curr){ 31 | if(s.length()==0) { 32 | res.add(new ArrayList<>(curr)); //新new一个 33 | } 34 | for (int i = 1; i <= s.length() ; i++) { 35 | String curr_str = s.substring(0,i); 36 | if(isPalindrome(curr_str)){ 37 | curr.add(curr_str); 38 | helper(s.substring(i), res, curr); 39 | curr.remove(curr.size()-1); //不要用curr.remove(curr_str); 会把集合内顺序打乱,AC不了 40 | } 41 | } 42 | } 43 | 44 | public static boolean isPalindrome(String s){ //判断是否为回文 45 | int b =0; 46 | int e = s.length()-1; 47 | while(b i - 1 || pal[j + 1][i - 1])) { 44 | pal[j][i] = true; 45 | min = j == 0 ? 0 : Math.min(min, cut[j - 1] + 1); 46 | } 47 | } 48 | cut[i] = min; 49 | } 50 | return cut[n - 1]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /code/lc134.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 134. Gas Station 4 | * 题意:给两个数组,一个表示在该点能加多少油,一个表示该点到下个点消耗多少油,加油站连成一个环,问能否走遍所有加油站,从哪一站开始 5 | * 难度:Medium 6 | * 分类:Greedy 7 | * 思路:计算两个数组的差,再把每个位置加起来,如果>=0,则能跑完。位置为最大连续子数组的开始位置。 8 | * Tips:lc53 9 | */ 10 | public class lc134 { 11 | public int canCompleteCircuit(int[] gas, int[] cost) { 12 | int[] arr = new int[gas.length]; 13 | int sum = 0, pos = 0, dp =0; 14 | for (int i = 0; i < arr.length ; i++) { 15 | arr[i] = gas[i] - cost[i]; 16 | sum += arr[i]; 17 | 18 | if(dp<=0) { //最大连续子数组,并记录位置 19 | dp = arr[i]; 20 | pos = i; 21 | } 22 | else 23 | dp += arr[i]; 24 | } 25 | return sum<0? -1: pos; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /code/lc136.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 136. Single Number 4 | * 题意:找出数组中单一的数 5 | * 难度:Easy 6 | * 分类:Hash Table, Bit Maniputation 7 | * 思路:两种巧妙方法:1.异或 2. set以后sum*2 - sum 8 | * Tips: 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.HashSet; 12 | import java.util.Set; 13 | 14 | public class lc136 { 15 | public static void main(String[] args) { 16 | int[] nums = {2,2,1}; 17 | System.out.println(singleNumber(nums)); 18 | System.out.println(singleNumber2(nums)); 19 | } 20 | public static int singleNumber(int[] nums) { 21 | int res = nums[0]; 22 | for (int i = 1; i < nums.length ; i++) { 23 | res = res ^ nums[i]; 24 | } 25 | return res; 26 | } 27 | public static int singleNumber2(int[] nums) { 28 | Set s = new HashSet(); 29 | int sum = 0; 30 | int sum2 = 0; 31 | for (int i = 0; i < nums.length ; i++) { 32 | sum += nums[i]; 33 | s.add(nums[i]); 34 | } 35 | for(Integer i : s){ 36 | sum2 += i; 37 | } 38 | return 2*sum2 - sum; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code/lc138.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 138. Copy List with Random Pointer 4 | * 题意:链表除了next指针外,还有一个random指针。拷贝这个链表 5 | * 难度:Medium 6 | * 分类:Hash Table, LinkedList 7 | * 思路:一种用HashTable,把源节点和复制的节点对应起来,空间复杂度为O(n) 8 | * 把要复制的节点直接连接在该节点之后,操作完以后再分开 9 | * Tips:因为需要每步骤返回值,所以递归的方法在这题更合适 10 | */ 11 | public class lc138 { 12 | class RandomListNode { 13 | int label; 14 | RandomListNode next, random; 15 | RandomListNode(int x) { this.label = x; } 16 | }; 17 | public RandomListNode copyRandomList(RandomListNode head) { 18 | if(head==null) return null; 19 | RandomListNode node = head; 20 | while(node!=null){ 21 | RandomListNode temp = new RandomListNode(node.label); 22 | temp.next = node.next; 23 | node.next = temp; 24 | node = temp.next; 25 | } 26 | node = head; 27 | while(node!=null){ 28 | if(node.random!=null) node.next.random = node.random.next; //注意判断是否为空 29 | node = node.next.next; 30 | } 31 | node = head; 32 | RandomListNode res = head.next; 33 | RandomListNode temp = head.next; 34 | while(temp!=null&&temp.next!=null){ 35 | node.next = temp.next; 36 | temp.next = node.next.next; 37 | node = node.next; 38 | temp = temp.next; 39 | } 40 | node.next = null; //别忘了最后一个节点连接给null 41 | return res; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc139.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 139. Word Break 4 | * 题意:是否能够分词 5 | * 难度:Medium 6 | * 分类:Dynamic Programming 7 | * 思路:动态规划 8 | * Tips:巧妙的方法,防止了复杂的操作,通过遍历之前计算出来的结果 9 | * 递归的方法本质和dp是一样的,记住用备忘录算法,把之前的结果记下来 10 | * lc140 11 | */ 12 | import java.util.HashMap; 13 | import java.util.List; 14 | 15 | public class lc139 { 16 | public boolean wordBreak(String s, List wordDict) { 17 | boolean[] dp = new boolean[s.length()+1]; 18 | dp[0] = true; 19 | for (int i = 1; i < dp.length ; i++) { 20 | for (int j = 0; j < i ; j++) { //遍历之前计算出来的结果 21 | if( dp[j]==true && wordDict.contains(s.substring(j,i))) 22 | dp[i] = true; 23 | } 24 | } 25 | return dp[s.length()]; 26 | } 27 | 28 | HashMap hm = new HashMap(); 29 | public boolean wordBreak2(String s, List wordDict) { 30 | if(hm.containsKey(s)) return hm.get(s); 31 | if(s.length() == 0) return true; 32 | Boolean flag = false; 33 | for(String word:wordDict){ 34 | if(s.startsWith(word)) flag = flag||wordBreak(s.substring(word.length()), wordDict); //注意函数 startsWith 35 | } 36 | hm.put(s, flag); 37 | return flag; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/lc14.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 14. Longest Common Prefix 4 | * 题意:找最长匹配前缀 5 | * 难度:Easy 6 | * 分类:String 7 | * Tips:可先将字符串排序,之后只比较数组中首和尾字符串即可 8 | */ 9 | import java.util.Arrays; 10 | 11 | public class lc14 { 12 | public static String longestCommonPrefix(String[] strs) { //不是最优的方法,多做了比较 13 | if(strs.length==0) 14 | return ""; 15 | Arrays.sort(strs); 16 | char[] str1 = strs[0].toCharArray(); 17 | char[] str2 = strs[strs.length-1].toCharArray(); 18 | int len = Math.min(str1.length,str2.length); 19 | int i = 0; 20 | while(i wordBreak(String s, List wordDict) { 16 | List res = new ArrayList<>(); 17 | if(s.length()==0) return res; 18 | return helper(s, wordDict, new HashMap<>()); 19 | } 20 | 21 | public List helper(String s, List wordDict, HashMap> hm){ 22 | List res = new ArrayList<>(); 23 | if(hm.containsKey(s)) return hm.get(s); //hm用以记录子结果,之前递归已计算出,则直接返回。备忘录算法。 24 | for (int i = s.length()-1; i >=0 ; i--) { 25 | String cut_str = s.substring(i); 26 | if(wordDict.contains(cut_str)){ 27 | List ls = helper(s.substring(0,i), wordDict, hm); //切掉以后剩下的字符串的结果 28 | for(String str:ls){ 29 | res.add(str+" "+cut_str); //结果拼上切掉的字符串 30 | } 31 | if(i==0){ //切完了,不需要拼空格。hm中没有保存键值为""的,上个循环不会有效果。 32 | res.add(cut_str); 33 | } 34 | hm.put(s, res); 35 | } 36 | } 37 | return res; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/lc141.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 141. Linked List Cycle 4 | * 题意:链表是否有环 5 | * 难度:Easy 6 | * 分类:Linked List, Two Pointers 7 | * 思路:快慢指针 8 | * lc142 9 | */ 10 | public class lc141 { 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | ListNode(int x) { val = x; } 15 | } 16 | public boolean hasCycle(ListNode head) { 17 | if(head==null||head.next==null) return false; 18 | ListNode slow = head; 19 | ListNode fast = head.next; 20 | while(fast!=null&&fast.next!=null){ //注意判断条件,slow一定不等于null,不用判断了 21 | slow = slow.next; 22 | fast = fast.next.next; 23 | if(fast==slow) return true; 24 | } 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /code/lc142.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 142. Linked List Cycle II 4 | * 题意:求链表环的起始节点 5 | * 难度:Medium 6 | * 分类:Linked List, Two Pointers 7 | * 思路:lc141进一步问题。快慢指针相遇后走了a+b步,head 走a步后到起始点,则 a+b+n=2a+2b -> a+b=n 所以相遇点再走a步到起始点。相遇以后再设一个指针从head开始走,慢指针接着走,则相遇点为环的入口点。 8 | * Tips: 9 | */ 10 | public class lc142 { 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | ListNode(int x) { val = x; } 15 | } 16 | public ListNode detectCycle(ListNode head) { 17 | if(head==null) 18 | return null; 19 | ListNode slow = head; 20 | ListNode fast = head; 21 | ListNode slow2 = head; 22 | while( fast.next!=null && fast.next.next!=null ){ 23 | slow = slow.next; 24 | fast = fast.next.next; 25 | if(slow==fast){ 26 | while(slow2!=slow){ 27 | slow = slow.next; 28 | slow2 = slow2.next; 29 | } 30 | return slow2; 31 | } 32 | } 33 | return null; 34 | } 35 | 36 | public ListNode detectCycle2(ListNode head) { 37 | if(head==null||head.next==null) return null; 38 | ListNode slow = head; 39 | ListNode fast = head.next; 40 | while(fast!=null&&fast.next!=null){ 41 | slow = slow.next; 42 | fast = fast.next.next; 43 | if(slow==fast){ 44 | slow = slow.next; 45 | while(head!=slow){ 46 | head = head.next; 47 | slow = slow.next; 48 | } 49 | return slow; 50 | } 51 | } 52 | return null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /code/lc144.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 144. Binary Tree Preorder Traversal 4 | * 题意:二叉树先序遍历 5 | * 难度:Medium 6 | * 分类:Stack, Tree 7 | * 思路:左节点依次入栈 8 | * Tips:和lc94中序,lc145后序一起看, lc102 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Stack; 13 | 14 | public class lc144 { 15 | public class TreeNode { 16 | int val; 17 | TreeNode left; 18 | TreeNode right; 19 | TreeNode(int x) { val = x; } 20 | } 21 | public List inorderTraversal(TreeNode root) { 22 | List res = new ArrayList<>(); 23 | if(root==null) 24 | return res; 25 | Stack st = new Stack(); 26 | while( !st.isEmpty() || root!=null ) { //注意停止条件 27 | while (root != null) { 28 | st.push(root); 29 | res.add(root.val); 30 | root = root.left; 31 | } 32 | root = st.pop(); 33 | root = root.right; 34 | } 35 | return res; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/lc145.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 145. Binary Tree Postorder Traversal 4 | * 题意:二叉树后序遍历 5 | * 难度:Hard 6 | * 分类:Stack, Tree 7 | * 思路:调整的先序遍历,再反转结果 8 | */ 9 | import java.util.ArrayList; 10 | import java.util.Collections; 11 | import java.util.List; 12 | import java.util.Stack; 13 | 14 | public class lc145 { 15 | public class TreeNode { 16 | int val; 17 | TreeNode left; 18 | TreeNode right; 19 | TreeNode(int x) { val = x; } 20 | } 21 | public List postorderTraversal(TreeNode root) { 22 | ArrayList res = new ArrayList(); 23 | if(root==null) return res; 24 | Stack st = new Stack(); 25 | while(!st.isEmpty()||root!=null){ 26 | while(root!=null) { 27 | st.add(root); 28 | res.add(root.val); 29 | root = root.right; //先遍历右节点 30 | } 31 | root = st.pop(); 32 | root =root.left; //再左节点 33 | } 34 | Collections.reverse(res); //反转链表 35 | return res; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /code/lc149.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.HashMap; 4 | 5 | /* 6 | * 149. Max Points on a Line 7 | * 题意:给定多个点,问一条线上最多几个点 8 | * 难度:Hard 9 | * 分类:HashTable, Math 10 | * 思路:每次选出一个点,与其他点匹配。因为斜率是小数,所以用两个整数(双层HashMap)来表示小数。时间O(n^2) 11 | * Tips: 12 | */ 13 | public class lc149 { 14 | class Point { 15 | int x; 16 | int y; 17 | Point() { x = 0; y = 0; } 18 | Point(int a, int b) { x = a; y = b; } 19 | } 20 | public int maxPoints(Point[] points) { 21 | if(points.length<=2) return points.length; 22 | int res = 0; 23 | for (int i = 0; i < points.length-1 ; i++) {//先固定一个点,再根据斜率进行记录就行了 24 | HashMap> hm = new HashMap<>(); 25 | int overlap = 1; 26 | int max = 0; 27 | for (int j = i+1; j < points.length ; j++) { 28 | int x = points[i].x - points[j].x; 29 | int y = points[i].y - points[j].y; 30 | if(x==0&&y==0){ //重复点 31 | overlap++; 32 | continue; 33 | } 34 | int gcd = genGCD(x, y); 35 | if(gcd!=0){ //注意,当一个值为0时,gcd==0 36 | x = x/gcd; 37 | y = y/gcd; 38 | } 39 | HashMap hm2 = hm.getOrDefault(x, new HashMap()); 40 | hm2.put(y,hm2.getOrDefault(y,0)+1); 41 | hm.put(x,hm2); 42 | max = Math.max(max, hm2.get(y)); 43 | } 44 | res = Math.max(res, max+overlap); //里边循环完了,才知道有几个overlap,所以在循环外加 45 | } 46 | return res; 47 | } 48 | 49 | public int genGCD(int a, int b){ 50 | if(b==0) return a; //注意和GCD不一样的是这没有比较大小,交换a,b。因为可能有负数 51 | return genGCD(b, a%b); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /code/lc15.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 15. 3Sum 4 | * 题意:找出数组中所有和为0的三元组合 5 | * 难度:Medium 6 | * 分类:Array, Two Pointers 7 | * 注意:如何避免 List 重复元素 8 | * Tips:lc15, lc16, lc923 9 | */ 10 | import java.util.*; 11 | 12 | public class lc15 { 13 | public static void main(String[] args) { 14 | int[] nums = {-1, 0, 1, 2, -1, -4}; 15 | System.out.println(threeSum(nums).toString()); 16 | } 17 | 18 | public static List> threeSum(int[] nums) { 19 | List> result = new ArrayList(); 20 | Arrays.sort(nums); 21 | for (int i = 0; i < nums.length-2 ; i++) { 22 | if( i>0 && nums[i]==nums[i-1] ) //防止重复添加相同内容List 23 | continue; 24 | int left = i+1, right = nums.length-1; 25 | while(left st = new Stack(); 16 | String opration = "+-*/"; 17 | int res = 0; 18 | for (int i = 0; i < tokens.length ; i++) { 19 | if(opration.contains(tokens[i])){ 20 | int n2 = st.pop(); //注意n1,n2顺序,除法时两个数是有顺序的 21 | int n1 = st.pop(); 22 | System.out.println(n1); 23 | System.out.println(n2); 24 | if(tokens[i].equals("+")){ //注意用equeals 25 | res = n1 + n2; 26 | }else if(tokens[i].equals("-")){ 27 | res = n1 - n2; 28 | }else if(tokens[i].equals("*")){ 29 | res = n1 * n2; 30 | }else if(tokens[i].equals("/")){ 31 | res = n1 / n2; 32 | } 33 | st.push(res); 34 | System.out.println(res); 35 | }else{ 36 | st.push(Integer.valueOf(tokens[i]));; 37 | } 38 | } 39 | return res; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/lc151.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | /* 6 | * 151. Reverse Words in a String 7 | * 题意:反转字符串中的单词 8 | * 难度:Medium 9 | * 分类:String 10 | * 思路:难点在中间的空格可能是多个空格,注意如何解决 11 | * Tips: 12 | */ 13 | public class lc151 { 14 | public String reverseWords(String s) { 15 | String[] words = s.trim().split(" +"); //+号匹配多个 16 | Collections.reverse(Arrays.asList(words)); 17 | return String.join(" ", words); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/lc152.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 152. Maximum Product Subarray 4 | * 题意:连续子序列最大乘积 5 | * 难度:Medium 6 | * 分类:Array, Dynamic Programming 7 | * 思路:保存最大,最小值,因为负负得正。dp不用保存数组,空间可以压缩。 8 | * Tips:Product是乘的意思 9 | */ 10 | public class lc152 { 11 | public static void main(String[] args) { 12 | int[] nums = {-4,-3,-2}; 13 | System.out.println(maxProduct(nums)); 14 | } 15 | public static int maxProduct(int[] nums) { 16 | int max = nums[0], min = nums[0], res = nums[0]; 17 | for (int i = 1; i < nums.length ; i++) { 18 | if(nums[i]>0){ 19 | max = Math.max(nums[i],nums[i]*max); 20 | min = Math.min(nums[i],nums[i]*min); 21 | }else{ 22 | int temp = max; //注意max会被替换,先保存下 23 | max = Math.max(nums[i],nums[i]*min); 24 | min = Math.min(nums[i],nums[i]*temp); 25 | } 26 | res = Math.max(max, res); 27 | } 28 | return res; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/lc153.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 153. Find Minimum in Rotated Sorted Array 4 | * 题意:反转数组找最小值 5 | * 难度:Medium 6 | * 分类:Array, Binary Search 7 | * 思路:想清楚,不用那么多判断 8 | * Tips:边界条件想清楚 9 | * nums[mid]和nums[right]比就行了 10 | */ 11 | public class lc153 { 12 | public int findMin(int[] nums) { 13 | int left = 0; 14 | int right = nums.length-1; 15 | while(left st; 15 | int min = Integer.MAX_VALUE; 16 | /** initialize your data structure here. */ 17 | public MinStack() { 18 | this.st = new Stack(); 19 | } 20 | 21 | public void push(int x) { 22 | if(x<=min){ //别忘了= 23 | st.push(this.min); 24 | this.min = x; 25 | } 26 | st.push(x); 27 | } 28 | 29 | public void pop() { 30 | int x = st.pop(); 31 | if(x==this.min){ 32 | this.min = st.pop(); 33 | } 34 | } 35 | 36 | public int top() { 37 | return st.peek(); 38 | } 39 | 40 | public int getMin() { 41 | return this.min; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/lc16.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Arrays; 4 | /* 5 | * 16. 3Sum Closest 6 | * 题意:找出3个数的和最接近target 7 | * 难度:Medium 8 | * 分类:Array, Two Pointers 9 | * 思路:3sum的思路,每次记下最接近的res即可 10 | * Tips:lc15, lc16, lc923 11 | */ 12 | public class lc16 { 13 | public int threeSumClosest(int[] nums, int target) { 14 | int res = nums[0]+nums[1]+nums[2]; 15 | Arrays.sort(nums); 16 | for (int i = 0; i < nums.length-2 ; i++) { 17 | int start = i+1; 18 | int end = nums.length-1; 19 | while(starttarget) end--; 24 | if(Math.abs(sum-target)nums[mid+1]&&nums[mid]>nums[mid-1]) return mid; 25 | if(nums[mid]0&&denominator<0) || (numerator<0&&denominator>0)) sb.append("-"); //符号 19 | long num = Math.abs((long)numerator); //用long防止溢出 20 | long den = Math.abs((long)denominator); 21 | sb.append(num/den); //整数部分 22 | 23 | HashMap hm = new HashMap(); //key存储余数,余数>0 <9, value存储index,用来加( 24 | long n = num%den; 25 | if(n!=0) sb.append("."); 26 | while( n!=0 && !hm.containsKey(n)){ 27 | hm.put(n, sb.length()); 28 | n = n*10; 29 | sb.append(n/den); 30 | n = n%den; 31 | } 32 | if(hm.containsKey(n)){ 33 | int index = hm.get(n); 34 | sb.insert(index, "("); 35 | sb.append(")"); 36 | } 37 | return sb.toString(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/lc169.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 169. Majority Element 4 | * 题意:数组中有一个元素出现次数 >len/2 ,找出这个数 5 | * 难度:Easy 6 | * 分类:Array, Divide and Conquer, Bit Maniputation 7 | * 思路:很多种方法, Hashmap 是 O(n), O(n)的。 快排是O(n), O(1)的。最巧妙的办法是 O(n), O(1) 的如下。 8 | * Tips:之所以能够 O(n), O(1) 是因为题目已经给定了数组中一定能找到这个数,该方法充分利用了这一点 9 | */ 10 | public class lc169 { 11 | public int majorityElement(int[] nums) { 12 | int res = nums[0]; 13 | int count = 1; 14 | for (int i = 1; i < nums.length ; i++) { // 摩尔投票法,看这个数出现了几次 15 | if(nums[i]!=res) // 不是这个数就 --, ==0就用当前数替换res 16 | count--; 17 | else 18 | count++; 19 | if(count==0){ 20 | res = nums[i]; 21 | count++; 22 | } 23 | } 24 | return res; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /code/lc17.java: -------------------------------------------------------------------------------- 1 | package code; 2 | import java.util.List; 3 | import java.util.Vector; 4 | /* 5 | * 17. Letter Combinations of a Phone Number 6 | * 题意:手机键盘字母输入 7 | * 难度:Medium 8 | * 思路:思路记一下,每次放到vector中,遍历vector,加上所有的可能 9 | * 分类:String, Backtracking 10 | */ 11 | public class lc17 { 12 | public static void main(String[] args) { 13 | System.out.println(letterCombinations("23").toString()); 14 | } 15 | 16 | public static List letterCombinations(String digits) { 17 | Vector res = new Vector<>(); 18 | if(digits.length()==0) 19 | return res; 20 | String[] charmap = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; 21 | res.add(""); 22 | for (int i = 0; i < digits.length(); i++) { 23 | int n = digits.charAt(i)-'0'; 24 | Vector temp_res = new Vector<>(); 25 | for (int j = 0; j < charmap[n].length(); j++) { 26 | for (int k = 0; k < res.size(); k++) { 27 | temp_res.add(res.get(k)+charmap[n].charAt(j)); 28 | } 29 | } 30 | 31 | res = temp_res; 32 | } 33 | return res; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc171.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 171. Excel Sheet Column Number 4 | * 题意:Excel列的表示转换为数字 5 | * 难度:Easy 6 | * 分类:Math 7 | * 思路:注意AA代表的是27, 没有0的表示。26进位不是27。 8 | * Tips: 9 | */ 10 | public class lc171 { 11 | public int titleToNumber(String s) { 12 | char[] ch_arr = s.toCharArray(); 13 | int res = 0; 14 | for(int i=0; i() { // Comparator接口 21 | @Override 22 | public int compare(String i, String j) { 23 | String s1 = i+j; // i+j 与 j+i 比较 24 | String s2 = j+i; 25 | return s2.compareTo(s1); 26 | } 27 | }); 28 | if(strs[0].equals("0")) return "0"; //防止"000"的情况 29 | String res = ""; 30 | for (String str:strs) { 31 | res+=str; 32 | } 33 | return res; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc188.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 188. Best Time to Buy and Sell Stock IV 4 | * 题意:买卖股票最大利润,可以买卖k次 5 | * 难度:Hard 6 | * 分类:Dynamic Programming 7 | * 思路:二维dp, dp[i][j] 表示i次交易,在数组prices[0~j]上的最大利润 8 | * dp[i][j] = Max( dp[i][j-1], dp[i-1][jj]+prices[j]-prices[jj] ) { jj in range of [0, j-1] } 9 | * = Max( dp[i][j-1], prices[j]+ max(dp[i-1][jj]-prices[jj]) ) 转化为这一步,少了一层循环 10 | * dp[0][j] = 0; dp[i][0] = 0; 11 | * Tips:lc121, lc309, lc188, lc123, lc714 12 | */ 13 | public class lc188 { 14 | public int maxProfit(int k, int[] prices) { 15 | if(prices.length==0) return 0; 16 | int n = prices.length; 17 | //if k >= n/2, then you can make maximum number of transactions. 18 | if (k >= n/2) { 19 | int maxPro = 0; 20 | for (int i = 1; i < n; i++) { 21 | if (prices[i] > prices[i-1]) 22 | maxPro += prices[i] - prices[i-1]; 23 | } 24 | return maxPro; 25 | } 26 | 27 | int[][] dp = new int[k+1][prices.length]; 28 | for (int i = 1; i <= k ; i++) { 29 | int localMax = -prices[0]; 30 | for (int j = 1; j < prices.length ; j++) { //jj的计算和这一维合并,总的复杂度是二次方而不是三次 31 | dp[i][j] = Math.max(dp[i][j-1], prices[j]+localMax); 32 | localMax = Math.max(localMax, dp[i-1][j]-prices[j]); 33 | } 34 | } 35 | return dp[k][prices.length-1]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/lc189.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 189. Rotate Array 4 | * 题意:数组向后移几位,超出末尾的补到前边 5 | * 难度:Easy 6 | * 分类:Array 7 | * 思路:一种环状替换,别忘了可能是多个环。 8 | * reverse 的方法,先整体反转,再按照k划分成两个数组分别反转 9 | * Tips: 10 | */ 11 | public class lc189 { 12 | public void rotate(int[] nums, int k) { 13 | if(nums.length<2) return; 14 | int sum = 0; 15 | for (int start_index = 0; start_index < nums.length ; start_index++) { //可能多个环,用sum判断是否停止 16 | if(sum==nums.length) break; 17 | int curr_index = start_index; 18 | int next_index = (start_index+k)%nums.length; 19 | int temp1 = nums[start_index]; 20 | int temp2 =0; 21 | while(next_index!=start_index){ 22 | sum++; 23 | temp2 = nums[next_index]; 24 | nums[next_index] = temp1; 25 | temp1 =temp2; 26 | curr_index = next_index; 27 | next_index = (curr_index+k)%nums.length; 28 | } 29 | nums[start_index] = temp1; 30 | sum++; 31 | } 32 | } 33 | 34 | public void rotate2(int[] nums, int k) { 35 | if(nums.length<2) return; 36 | k = k%nums.length; //处理k>length的case 37 | reverse(nums, 0, nums.length-1); 38 | reverse(nums, 0, k-1); 39 | reverse(nums, k, nums.length-1); 40 | } 41 | public void reverse(int[] nums, int begin, int end){ 42 | while(begin0){ 18 | fast = fast.next; 19 | n--; 20 | } 21 | while(fast.next!=null){ 22 | low = low.next; 23 | fast = fast.next; 24 | } 25 | ListNode temp = low.next.next; 26 | low.next = temp; 27 | return res.next; 28 | } 29 | 30 | public class ListNode { 31 | int val; 32 | ListNode next; 33 | ListNode(int x) { val = x; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc190.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | /* 4 | * 190. Reverse Bits 5 | * 题意:转换为二进制,反转,再输出 6 | * 难度:Easy 7 | * 分类:Bit Manipulation 8 | * 思路:做位移操作,自己没想起来,好好看看 9 | * Tips:注意 >>> 无符号位移 它不会将所处理的值的最高位视为正负符号,所以作位移处理时,会直接在空出的高位填入0 10 | */ 11 | public class lc190 { 12 | public static void main(String[] args) { 13 | System.out.println(reverseBits(10)); 14 | } 15 | // you need treat n as an unsigned value 16 | public static int reverseBits(int n) { 17 | int result = 0; 18 | for (int i = 0; i < 32 ; i++) { 19 | result += n&1; 20 | n >>>= 1; //无视符号右移 21 | if(i<31) result<<=1; 22 | } 23 | return result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/lc191.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 191. Number of 1 Bits 4 | * 题意:统计二进制数中1的个数 5 | * 难度:Easy 6 | * 分类:Bit Manipulation 7 | * 思路:每次移一位,与运算 8 | * Tips: 9 | */ 10 | public class lc191 { 11 | // you need to treat n as an unsigned value 12 | public int hammingWeight(int n) { 13 | int sum = 0; 14 | int a = 1; 15 | while(a!=0){ 16 | int b = n&a; 17 | if(b!=0) sum += 1; 18 | a <<= 1; 19 | } 20 | return sum; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /code/lc198.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 198. House Robber 4 | * 题意:数组最大和,不能选取相邻的两个数 5 | * 难度:Easy 6 | * 分类:Dynamic Programming 7 | * 思路:经典的dp题,记一下 8 | * Tips:时间复杂度为 O(n) 9 | * lc213 10 | */ 11 | public class lc198 { 12 | public int rob(int[] nums) { 13 | if(nums.length == 0) 14 | return 0; 15 | if(nums.length == 1) 16 | return nums[0]; 17 | int[] dp = new int[nums.length]; 18 | dp[0] = nums[0]; 19 | dp[1] = Math.max(nums[0], nums[1]); 20 | for (int i = 2; i < nums.length ; i++) { 21 | dp[i] = Math.max((dp[i-2] + nums[i]),dp[i-1]); //dp[i] 表示以 0~i 的数组的结果 22 | } 23 | return dp[nums.length-1]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/lc199.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 199. Binary Tree Right Side View 4 | * 题意:二叉树的右视图 5 | * 难度:Medium 6 | * 分类:Tree, Depth-first Search, Breadth-first Search 7 | * 思路:1.记录当前递归最大深度,每次把第一次出现深度的节点值输出即可 8 | * 2.层次遍历 9 | * Tips: 10 | */ 11 | import java.util.ArrayList; 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | import java.util.Queue; 15 | 16 | public class lc199 { 17 | public class TreeNode { 18 | int val; 19 | TreeNode left; 20 | TreeNode right; 21 | TreeNode(int x) { 22 | val = x; 23 | } 24 | } 25 | 26 | int max_depth = 0; 27 | List res = new ArrayList(); 28 | public List rightSideView(TreeNode root) { 29 | dfs(root, 1); 30 | return res; 31 | } 32 | 33 | public void dfs(TreeNode root, int depth){ 34 | if(root==null) return; //别忘了null 35 | if(depth>max_depth) { 36 | max_depth = depth; 37 | res.add(root.val); 38 | } 39 | dfs(root.right, depth+1); 40 | dfs(root.left, depth+1); 41 | } 42 | 43 | public List rightSideView2(TreeNode root) { 44 | List res = new ArrayList(); 45 | Queue qu = new LinkedList(); //是一个队列,用LinkedList 46 | if(root!=null) qu.add(root); 47 | while(!qu.isEmpty()){ 48 | int size = qu.size(); 49 | while(size>0){ 50 | TreeNode tn = qu.remove(); 51 | if(size==1) res.add(tn.val); //==1的时候添加 52 | if(tn.left!=null) qu.add(tn.left); 53 | if(tn.right!=null) qu.add(tn.right); 54 | size--; 55 | } 56 | } 57 | return res; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /code/lc2.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 2. Add Two Numbers 4 | * 题意:两个链表,节点上的数逆序组成一个数字,求和,返回链表 5 | * 难度:Medium 6 | * 分类:Linked List, Math 7 | * 算法:两个链表一起遍历,按位加,注意进位 8 | * Tips:不要遍历完一个链表保存为变量,求变量和再转化为链表。因为链表可能很长,变量无法保存下来; 9 | * 注意考虑两个链表长度不一致的问题 10 | */ 11 | public class lc2 { 12 | 13 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 14 | int sum = 0; 15 | ListNode result = new ListNode(0); 16 | ListNode cur = result; 17 | while(l1!=null || l2!=null){ 18 | if(l1!=null) { 19 | sum += l1.val; 20 | l1 = l1.next; 21 | } 22 | if(l2!=null) { 23 | sum += l2.val; 24 | l2 = l2.next; 25 | } 26 | cur.next = new ListNode(sum%10); 27 | cur = cur.next; 28 | sum = sum/10; 29 | } 30 | if(sum==1) { 31 | cur.next = new ListNode(1); 32 | } 33 | return result.next; 34 | } 35 | 36 | public class ListNode { 37 | int val; 38 | ListNode next; 39 | ListNode(int x) { val = x; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/lc20.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.HashMap; 4 | import java.util.Stack; 5 | 6 | /* 7 | * 20. Valid Parentheses 8 | * 题意:括号匹配 9 | * 难度:Easy 10 | * 分类:String, Stack 11 | */ 12 | public class lc20 { 13 | public static void main(String[] args) { 14 | System.out.println(isValid("]")); 15 | } 16 | public static boolean isValid(String s) { 17 | Stack st = new Stack(); 18 | HashMap hm = new HashMap(); 19 | hm.put("(",")"); 20 | hm.put("[","]"); 21 | hm.put("{","}"); 22 | for (int i = 0; i < s.length() ; i++) { 23 | char ch = s.charAt(i); 24 | if(ch=='(' || ch=='[' || ch=='{'){ 25 | st.push(String.valueOf(ch)); 26 | }else{ 27 | if(st.size()==0) 28 | return false; 29 | String temp1 = hm.get(st.pop()); 30 | String temp2 = String.valueOf(ch); 31 | if(!temp1.equals(temp2)) 32 | return false; 33 | } 34 | } 35 | if(st.size()==0) 36 | return true; 37 | return false; 38 | } 39 | 40 | public boolean isValid2(String s) { 41 | Stack stack = new Stack(); 42 | for (char c : s.toCharArray()) { 43 | if (c == '(') 44 | stack.push(')'); 45 | else if (c == '{') 46 | stack.push('}'); 47 | else if (c == '[') 48 | stack.push(']'); 49 | else if (stack.isEmpty() || stack.pop() != c) 50 | return false; 51 | } 52 | return stack.isEmpty(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /code/lc202.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 202. Happy Number 4 | * 题意:各位置上的数字循环求平方和,如果可以等于1,则为Happy Number 5 | * 难度:Easy 6 | * 分类:Hash Table, Math 7 | * 思路:如果不会等于1,则会产生循环,用hashset记录之前是否出现过 8 | * 也可利用判断链表是否有环的思路,一个计算一步,一个计算两步,看是会相等来判断 9 | * Tips: 10 | */ 11 | import java.util.HashSet; 12 | 13 | public class lc202 { 14 | public boolean isHappy(int n) { 15 | HashSet hs = new HashSet(); 16 | hs.add(n); 17 | int sum = 0; 18 | while(true){ 19 | sum = 0; 20 | while(n!=0){ 21 | sum += Math.pow(n%10,2); 22 | n = n/10; 23 | } 24 | if(sum==1) return true; 25 | else if(hs.contains(sum)) break; 26 | hs.add(sum); 27 | n = sum; 28 | System.out.println(sum); 29 | } 30 | return false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/lc204.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 204. Count Primes 4 | * 题意:计算小于n的素数的个数 5 | * 难度:Easy 6 | * 分类:Hash Table, Math 7 | * 思路:两个循环,相乘得到的数不是素数。 8 | * Tips: 9 | */ 10 | public class lc204 { 11 | public int countPrimes(int n) { 12 | if(n<3) return 0; 13 | boolean[] flags = new boolean[n]; 14 | int sum = 0; 15 | for(int i=2; i findWords(char[][] board, String[] words) { 17 | //暴力搜索 18 | List res = new ArrayList<>(); 19 | for (int i = 0; i < board.length ; i++) { 20 | for (int j = 0; j < board[0].length ; j++) { 21 | for (int k = 0; k < words.length ; k++) { 22 | char[] str = words[k].toCharArray(); 23 | if(dfs(board, i, j, str, 0)&&!res.contains(words[k])) res.add(words[k]); //记得去重 24 | } 25 | } 26 | } 27 | return res; 28 | } 29 | public boolean dfs(char[][] board, int i, int j, char[] str, int index){ 30 | if(i<0||j<0||i>=board.length||j>=board[0].length||index>=str.length) return false; 31 | if(board[i][j]==str[index]){ 32 | if(index==str.length-1) return true; 33 | board[i][j] = '0'; 34 | boolean res = dfs(board, i+1, j, str, index+1)|| 35 | dfs(board, i-1, j, str, index+1)|| 36 | dfs(board, i, j+1, str, index+1)|| 37 | dfs(board, i, j-1, str, index+1); //用res记录结果,重置字符以后再返回 38 | board[i][j] = str[index]; //记得回溯后重置为原来的字符 39 | return res; 40 | } 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc213.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Arrays; 4 | /* 5 | * 213. House Robber II 6 | * 题意:数组最大和,不能选取相邻的两个数。数组首尾是连着的 7 | * 难度:Medium 8 | * 分类:Dynamic Programming 9 | * 思路:分别把第一个元素置0和最后一个元素置0,用lc198的解法 10 | * 11 | * Tips:lc198 12 | */ 13 | public class lc213 { 14 | public int rob(int[] nums) { //分别把第一个元素置0和最后一个元素置0,用lc198的解法 15 | if(nums.length == 0) 16 | return 0; 17 | if(nums.length == 1) 18 | return nums[0]; 19 | int res1 = helper(Arrays.copyOf(nums, nums.length-1)); 20 | nums[0] = 0; 21 | int res2 = helper(nums); 22 | return Math.max(res1, res2); 23 | } 24 | 25 | public int helper(int[] nums) { 26 | if(nums.length == 0) 27 | return 0; 28 | if(nums.length == 1) 29 | return nums[0]; 30 | int[] dp = new int[nums.length]; 31 | dp[0] = nums[0]; 32 | dp[1] = Math.max(nums[0], nums[1]); 33 | for (int i = 2; i < nums.length ; i++) { 34 | dp[i] = Math.max((dp[i-2] + nums[i]),dp[i-1]); //dp[i] 表示以 0~i 的数组的结果 35 | } 36 | return dp[nums.length-1]; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/lc215.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 215. Kth Largest Element in an Array 4 | * 题意:找第k大的数 5 | * 难度:Medium 6 | * 分类:Divide and Conquer, Heap 7 | * 思路:快排的思想 8 | * Tips:经典的题目,记一下代码格式,方便快速写出 9 | * 两个点 1.降序排序 2.注意等号。 相比快排,省略了首行判断返回 和 交换 10 | * lc912 11 | */ 12 | public class lc215 { 13 | public static void main(String[] args) { 14 | int[] nums = {3,2,3,1,2,4,5,5,6}; 15 | System.out.println(findKthLargest(nums, 4)); 16 | } 17 | public static int findKthLargest(int[] nums, int k) { 18 | return quickSort(nums, 0, nums.length-1, k); 19 | } 20 | 21 | public static int quickSort(int[] nums, int left, int right, int k){ 22 | int origin_l = left; //left 和 right 移动,但要保存一下原始的值,方便递归调用 23 | int origin_r = right; 24 | int cur = nums[left]; 25 | while(left= cur) //注意要加个=号,上个while加也行,防止重复数字死循环 30 | left++; 31 | nums[right] = nums[left]; 32 | } 33 | nums[left] = cur; 34 | if(left==k-1) return cur; 35 | else if(left>k-1) return quickSort(nums, origin_l, left-1, k); 36 | else return quickSort(nums, left+1, origin_r, k); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/lc217.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.HashSet; 4 | /* 5 | * 217. Contains Duplicate 6 | * 题意:数组中是否有重复的数字 7 | * 难度:Easy 8 | * 分类:Array, Hash Table 9 | * 思路:用Hashset记录是否有重复 10 | * Tips: 11 | */ 12 | public class lc217 { 13 | public boolean containsDuplicate(int[] nums) { 14 | HashSet hs = new HashSet(); 15 | for(int i=0; i getSkyline(int[][] buildings) { 18 | List res = new ArrayList<>(); 19 | int[][] arr = new int[buildings.length*2][2]; 20 | for (int i = 0, j=0; i < buildings.length ; i++) { //转换成坐标 21 | arr[j][0] = buildings[i][0]; 22 | arr[j][1] = buildings[i][2]; 23 | j++; 24 | arr[j][0] = buildings[i][1]; 25 | arr[j][1] = -buildings[i][2]; //结束节点y用负数表示 26 | j++; 27 | } 28 | Arrays.sort(arr, new Comparator() { //定义比较方法 29 | @Override 30 | public int compare(int[] o1, int[] o2) { 31 | if(o1[0]!=o2[0]) 32 | return o1[0] - o2[0]; 33 | else 34 | return o2[1] - o1[1]; //注意这一点,防止 {{0,2,3}, {2,5,3}} case。 两个点重合了不会连续输出。 35 | } 36 | }); 37 | PriorityQueue pr = new PriorityQueue(); 38 | pr.add(0); 39 | int pre = 0; 40 | for (int i = 0; i < arr.length ; i++) { 41 | if(arr[i][1]>0){ 42 | pr.add(-arr[i][1]); //默认是最小优先队列 43 | }else{ 44 | pr.remove(arr[i][1]); 45 | } 46 | if(pr.peek()!=pre){ 47 | res.add(new int[]{arr[i][0], -pr.peek()}); 48 | pre = pr.peek(); 49 | } 50 | } 51 | return res; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /code/lc221.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 221. Maximal Square 4 | * 题意:0,1数组中最大正方形 5 | * 难度:Medium 6 | * 分类:Dynamic Programming 7 | * 思路:三个正方形+上右下角位置,可以组成一个新的正方形 8 | * Tips:和lc85作比较 9 | */ 10 | public class lc221 { 11 | public static void main(String[] args) { 12 | char[][] matrix = {{'1','0','1','0','0'},{'1','0','1','1','1'},{'1','1','1','1','1'},{'1','0','0','1','0'}}; 13 | System.out.println(maximalSquare(matrix)); 14 | } 15 | public static int maximalSquare(char[][] matrix) { 16 | if(matrix.length==0) return 0; 17 | int[][] dp = new int[matrix.length][matrix[0].length]; 18 | int max = 0; 19 | for (int i = 0; i < matrix.length ; i++) { 20 | for (int j = 0; j < matrix[0].length ; j++) { 21 | if(i==0 || j==0) { 22 | dp[i][j] = matrix[i][j]-'0'; 23 | max = Math.max(dp[i][j],max); 24 | } 25 | else{ 26 | if(matrix[i][j]=='1') { 27 | dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; //dp[i][j] 最大正方形边长 28 | max = Math.max(dp[i][j], max); 29 | } 30 | } 31 | } 32 | } 33 | return max*max; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc226.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Stack; 4 | 5 | /* 6 | * 226. Invert Binary Tree 7 | * 题意:反转二叉树 8 | * 难度:Easy 9 | * 分类:Tree 10 | * 思路:递归或迭代,两种思路,都很简单 11 | * Tips: 12 | */ 13 | public class lc226 { 14 | public class TreeNode { 15 | int val; 16 | TreeNode left; 17 | TreeNode right; 18 | TreeNode(int x) { val = x; } 19 | } 20 | public TreeNode invertTree(TreeNode root) { 21 | //递归 22 | if(root==null) return null; 23 | TreeNode temp = root.left; 24 | root.left = root.right; 25 | root.right = temp; 26 | invertTree(root.left); 27 | invertTree(root.right); 28 | return root; 29 | } 30 | 31 | public TreeNode invertTree2(TreeNode root) { 32 | //迭代 33 | if(root==null) 34 | return null; 35 | Stack st = new Stack(); 36 | st.add(root); 37 | while(!st.isEmpty()){ 38 | TreeNode tn = st.pop(); 39 | TreeNode temp = tn.left; 40 | tn.left = tn.right; 41 | tn.right = temp; 42 | if(tn.left!=null) 43 | st.add(tn.left); 44 | if(tn.right!=null) 45 | st.add(tn.right); 46 | } 47 | return root; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/lc227.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Stack; 4 | 5 | /* 6 | * 227. Basic Calculator II 7 | * 题意:表达式计算 8 | * 难度:Medium 9 | * 分类:String 10 | * 思路:很巧妙的方法,每次遍历到下一个符号的时候,计算前一个符号的运算,避免了复杂的逻辑。 11 | * + - 运算直接入栈,* / 运算则计算后将结果入栈,实现了 * / 优先运算 12 | * Tips:自己想的方法会非常麻烦。这个解法非常聪明。 13 | */ 14 | public class lc227 { 15 | public int calculate(String s) { 16 | char[] chs = s.replace(" ","").toCharArray(); 17 | int num = 0; 18 | char sign = '+'; 19 | Stack st = new Stack(); 20 | for (int i = 0; i < chs.length ; i++) { 21 | if(Character.isDigit(chs[i])){ 22 | num = num * 10 + chs[i]-'0'; 23 | } 24 | if( !Character.isDigit(chs[i]) || i==chs.length-1 ){ //遍历到最后,即使不是符号,也要计算 25 | if(sign=='+'){ 26 | st.push(num); 27 | } 28 | else if(sign=='-'){ 29 | st.push(-num); 30 | } 31 | else if(sign=='*'){ 32 | st.push(st.pop()*num); 33 | } 34 | else if(sign=='/'){ 35 | st.push(st.pop()/num); 36 | } 37 | num = 0; 38 | sign = chs[i]; //非常聪明 39 | } 40 | } 41 | int res = 0; 42 | for(Integer i : st){ 43 | System.out.println(i); 44 | res += i; 45 | } 46 | return res; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /code/lc230.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Stack; 4 | 5 | /* 6 | * 230. Kth Smallest Element in a BST 7 | * 题意:二叉搜索树种第k小的数 8 | * 难度:Medium 9 | * 分类:Binary Search, Tree 10 | * 思路:每次找到最小的值,k--。中序遍历。 11 | * Tips:非递归中序遍历还是不熟练。。。 12 | */ 13 | public class lc230 { 14 | public class TreeNode { 15 | int val; 16 | TreeNode left; 17 | TreeNode right; 18 | 19 | TreeNode(int x) { 20 | val = x; 21 | } 22 | } 23 | public int kthSmallest(TreeNode root, int k) { 24 | Stack st = new Stack(); 25 | while(!st.isEmpty()||root!=null){ 26 | while(root!=null) { 27 | st.add(root); 28 | root = root.left; 29 | } 30 | root = st.pop(); 31 | k--; 32 | if(k==0) return root.val; 33 | root = root.right; 34 | } 35 | return 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/lc234.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 234. Palindrome Linked List 4 | * 题意:判断链表是否是回文的 5 | * 难度:Easy 6 | * 分类:LinkedList, Two Pointers 7 | * 思路:反转一半就行了,避免了空间开销 8 | * Tips:很好的题,考了 Two Pointers, 还考了链表反转 9 | * lc5, lc9, lc125, lc131, lc234, lc647 10 | */ 11 | public class lc234 { 12 | public class ListNode { 13 | int val; 14 | ListNode next; 15 | ListNode(int x) { val = x; } 16 | } 17 | 18 | public boolean isPalindrome(ListNode head) { 19 | if(head==null||head.next==null) 20 | return true; 21 | ListNode slow = head; 22 | ListNode fast = head; 23 | while (fast.next != null && fast.next.next != null) { 24 | slow = slow.next; 25 | fast = fast.next.next; 26 | } 27 | ListNode head2 = reverse(slow.next,null); 28 | slow.next = null; //注意截断一下 29 | while(head2!=null&&head!=null){ 30 | if(head2.val!=head.val) 31 | return false; 32 | head = head.next; 33 | head2 = head2.next; 34 | } 35 | return true; 36 | } 37 | public ListNode reverse(ListNode head, ListNode pre){ 38 | ListNode next = head.next; 39 | head.next = pre; 40 | if(next==null) 41 | return head; 42 | return reverse(next, head); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/lc237.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 237. Delete Node in a Linked List 4 | * 题意:删除链表中的一个节点,给的是这个节点,不知道前边的节点 5 | * 难度:Easy 6 | * 分类:Linked List 7 | * 思路:剑指Offer上有,拷贝下一个节点的内容到该节点,删除下一个节点 8 | * Tips: 9 | */ 10 | public class lc237 { 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | 15 | ListNode(int x) { 16 | val = x; 17 | } 18 | } 19 | public void deleteNode(ListNode node) { 20 | node.val = node.next.val; 21 | node.next = node.next.next; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/lc238.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 238. Product of Array Except Self 4 | * 题意:数组中除了nums[i]的乘积 5 | * 难度:Medium 6 | * 分类:Array 7 | * 思路:左右两个方向简单dp,空间压缩以后可以直接迭代的方法算 8 | * Tips: 9 | */ 10 | public class lc238 { 11 | public int[] productExceptSelf(int[] nums) { 12 | int[] res = new int[nums.length]; 13 | res[0] = 1; 14 | for (int i = 1; i < nums.length; i++) { 15 | res[i] = res[i-1]*nums[i-1]; 16 | } 17 | int temp = 1; //用temp记录右边值,每次迭代一下 18 | res[nums.length-1] = res[nums.length-1] * temp; 19 | for (int i = nums.length-2; i>=0 ; i--) { 20 | temp = temp * nums[i+1]; 21 | res[i] = res[i] * temp; 22 | } 23 | return res; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/lc239.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 239. Sliding Window Maximum 4 | * 题意:滑动窗口中最大值 5 | * 难度:Hard 6 | * 分类:Heap 7 | * 思路:用双向队列,保证队列里是递减的。单调队列,好好学习一下。 8 | * Tips:与lc84做比较,84是递增栈 9 | */ 10 | import java.util.Deque; 11 | import java.util.LinkedList; 12 | 13 | public class lc239 { 14 | public static void main(String[] args) { 15 | int nums[] = {-95,92,-85,59,-59,-14,88,-39,2,92,94,79,78,-58,37,48,63,-91,91,74,-28,39,90,-9,-72,-88,-72,93,38,14,-83,-2,21,4,-75,-65,3,63,100,59,-48,43,35,-49,48,-36,-64,-13,-7,-29,87,34,56,-39,-5,-27,-28,10,-57,100,-43,-98,19,-59,78,-28,-91,67,41,-64,76,5,-58,-89,83,26,-7,-82,-32,-76,86,52,-6,84,20,51,-86,26,46,35,-23,30,-51,54,19,30,27,80,45,22}; 16 | int k = 10; 17 | int[] res = maxSlidingWindow(nums,k); 18 | for (int i = 0; i < res.length ; i++) { 19 | System.out.print(res[i]); 20 | System.out.print(','); 21 | } 22 | } 23 | public static int[] maxSlidingWindow(int[] nums, int k) { 24 | if(nums.length==0) 25 | return new int[]{}; 26 | int[] res = new int[nums.length-k+1]; 27 | int cur = 0; 28 | Deque dq = new LinkedList(); //队列里是递减的,存的仍然是下标 29 | for (int i = 0; i < nums.length ; i++) { 30 | if( !dq.isEmpty() && dq.peekFirst()<=i-k) //窗口长度过长了,删掉头 31 | dq.removeFirst(); 32 | while( !dq.isEmpty() && nums[dq.peekLast()]<=nums[i]){// removeLast 不是 First。 自己写的时候这写错了,如果是First的话,有些Case也能过 33 | dq.removeLast(); 34 | } 35 | dq.addLast(i); 36 | if(i>=k-1){ 37 | res[cur] = nums[dq.peekFirst()]; 38 | cur++; 39 | } 40 | } 41 | return res; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc24.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 24. Swap Nodes in Pairs 4 | * 题意:交换相邻的两个节点 5 | * 难度:Medium 6 | * 分类:Linked List 7 | * 思路:递归的方法,递归交换后续节点以后,再交换现在的两个节点 8 | * 非递归的方法,需要保存三个节点,加一个头节点指向head 9 | * Tips: 10 | */ 11 | public class lc24 { 12 | public class ListNode { 13 | int val; 14 | ListNode next; 15 | ListNode(int x) { 16 | val = x; 17 | } 18 | } 19 | 20 | public ListNode swapPairs(ListNode head) { 21 | if( head==null||head.next==null ) return head; 22 | return helper(head); //用递归的方法,因为交换了两个以后,第二个节点的下一个节点必须等后边两个节点交换了以后才知道谁在前 23 | } 24 | public ListNode helper(ListNode head){ 25 | if(head==null) return null; 26 | if(head.next == null) return head; //节点数可能是奇数 27 | ListNode res = head.next; 28 | ListNode ln1 = head, ln2 = head.next, ln3 = ln2.next; 29 | ln2.next = ln1; 30 | ln1.next = helper(ln3); 31 | return res; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/lc240.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 240. Search a 2D Matrix II 4 | * 题意:有序矩阵中搜索值 5 | * 难度:Medium 6 | * 分类:Binary Search, Divide and Conquer 7 | * 思路:两种方法,一种O(mlg(n)),遍历每一行,每行二分查找。另一种O(m+n),从右上角开始移动 8 | * Tips:lc240, lc378 9 | */ 10 | public class lc240 { 11 | public boolean searchMatrix(int[][] matrix, int target) { 12 | if(matrix.length==0) 13 | return false; 14 | int i = 0; 15 | int j = matrix[0].length; 16 | while( i=0 ){ 17 | if(matrix[i][j]==target) 18 | return true; 19 | else if(matrix[i][j]>target) 20 | j--; 21 | else 22 | i++; 23 | } 24 | return false; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /code/lc242.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 242. Valid Anagram 4 | * 题意:字符串t是否为s打乱后的重排列 5 | * 难度:Easy 6 | * 分类:Hash Table, Sort 7 | * 思路:hash table 计算即可,<0了直接返回false 8 | * Tips:和重排列那题联系一下 lc46 9 | */ 10 | public class lc242 { 11 | public boolean isAnagram(String s, String t) { 12 | if(s.length()!=t.length()) return false; 13 | int[] chs = new int[26]; 14 | for(int i=0; i 0) { // 链表反转的思路 30 | ListNode tmp = head.next; 31 | head.next = curr; 32 | curr = head; 33 | head = tmp; 34 | } 35 | head = curr; 36 | } 37 | return head; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/lc26.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 26. Remove Duplicates from Sorted Array 4 | * 题意:移除数组中重复元素 5 | * 难度:Easy 6 | * 分类:Array, Two Pointers 7 | * lc27 8 | */ 9 | public class lc26 { 10 | public static void main(String[] args) { 11 | int[] nums = {0,0,1,1,1,2,2,3,3,4}; 12 | int n = removeDuplicates(nums); 13 | for (int i = 0; i pr = new PriorityQueue<>(); //用Long,防止溢出 17 | pr.add(1L); 18 | long res = 0; 19 | while(n>0){ 20 | res = pr.remove(); 21 | while(pr.size()>0 &&pr.peek()==res ) pr.remove(); //注意可能存在重复的数字 22 | pr.add(res*2); 23 | pr.add(res*3); 24 | pr.add(res*5); 25 | n--; 26 | } 27 | return (int)res; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/lc268.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 268. Missing Number 4 | * 题意:找出 0~n 中少的那个数 5 | * 难度:Easy 6 | * 分类:Array, Math, Bit Manipulation 7 | * 思路:两种巧妙的方法,时间空间都是O(1) 8 | * 异或 9 | * 求和以后,减去所有 10 | * Tips:lc268 lc448 lc287 11 | */ 12 | public class lc268 { 13 | public int missingNumber(int[] nums) { 14 | int res = nums.length*(nums.length+1)/2; 15 | for(int i:nums) res-=i; 16 | return res; 17 | } 18 | public int missingNumber2(int[] nums) { 19 | int res = nums.length; //异或上长度 20 | for(int i=0; i= 2 && lives <= 3) { 24 | board[i][j] = 3; // Make the 2nd bit 1: 01 ---> 11 25 | } 26 | if (board[i][j] == 0 && lives == 3) { 27 | board[i][j] = 2; // Make the 2nd bit 1: 00 ---> 10 28 | } 29 | } 30 | } 31 | 32 | for (int i = 0; i < m; i++) { 33 | for (int j = 0; j < n; j++) { 34 | board[i][j] >>= 1; // Get the 2nd state. 35 | } 36 | } 37 | } 38 | 39 | public int liveNeighbors(int[][] board, int m, int n, int i, int j) { 40 | int lives = 0; 41 | for (int x = Math.max(i - 1, 0); x <= Math.min(i + 1, m - 1); x++) { // 用max,min判断边界 42 | for (int y = Math.max(j - 1, 0); y <= Math.min(j + 1, n - 1); y++) { 43 | lives += board[x][y] & 1; 44 | } 45 | } 46 | lives -= board[i][j] & 1; //减去自己 47 | return lives; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/lc29.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 29. Divide Two Integers 4 | * 题意:不用乘法,除法,取模运算实现除法 5 | * 难度:Medium 6 | * 分类:Math, Binary Search 7 | * 思路:被除数减去除数,除数每次左移一位,也就是*2 来实现类似二分的思想 8 | * Tips:注意下用long类型,以及溢出的情况,注意符号 9 | */ 10 | public class lc29 { 11 | public static void main(String[] args) { 12 | System.out.println(divide(-1010369383,-2147483648)); 13 | } 14 | public static int divide(int dividend, int divisor) { 15 | if(divisor==0||dividend==Integer.MIN_VALUE&&divisor==-1) return Integer.MAX_VALUE; //溢出的话直接返回最小值 16 | int sign; 17 | if( (dividend>0&&divisor>0) || (dividend<0&&divisor<0) ) sign = 1; 18 | else sign = -1; 19 | long dividend2 = Math.abs((long)dividend); //注意这要强制转换成long,再取abs 20 | long divisor2 = Math.abs((long)divisor); 21 | long div = divisor2; 22 | long res = 0; //这里也是long 23 | int p = 0; 24 | while( !(div>dividend2 && div==divisor2) ){ 25 | long temp = dividend2 - div; 26 | if(temp>=0){ 27 | res += Math.pow(2, p); 28 | p++; 29 | div = div << 1; 30 | dividend2 = temp; 31 | }else{ 32 | div = divisor2; 33 | p = 0; 34 | } 35 | } 36 | return (int)res*sign; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/lc295.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.PriorityQueue; 4 | /* 5 | * 295. Find Median from Data Stream 6 | * 题意:流数据中找中位数 7 | * 难度:Hard 8 | * 分类: 9 | * 思路:用两个优先队列,一个保存左半边最大值,一个保存右半边最小值 10 | * 保持左半边最多比右半边多一个数 11 | * Tips: 12 | */ 13 | public class lc295 { 14 | class MedianFinder { 15 | PriorityQueue pq1; //默认是最小,右半边 16 | PriorityQueue pq2; //左半边 17 | 18 | /** initialize your data structure here. */ 19 | public MedianFinder() { 20 | this.pq1 = new PriorityQueue(); 21 | this.pq2 = new PriorityQueue(); 22 | } 23 | 24 | public void addNum(int num) { 25 | pq1.add(num); //两个队列都过一遍 26 | pq2.add(-pq1.poll()); 27 | if (pq1.size() < pq2.size()) //如果中位数是一个数,就存在左半边 28 | pq1.add(-pq2.poll()); 29 | } 30 | 31 | public double findMedian() { 32 | if(pq1.size()==pq2.size()+1) return pq1.peek(); 33 | return -((double)(-pq1.peek()+pq2.peek()))/2; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/lc3.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 3. Longest Substring Without Repeating Characters 4 | * 题意:找出字符串中没有重复字母的最大长度 5 | * 难度:Medium 6 | * 分类:Hash Table, Two Pointers, String 7 | * 算法:两个指针,记录没有重复字母的子串的首和尾 8 | * lc76 9 | */ 10 | import java.util.HashMap; 11 | 12 | public class lc3 { 13 | public static void main(String[] args) { 14 | String s = "abba"; 15 | System.out.println(lengthOfLongestSubstring(s)); 16 | } 17 | 18 | public static int lengthOfLongestSubstring(String s) { 19 | HashMap hm = new HashMap<>(); 20 | int max = 0; 21 | int j = 0; 22 | for (int i = 0; i nums[j]){ 23 | dp[i] = Math.max(dp[j]+1, dp[i]); 24 | } 25 | } 26 | res = Math.max(res, dp[i]); 27 | } 28 | return res; 29 | } 30 | 31 | public int lengthOfLIS2(int[] nums) { 32 | if(nums.length<2) 33 | return nums.length; 34 | int size = 0; //size指dp中递增的长度。 dp[0~i] 表示了长度为 i+1 的递增子数组,且最后一个值是最小值 35 | int[] dp = new int[nums.length]; //dp存储递增的数组,之后更新这个数组。如果x>最后一个值,则插入到末尾,否则更新对应位置上的值为该值。 36 | for (int i = 0; i < nums.length ; i++) { 37 | int left = 0; 38 | int right = size; 39 | while(left!=right){ //得到要插入的位置 40 | int mid = (left+right)/2; 41 | if(dp[mid]0&&nums[ptr-1]>=nums[ptr]){// 注意是 >= {5,1,1} , 等于-- 28 | ptr--; 29 | } 30 | ptr--; 31 | if(ptr!=-1){ 32 | //从后往前找出比第一个x大的数 33 | int val = nums[ptr]; 34 | int ptr2 = nums.length-1; 35 | while(ptr2>ptr){ 36 | if(nums[ptr2]>nums[ptr]) break; 37 | ptr2--; 38 | } 39 | nums[ptr] = nums[ptr2]; 40 | nums[ptr2] = val; 41 | } 42 | 43 | //把之后的数逆序 44 | ReverseNums(nums,ptr+1,nums.length-1); //+1,不包含ptr那个位置 45 | } 46 | public static void ReverseNums(int[] nums, int start, int end){ 47 | int l = end+start; 48 | for (int i = start; i < (start+end+1)/2 ; i++) { 49 | int temp = nums[i]; 50 | nums[i] = nums[l-i]; 51 | nums[l-i] = temp; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /code/lc326.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 326. Power of Three 4 | * 题意:判断该数是否为3的幂 5 | * 难度:Easy 6 | * 分类:Math 7 | * 思路:除以3,除到不能整除,判断是否为1 8 | * Tips: 9 | */ 10 | public class lc326 { 11 | public boolean isPowerOfThree(int n) { 12 | if (n < 1) return false; 13 | while (n % 3 == 0) n /= 3; 14 | return n == 1; 15 | } 16 | public boolean isPowerOfThree2(int n) { 17 | if(n==1) return true; 18 | double d = n; 19 | while(d>1){ 20 | d=d/3; 21 | if(d==1) return true; 22 | } 23 | return false; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/lc328.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 328. Odd Even Linked List 4 | * 题意:奇数的node都在偶数node的后面,第一个节点index为0 5 | * 难度:Medium 6 | * 分类:Linked List 7 | * 思路:while的条件很不好想,记住:这种跳两次的迭代,都判断后边那个节点的 next!=null 为终止条件 8 | * Tips:lc318 9 | */ 10 | public class lc328 { 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | ListNode(int x) { 15 | val = x; 16 | } 17 | } 18 | public ListNode oddEvenList(ListNode head) { 19 | if(head==null||head.next==null) return head; 20 | ListNode even = head; 21 | ListNode odd_head = head.next; 22 | ListNode odd = head.next; 23 | while( odd!=null && odd.next!=null ){ //这个条件很难想通 24 | even.next = even.next.next; 25 | odd.next = odd.next.next; 26 | even = even.next; 27 | odd = odd.next; 28 | } 29 | even.next = odd_head; 30 | return head; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/lc329.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 329. Longest Increasing Path in a Matrix 4 | * 题意:寻找最长的递增路径 5 | * 难度:Hard 6 | * 分类:Depth-first Search, Topological Sort, Memoization 7 | * 思路:带记忆的dfs,之前计算的最优解可以直接合并 8 | * Tips: 9 | */ 10 | public class lc329 { 11 | public int longestIncreasingPath(int[][] matrix) { 12 | if(matrix.length==0) return 0; 13 | int[][] cache = new int[matrix.length][matrix[0].length]; //存储计算过的结果 14 | int res = 0; 15 | for (int i = 0; i < matrix.length ; i++) { 16 | for (int j = 0; j < matrix[0].length ; j++) { 17 | res = Math.max(dfs(matrix, i, j, cache), res); 18 | } 19 | } 20 | return res; 21 | } 22 | 23 | public int dfs(int[][] matrix, int i, int j, int[][] cache){ 24 | int max = 1; 25 | if(cache[i][j]!=0) return cache[i][j]; 26 | if( i>0 && matrix[i-1][j]>matrix[i][j]) max = Math.max(dfs(matrix, i-1, j, cache)+1, max); 27 | if( j>0 && matrix[i][j-1]>matrix[i][j]) max = Math.max(dfs(matrix, i, j-1, cache)+1, max); 28 | if( i+1matrix[i][j]) max = Math.max(dfs(matrix, i+1, j, cache)+1, max); 29 | if( j+1matrix[i][j]) max = Math.max(dfs(matrix, i, j+1, cache)+1, max); 30 | cache[i][j] = max; 31 | return max; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/lc334.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 334. Increasing Triplet Subsequence 4 | * 题意:数组中是否存在递增的3个数 5 | * 难度:Medium 6 | * 分类:Array 7 | * 思路:思路很清奇,自己没想到,时间复杂度O(N),空间是O(1)。其实和lc300 O(nlgn) 解法思路是一样的,只是固定了dp数组长度为两个数。 8 | * Tips:lc300最长递增子序列 9 | */ 10 | public class lc334 { 11 | public boolean increasingTriplet(int[] nums) { 12 | int small = Integer.MAX_VALUE; 13 | int big = Integer.MAX_VALUE; 14 | for (int i = 0; i < nums.length ; i++) { 15 | if(nums[i]target){ 39 | end = mid-1; 40 | }else{ 41 | start = mid; 42 | } 43 | } 44 | if(nums[start]!=target) 45 | return res; 46 | res[1]=end; 47 | return res; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/lc343.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 343. Integer Break 4 | * 题意:给定一个正整数,找出一组数字和为该数,且这组数的乘积最大 5 | * 难度:Medium 6 | * 分类:Math, Dynamic Programming 7 | * 思路:能减3的减3,因为3得到的乘积最大 8 | * Tips: 9 | */ 10 | public class lc343 { 11 | public int integerBreak(int n) { 12 | if(n==2) return 1; 13 | if(n==3) return 2; 14 | return helper(n); 15 | } 16 | 17 | public int helper(int n){ 18 | if(n==2) return 2; 19 | if(n==3) return 3; 20 | if(n==4) return 4; 21 | if(n==5) return 6; 22 | else return helper(n-3)*3; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/lc344.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 344. Reverse String 4 | * 题意:反转字符串 5 | * 难度:Easy 6 | * 分类:Two Pointers, String 7 | * 思路: 8 | * Tips: 9 | */ 10 | public class lc344 { 11 | public void reverseString(char[] s) { 12 | int begin = 0, end = s.length-1; 13 | while(begin res = new ArrayList(); 18 | HashMap hm = new HashMap(); 19 | for (int i : nums1) hm.put(i, hm.getOrDefault(i, 0) + 1); 20 | for (int i : nums2) { 21 | if (hm.getOrDefault(i, 0) > 0) { 22 | res.add(i); 23 | hm.put(i, hm.get(i) - 1); 24 | } 25 | } 26 | int[] res_arr = new int[res.size()]; //toArray方法只能转化为 Integer[] 类型,和返回值不一致 27 | for (int i = 0; i < res_arr.length; i++) { 28 | res_arr[i] = res.get(i); 29 | } 30 | return res_arr; 31 | } 32 | } -------------------------------------------------------------------------------- /code/lc36.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 36. Valid Sudoku 4 | * 题意:横排,竖排,3*3不能包含相同数字 5 | * 难度:Medium 6 | * 分类:Hash Table 7 | * 思路:用一个Set即可,把行号,列号拼上去 8 | * Tips:注意add如果已经有了,返回的是false 9 | */ 10 | import java.util.HashSet; 11 | 12 | public class lc36 { 13 | public boolean isValidSudoku(char[][] board) { 14 | HashSet hs = new HashSet(); // 如果此set已包含该元素,则该调用不更改set并返回false。 15 | for (int i = 0; i < board.length ; i++) { 16 | for (int j = 0; j < board[0].length ; j++) { 17 | if(board[i][j]=='.') continue; 18 | boolean flag1 = hs.add(board[i][j]+"row"+i); 19 | boolean flag2 = hs.add(board[i][j]+"col"+j); 20 | boolean flag3 = hs.add(board[i][j]+"box"+i/3+j/3); 21 | if((!flag1)||(!flag2)||(!flag3)) { 22 | return false; 23 | } 24 | } 25 | } 26 | return true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/lc371.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 371. Sum of Two Integers 4 | * 题意:两个数相加,但不能用 + - 操作符号 5 | * 难度:Easy 6 | * 分类:Bit Maniputation 7 | * 思路:自己没想起来 8 | * https://leetcode.com/problems/sum-of-two-integers/discuss/84278/A-summary%3A-how-to-use-bit-manipulation-to-solve-problems-easily-and-efficiently 9 | * Tips: 10 | */ 11 | public class lc371 { 12 | public int getSum(int a, int b) { 13 | return b==0? a:getSum(a^b, (a&b)<<1); // a^b 为不算进位的结果,加上进位 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /code/lc38.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 38. Count and Say 4 | * 题意:初始输出为1,后续输出为上次输出的读法,求第n次的读法 5 | * 难度:Easy 6 | * 分类:String 7 | * 注意:题意很难懂,读懂题意了就简单了 8 | */ 9 | public class lc38 { 10 | public static void main(String[] args) { 11 | System.out.println(countAndSay(5)); 12 | } 13 | 14 | public static String countAndSay(int n) { 15 | String temp = "1"; 16 | while(n>1){ 17 | temp = Say(temp); 18 | n--; 19 | } 20 | return temp; 21 | } 22 | 23 | public static String Say(String str){ 24 | char[] chars = str.toCharArray(); 25 | StringBuilder res = new StringBuilder(); 26 | int sum =0; 27 | char pre = chars[0]; 28 | for (int i = 0; i < chars.length ; i++) { 29 | if(chars[i]==pre) 30 | sum++; 31 | else{ 32 | res.append(sum); 33 | res.append(pre); 34 | sum = 1; 35 | pre = chars[i]; 36 | } 37 | if(i==chars.length-1){ //注意到字符末尾后要添加一次,因为不会再循环了 38 | res.append(sum); 39 | res.append(pre); 40 | } 41 | } 42 | return res.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/lc384.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 384. Shuffle an Array 4 | * 题意:重排列一个数组,每个值在每个位置的概率都是均匀的 5 | * 难度:Medium 6 | * 分类: 7 | * 思路: 8 | * Tips: 9 | */ 10 | public class lc384 { 11 | public class Solution { 12 | 13 | private int[] nums; 14 | 15 | public Solution(int[] nums) { 16 | this.nums = nums; 17 | } 18 | 19 | /** Resets the array to its original configuration and return it. */ 20 | public int[] reset() { 21 | return nums; 22 | } 23 | 24 | /** Returns a random shuffling of the array. */ 25 | public int[] shuffle() { 26 | int[] rand = new int[nums.length]; 27 | for (int i = 0; i < nums.length; i++){ 28 | int r = (int) (Math.random() * (i+1)); // +1是因为下标从0开始 29 | rand[i] = rand[r]; 30 | rand[r] = nums[i]; 31 | } 32 | return rand; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc387.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 387. First Unique Character in a String 4 | * 题意:第一个没有重复的字符索引 5 | * 难度:Easy 6 | * 分类:Hash Table, String 7 | * 思路: 8 | * Tips: 9 | */ 10 | public class lc387 { 11 | public int firstUniqChar(String s) { 12 | int freq [] = new int[26]; 13 | for(int i = 0; i < s.length(); i ++) 14 | freq [s.charAt(i) - 'a'] ++; 15 | for(int i = 0; i < s.length(); i ++) 16 | if(freq [s.charAt(i) - 'a'] == 1) 17 | return i; 18 | return -1; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/lc39.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /* 7 | * 39. Combination Sum 8 | * 题意:找出和为sum的所有组合 9 | * 难度:Medium 10 | * 分类:Array, Backtracking 11 | * 思路:回溯法 12 | * Tips:向res添加答案时注意要new一个新的List,否则后续循环的操作会影响res中的L; 设置一个start标志,记录上次数组循环到哪了,防止重复集合。 13 | * 和lc46,lc78做比较,46是排列组合,所以不需要start标志,start标志是为了防止相同元素的组合排列不同而当做了另一种 14 | */ 15 | public class lc39 { 16 | public static void main(String[] args) { 17 | int[] candidates = {2,3,6,7}; 18 | int target = 7; 19 | System.out.println(combinationSum(candidates, target).toString()); 20 | } 21 | public static List> combinationSum(int[] candidates, int target) { 22 | List> res = new ArrayList>(); 23 | if(candidates.length==0||target==0) return res; 24 | List l = new ArrayList(); 25 | backtracking(res,candidates,target,l,0,0); 26 | return res; 27 | } 28 | 29 | public static void backtracking(List> res, int[] candidates, int target, List l, int sum, int start){ 30 | for (int i = start; i < candidates.length; i++) { 31 | l.add(candidates[i]); 32 | if(sum+candidates[i]==target) { 33 | res.add(new ArrayList<>(l));//new 新的 List 34 | } else if(sum+candidates[i](){ 26 | @Override 27 | public int compare(int[] o1, int[] o2){ 28 | return o1[0]!=o2[0]?-o1[0]+o2[0]:o1[1]-o2[1]; //按身高降序排序,如果身高相同,则按前边有几个人增序排序 29 | } 30 | }); 31 | List res = new LinkedList<>(); 32 | for(int[] cur : people){ 33 | res.add(cur[1],cur); //用于在列表的指定位置插入指定元素,并将当前处于该位置的元素及其后续元素的索引加1 34 | } 35 | return res.toArray(new int[people.length][]); //list转array,需要传入一个array对象 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/lc41.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 41. First Missing Positive 4 | * 题意:返回数组中最小的未出现的正整数 5 | * 难度:Hard 6 | * 分类:Array 7 | * 思路:未出现的正整数一定在 [1~nums.length+1] 中,理解了这一点就好做了 8 | * Tips: 9 | */ 10 | public class lc41 { 11 | public static void main(String[] args) { 12 | int[] nums = {1,1}; 13 | System.out.println(firstMissingPositive(nums)); 14 | } 15 | public static int firstMissingPositive(int[] nums) { 16 | for (int i = 0; i < nums.length ; i++) { 17 | if(nums[i]>0&&nums[i]<=nums.length&&nums[nums[i]-1]!=nums[i]){ //第三个判断条件判断要交换的位置上是否已经就为了,防止重复元素死循环 18 | int temp = nums[nums[i]-1]; 19 | nums[nums[i]-1] = nums[i]; 20 | nums[i] = temp; 21 | i--; 22 | } 23 | } 24 | for (int i = 0; i < nums.length ; i++) { 25 | if(nums[i]!=i+1) 26 | return i+1; 27 | } 28 | return nums.length+1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/lc412.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | /* 6 | * 412. Fizz Buzz 7 | * 题意:遇到3就Fizz,5就Buzz,既能被3又能被5就FizzBuzz 8 | * 难度:Easy 9 | * 分类: 10 | * 思路:避免来回除,自下向上 11 | * Tips: 12 | */ 13 | public class lc412 { 14 | public List fizzBuzz(int n) { 15 | List ret = new ArrayList(n); 16 | for(int i=1,fizz=0,buzz=0;i<=n ;i++){ 17 | fizz++; 18 | buzz++; 19 | if(fizz==3 && buzz==5){ 20 | ret.add("FizzBuzz"); 21 | fizz=0; 22 | buzz=0; 23 | }else if(fizz==3){ 24 | ret.add("Fizz"); 25 | fizz=0; 26 | }else if(buzz==5){ 27 | ret.add("Buzz"); 28 | buzz=0; 29 | }else{ 30 | ret.add(String.valueOf(i)); 31 | } 32 | } 33 | return ret; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc43.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 43. Multiply Strings 4 | * 题意:大数相乘 5 | * 难度:Medium 6 | * 分类:Math, String 7 | * 思路:每个位置上的数字都相乘,把位置排好,加起来 8 | * https://leetcode.com/problems/multiply-strings/discuss/17605/Easiest-JAVA-Solution-with-Graph-Explanation 9 | * Tips:挺难的,好多细节 10 | */ 11 | public class lc43 { 12 | public String multiply(String num1, String num2) { 13 | int[] res = new int[num1.length()+num2.length()]; //最高位 index 是 0 14 | for (int i = num1.length()-1; i>=0 ; i--) { //从后往前,解决重复进位 15 | for (int j = num2.length()-1; j>=0 ; j--) { 16 | int a = i+j; 17 | int b = i+j+1; 18 | int mul = (num1.charAt(i) -'0') * (num2.charAt(j) - '0'); 19 | mul += res[b]; //解决进位 20 | res[b] = mul%10; //右边的直接=,因为上一步已经+了 21 | res[a] += mul/10; //左边+= 22 | } 23 | } 24 | StringBuilder sb = new StringBuilder(); 25 | for(int i:res) if(!(sb.length()==0&&i==0)) sb.append(i); 26 | return sb.length() == 0 ? "0" : sb.toString(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/lc438.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 438. Find All Anagrams in a String 4 | * 题意:匹配相同字符组成的串 5 | * 难度:Easy 6 | * 分类:Hash Table 7 | * 思路:滑动窗口,O(n)时间 8 | * Tips:滑动窗口解法 https://leetcode.com/problems/find-all-anagrams-in-a-string/discuss/92007/Sliding-Window-algorithm-template-to-solve-all-the-Leetcode-substring-search-problem 9 | * lc76类似 10 | */ 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.List; 14 | 15 | public class lc438 { 16 | public static void main(String[] args) { 17 | System.out.println(findAnagrams("cbaebabacd", "abc")); 18 | } 19 | public static List findAnagrams(String s, String p) { 20 | List ls = new ArrayList<>(); 21 | if(s.length() hm = new HashMap(); 24 | for (int i = 0; i < p.length() ; i++) { 25 | hm.put(p.charAt(i), hm.getOrDefault(p.charAt(i), 0)+1); 26 | } 27 | int right = 0, left = 0, count = 0; 28 | while(right=0) //注意count++的条件,多余的相同字符不用++了 34 | count++; 35 | } 36 | if(count==p.length()) 37 | ls.add(left); 38 | if(right-left+1==p.length()){ //左指针需要右移 39 | if(hm.containsKey(ch_l)){ 40 | hm.put(ch_l, hm.get(ch_l)+1); 41 | if(hm.get(ch_l)>0) //count--的条件 42 | count--; 43 | } 44 | left++; 45 | } 46 | right++; 47 | } 48 | return ls; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /code/lc44.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 44. Wildcard Matching 4 | * 题意:通配符匹配 5 | * 难度:Hard 6 | * 分类:String, Dynamic Programming, Backtracking, Greedy 7 | * 思路:二维dp,和lc10很像,比lc10要简单一些。空间还可以压缩。 8 | * Tips:bingo 9 | */ 10 | public class lc44 { 11 | public static void main(String[] args) { 12 | System.out.println(isMatch("cb","?b")); 13 | } 14 | public static boolean isMatch(String s, String p) { 15 | boolean[][] dp = new boolean[s.length()+1][p.length()+1]; 16 | dp[0][0] = true; 17 | char[] s_ch = s.toCharArray(); 18 | char[] p_ch = p.toCharArray(); 19 | for (int i = 0; i < p.length() ; i++) { 20 | if(p_ch[i]=='*') dp[0][i+1]=true; 21 | else break; 22 | } 23 | for (int i = 1; i <= s.length() ; i++) { 24 | for (int j = 1; j <= p.length() ; j++) { 25 | if(s_ch[i-1]==p_ch[j-1] || p_ch[j-1]=='?') dp[i][j] = dp[i-1][j-1]; 26 | if(p_ch[j-1]=='*') dp[i][j] = dp[i-1][j-1] || dp[i-1][j] || dp[i][j-1]; 27 | //dp[i-1][j-1] *任意第一个字符 28 | //dp[i-1][j] *匹配后续任意 29 | //dp[i][j-1] *匹配空 30 | } 31 | } 32 | return dp[s.length()][p.length()]; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/lc448.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /* 7 | * 448. Find All Numbers Disappeared in an Array 8 | * 题意:数组长度为n,数组中数字取值为1~n,有些数字可能出现多次,有些可能不出现,找出未出现的数字 9 | * 难度:Easy 10 | * 分类:Array 11 | * 思路:把对应的数字放到对应的位置,最后遍历一遍,如果位置和数字不对应,则为缺失的值。 12 | * Tips:lc268 lc448 lc287 13 | */ 14 | public class lc448 { 15 | public static void main(String[] args) { 16 | System.out.println(findDisappearedNumbers(new int[]{4,3,2,7,8,2,3,1})); 17 | } 18 | public static List findDisappearedNumbers(int[] nums) { 19 | for (int i = 0; i < nums.length ; i++) { 20 | if(nums[i]-1!=i && nums[nums[i]-1]!=nums[i]) { 21 | int temp = nums[i]; 22 | nums[i] = nums[temp-1]; 23 | nums[temp-1] = temp; 24 | i--; 25 | } 26 | } 27 | List res = new ArrayList<>(); 28 | for (int i = 0; i < nums.length ; i++) { 29 | if(nums[i]!=i+1) 30 | res.add(i+1); 31 | } 32 | return res; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/lc454.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.HashMap; 4 | 5 | /* 6 | * 454. 4Sum II 7 | * 题意:从4个数组中各挑一个数,使得和为0 8 | * 难度:Medium 9 | * 分类:Hash Table, Binary Search 10 | * 思路:自己没想起来,看了答案后感觉很无聊 11 | * 两个集合暴力求出所有和的可能,然后2Sum的思路,利用Hashmap即可 12 | * 其实是利用了二分的思想,把4个数的和变为两个2个数的和 13 | * Tips: 14 | */ 15 | public class lc454 { 16 | public int fourSumCount(int[] A, int[] B, int[] C, int[] D) { 17 | HashMap hm = new HashMap(); 18 | int res=0; 19 | for(int i=0; i> permute(int[] nums) { 20 | List> res = new ArrayList<>(); 21 | backtracking(res,nums,new ArrayList()); 22 | return res; 23 | } 24 | public static void backtracking(List> res, int[] nums, List l){ 25 | if(l.size()==nums.length){ 26 | res.add(new ArrayList<>(l)); 27 | return; 28 | } 29 | 30 | for (int i = 0; i < nums.length ; i++) { 31 | if(l.contains((Integer)nums[i])) //防止相同的元素再次添加 32 | continue; 33 | l.add(nums[i]); 34 | backtracking(res,nums,l); 35 | l.remove((Integer)nums[i]); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /code/lc461.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 461. Hamming Distance 4 | * 题意:转换为2进制,有几个位置上的值不同,就叫做Hamming distance 5 | * 难度:Easy 6 | * 分类:Bit Maniputation 7 | * 思路:异或运算可以直接得出异或后二进制的结果,再统计1的个数即可 8 | * Tips: 9 | */ 10 | public class lc461 { 11 | public int hammingDistance(int x, int y) { 12 | int num = x^y; 13 | int res = 0; 14 | while(num>0){ 15 | res += num%2; 16 | num /= 2; 17 | } 18 | return res; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/lc48.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 48. Rotate Image 4 | * 题意:将数组顺时针翻转90度 5 | * 难度:Medium 6 | * 分类:Array 7 | * 思路:两种思路:先对角,再以竖轴对称;先以横轴对称,再对角.思路很新奇,记一下. 8 | */ 9 | public class lc48 { 10 | public static void main(String[] args) { 11 | int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 12 | printArr(matrix); 13 | rotate(matrix); 14 | System.out.println(); 15 | printArr(matrix); 16 | } 17 | public static void rotate(int[][] matrix) { 18 | for (int i = 0; i > groupAnagrams(String[] strs) { 14 | HashMap> m = new HashMap(); 15 | for (int i = 0; i < strs.length ; i++) { 16 | char[] chs = strs[i].toCharArray(); 17 | Arrays.sort(chs); //对字符串排序 18 | String key = String.valueOf(chs); 19 | if(m.containsKey(key)) 20 | m.get(key).add(strs[i]); 21 | else { 22 | ArrayList l = new ArrayList(); 23 | l.add(strs[i]); 24 | m.put(key,l); 25 | } 26 | } 27 | return new ArrayList(m.values()); //学下这句的语法 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/lc494.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 494. Target Sum 4 | * 题意:给数组中的元素赋加减号,使得和为target的分配方案有几种 5 | * 难度:Medium 6 | * 分类:Dynamic Programming, Depth-first Search 7 | * 思路:可以用递归+mem的方法。也可以转化为0,1背包问题,注意dp的时候把下标移位。另一种方法是转化为子数组的和为(target + sum(nums))/2的问题,求解方法类似lc416 8 | * Tips:多抽象总结一下相关的问题,如何抽象出背包。对于这个数字,要么+,要么-,就两种情况。https://leetcode.com/problems/target-sum/discuss/97335/Short-Java-DP-Solution-with-Explanation 9 | * dp[i][j] 表示前i个元素和为j的方案个数 10 | * dp[i][j] = dp[i-1][j-nums[j]] + dp[i-1][j+nums[j]] //加减两种方案加起来 11 | * lc416, lc494 12 | */ 13 | public class lc494 { 14 | public int findTargetSumWays(int[] nums, int S) { 15 | int sum = 0; 16 | for (int i : nums) { 17 | sum += i; 18 | } 19 | if(S>sum||S<-sum) 20 | return 0; 21 | int[] dp = new int[sum*2+1]; //还有0,所以+1 22 | dp[sum] = 1; 23 | for (int i = 0; i < nums.length ; i++) { 24 | int[] dp2 = new int[sum*2+1]; 25 | for (int j = 0; j < dp.length ; j++) { 26 | if(j+nums[i]=0) 29 | dp2[j-nums[i]] += dp[j]; 30 | } 31 | dp = dp2; 32 | } 33 | return dp[S+sum]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc5.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 5. Longest Palindromic Substring 4 | * 题意:找出给定字符串中最长的回文串 5 | * 难度:Medium 6 | * 分类:String, Dynamic Programming 7 | * Tips:从后往前遍历,保证后续dp时,子情况已计算出 8 | * 还有一种思路是从中间往两边扩展,中间有两种情况,一种一个字符,一种两个字符 9 | * lc5, lc9, lc125, lc131, lc234, lc647 10 | */ 11 | public class lc5 { 12 | public static void main(String[] args) { 13 | String s = "cbbd"; 14 | System.out.println(longestPalindrome(s)); 15 | } 16 | 17 | public static String longestPalindrome(String s) { 18 | int n = s.length(); 19 | boolean[][] dp = new boolean[n][n]; 20 | String res = ""; 21 | for (int i = n-1; i>=0 ; i--) { 22 | for (int j = i; j res.length()) 27 | res = s.substring(i,j+1); // 起始索引,终止索引(不包括,所以+1) 28 | } 29 | } 30 | } 31 | return res; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/lc50.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 50. Pow(x, n) 4 | * 题意:幂运算 5 | * 难度:Medium 6 | * 分类:Math, Binary Search 7 | * 思路:和lc29的思路类似,数值上的二分。用前一步的结果进行下一步的运算,降低了迭代次数 8 | * Tips:注意溢出的情况,负数的情况。 9 | */ 10 | public class lc50 { 11 | public double myPow(double x, int n) { 12 | if(n == 0) return 1; 13 | if(n==Integer.MIN_VALUE && x!=1 && x!=-1) return 0; //负数最小值,结果溢出 14 | if(n<0){ 15 | n = -n; 16 | x = 1/x; //负数变成 1/x 17 | } 18 | return (n%2 == 0) ? myPow(x*x, n/2) : x*myPow(x*x, n/2); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/lc51.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 51. N-Queens 4 | * 题意:8皇后问题 5 | * 难度:Hard 6 | * 分类:Backtracking 7 | * 思路:回溯+判断,注意怎么判断两个斜线方向 8 | * Tips:lc52 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.HashSet; 12 | import java.util.List; 13 | 14 | public class lc51 { 15 | StringBuilder ss = new StringBuilder(); 16 | HashSet hs = new HashSet(); 17 | public List> solveNQueens(int n) { 18 | for (int i = 0; i < n-1 ; i++) { 19 | ss.append("."); 20 | } 21 | return dfs(new ArrayList<>(), new ArrayList(), n, 0); 22 | } 23 | 24 | public List> dfs(List> res, List curr, int n, int row){ 25 | if(row==n){ 26 | res.add(new ArrayList<>(curr)); 27 | return res; 28 | } 29 | for (int i = 0; i < n ; i++) { 30 | if(isValid(row, i)){ 31 | curr.add(new StringBuilder(ss).insert(i,"Q").toString()); 32 | int a = row+i; // row+col 作为key 33 | int b = row-i; // row-col 作为key 34 | hs.add("row"+row); hs.add("col"+i); hs.add("k1"+a); hs.add("k2"+b); 35 | dfs(res, curr, n, row+1); 36 | curr.remove(curr.size()-1); 37 | hs.remove("row"+row); hs.remove("col"+i); hs.remove("k1"+a); hs.remove("k2"+b); //别忘了删掉 38 | } 39 | } 40 | return res; 41 | } 42 | 43 | public boolean isValid(int row, int col){ 44 | int a = row+col; 45 | int b = row-col; 46 | if(hs.contains("row"+row)||hs.contains("col"+col)||hs.contains("k1"+a)||hs.contains("k2"+b)) return false; 47 | return true; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/lc52.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.HashSet; 4 | /* 5 | * 52. N-Queens II 6 | * 题意:8皇后问题 7 | * 难度:Hard 8 | * 分类:Backtracking 9 | * 思路:和 lc51 一样,输出变为种类数,反而简单了 10 | * Tips: 11 | */ 12 | public class lc52 { 13 | HashSet hs = new HashSet(); 14 | int res = 0; 15 | public int totalNQueens(int n) { 16 | dfs(n, 0); 17 | return res; 18 | } 19 | 20 | public void dfs(int n, int row){ 21 | if(row==n){ 22 | res++; 23 | } 24 | for (int i = 0; i < n ; i++) { 25 | if(isValid(row, i)){ 26 | int a = row+i; // row+col 作为key 27 | int b = row-i; // row-col 作为key 28 | hs.add("row"+row); hs.add("col"+i); hs.add("k1"+a); hs.add("k2"+b); 29 | dfs(n, row+1); 30 | hs.remove("row"+row); hs.remove("col"+i); hs.remove("k1"+a); hs.remove("k2"+b); //别忘了删掉 31 | } 32 | } 33 | } 34 | 35 | public boolean isValid(int row, int col){ 36 | int a = row+col; 37 | int b = row-col; 38 | if(hs.contains("row"+row)||hs.contains("col"+col)||hs.contains("k1"+a)||hs.contains("k2"+b)) return false; 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/lc53.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 53. Maximum Subarray 4 | * 题意:最大连续子序列和 5 | * 难度:Easy 6 | * 分类:Array, Divide and Conquer, Dynamic Programming 7 | * 注意:分治方法如何进行merge,merge时,必须包含mid元素,因为是连续子序列 8 | * lc978 9 | */ 10 | public class lc53 { 11 | public static void main(String[] args) { 12 | int[] nums = {-2,1,-3,4,-1,2,1,-5,4}; 13 | System.out.println(maxSubArray(nums)); 14 | System.out.println(maxSubArray2(nums)); 15 | } 16 | 17 | public static int maxSubArray(int[] nums) { 18 | // dp[i] 表示以nums[i]结尾的最大和 19 | int[] dp = new int[nums.length]; 20 | dp[0] = nums[0]; 21 | int res = dp[0]; 22 | for (int i = 1; i 0 ? dp[i-1]+nums[i] : nums[i]; 24 | res = Math.max(res,dp[i]); 25 | } 26 | return res; 27 | } 28 | 29 | public static int maxSubArray2(int[] nums) { 30 | return DivideConquer(nums,0,nums.length-1); 31 | } 32 | 33 | public static int DivideConquer(int[] nums, int start, int end){ 34 | if(start == end) 35 | return nums[start]; 36 | else{ 37 | int mid = (start+end)/2; 38 | int left = DivideConquer(nums, start, mid); 39 | int right = DivideConquer(nums, mid+1, end); 40 | int temp = 0; 41 | int lmax = nums[mid]; 42 | for (int i = mid; i >=start ; i--) { 43 | temp += nums[i]; 44 | lmax = Math.max(temp,lmax); 45 | } 46 | temp = 0; 47 | int rmax = nums[mid+1]; 48 | for (int i = mid+1; i <= end ; i++) { 49 | temp += nums[i]; 50 | rmax = Math.max(temp,rmax); 51 | } 52 | return Math.max(Math.max(left,right),lmax+rmax); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /code/lc538.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 538. Convert BST to Greater Tree 4 | * 题意:二叉搜索树,让节点上的值+上所有比它大的值 5 | * 难度:Easy 6 | * 分类:Tree 7 | * 思路:因为是二叉搜索树,右,中,左,这样遍历就可以最大的值递减遍历出结果了。 8 | * 记住,不好递归返回值的,直接设置一个全局变量即可,简单方便。全局变量,全局变量,全局变量!!! 9 | * Tips: 10 | */ 11 | public class lc538 { 12 | public class TreeNode { 13 | int val; 14 | TreeNode left; 15 | TreeNode right; 16 | TreeNode(int x) { val = x; } 17 | } 18 | int sum = 0; 19 | public TreeNode convertBST(TreeNode root) { 20 | if(root==null) return null; 21 | convertBST(root.right); 22 | sum += root.val; 23 | root.val = sum; 24 | convertBST(root.left); 25 | return root; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /code/lc542.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 542. 01 Matrix 4 | * 题意:0,1矩阵,每个点找离自己最近的0的距离 5 | * 难度:Medium 6 | * 分类:Depth-first Search, Breadth-first Search 7 | * 思路:广度优先搜索 8 | * Tips: 9 | */ 10 | import java.util.LinkedList; 11 | import java.util.Queue; 12 | 13 | public class lc542 { 14 | public int[][] updateMatrix(int[][] matrix) { 15 | Queue qu = new LinkedList(); 16 | for(int i=0; i=matrix.length||cur_col<0||cur_col>=matrix[0].length||matrix[cur_row][cur_col]<=matrix[cell[0]][cell[1]]+1) continue; 32 | matrix[cur_row][cur_col] = matrix[cell[0]][cell[1]]+1; 33 | qu.add(new int[]{cur_row,cur_col}); 34 | } 35 | } 36 | return matrix; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/lc543.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 543. Diameter of Binary Tree 4 | * 题意:树中的最长路径 5 | * 难度:Easy 6 | * 分类:Tree 7 | * 思路:和lc124思路一样,但lc124是Hard,这道竟然是Easy,哈哈哈 8 | * Tips: 9 | */ 10 | public class lc543 { 11 | public class TreeNode { 12 | int val; 13 | TreeNode left; 14 | TreeNode right; 15 | TreeNode(int x) { val = x; } 16 | } 17 | int max = 0; 18 | public int diameterOfBinaryTree(TreeNode root) { 19 | helper(root); 20 | return max; 21 | } 22 | public int helper(TreeNode root){ 23 | if(root==null) 24 | return 0; 25 | int left = helper(root.left); 26 | int right = helper(root.right); 27 | max = Math.max(left+right, max); 28 | return Math.max(left, right)+1; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/lc55.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 55. Jump Game 4 | * 题意:数组中存储能走的最大步数,问是否能从数组开始走到数组结尾 5 | * 难度:Medium 6 | * 分类:Array, Greedy 7 | * 思路:因为只要有一条路径走到就可以,不需要计算所有的路径,所以用贪心的方法. 8 | * Tips:很经典的题目,记忆一下 9 | */ 10 | public class lc55 { 11 | public static void main(String[] args) { 12 | int[] arr = {3,2,1,0,4}; 13 | System.out.println(canJump(arr)); 14 | } 15 | public static boolean canJump(int[] nums) { 16 | int des = nums.length-1; 17 | for (int i = nums.length-1 ; i >=0 ; i--) { 18 | if(i + nums[i] >= des) 19 | des = i; 20 | } 21 | return des == 0; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/lc559.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.List; 4 | 5 | /* 6 | * 559. Maximum Depth of N-ary Tree 7 | * 题意:多叉树的最大深度 8 | * 难度:Easy 9 | * 分类:Tree, Depth-first Search, Breadth-first Search 10 | * 思路:BFS 也能做和 lc104思路一样 11 | * Tips:lc104, lc111 12 | */ 13 | 14 | public class lc559 { 15 | class Node { 16 | public int val; 17 | public List children; 18 | 19 | public Node() {} 20 | 21 | public Node(int _val,List _children) { 22 | val = _val; 23 | children = _children; 24 | } 25 | } 26 | 27 | public int maxDepth(Node root) { 28 | if(root==null) return 0; 29 | int res = 0; 30 | for (Node nd : root.children) { 31 | res = Math.max(maxDepth(nd), res); 32 | } 33 | return res+1; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /code/lc56.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 56. Merge Intervals 4 | * 题意:区间合并 5 | * 难度:Medium 6 | * 分类:Array, Sort 7 | * 思路:排序以后,遍历一遍就可以了 8 | * Tips:对象的排序问题,转化为了数组,再把数组排序; java8可以用类似lambda表达式的方式排序; Collection实现Comparator排序 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | public class lc56 { 15 | 16 | // Collection.sort 17 | /* Collections.sort(intervals, new Comparator(){ 18 | @Override 19 | public int compare(Interval obj0, Interval obj1) { 20 | return obj0.start - obj1.start; 21 | } 22 | });*/ 23 | 24 | // lambda 表达式 25 | // intervals.sort((i1, i2) -> Integer.compare(i1.start, i2.start)); 26 | 27 | public class Interval { 28 | int start; 29 | int end; 30 | Interval() { start = 0; end = 0; } 31 | Interval(int s, int e) { start = s; end = e; } 32 | } 33 | 34 | public List merge(List intervals) { 35 | List res = new ArrayList(); 36 | if(intervals.size()==0) 37 | return res; 38 | int[] starts = new int[intervals.size()]; 39 | int[] ends = new int[intervals.size()]; 40 | for (int i = 0; i < intervals.size() ; i++) { 41 | starts[i] = intervals.get(i).start; 42 | ends[i] = intervals.get(i).end; 43 | } 44 | Arrays.sort(starts); 45 | Arrays.sort(ends); 46 | for (int i = 1; i < starts.length ; i++) { //注意下这里的操作 47 | if(starts[i]<=ends[i-1]){ 48 | starts[i] = starts[i-1]; 49 | }else{ 50 | res.add(new Interval(starts[i-1],ends[i-1])); 51 | } 52 | } 53 | res.add(new Interval(starts[starts.length-1],ends[starts.length-1])); //把最后一个区间也加上 54 | return res; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /code/lc560.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.HashMap; 4 | 5 | /* 6 | * 560. Subarray Sum Equals K 7 | * 题意:连续子数组的和等于k的个数 8 | * 难度:Medium 9 | * 分类:Array, Hash Table 10 | * 思路:求出累加和存在hashmap中,如果当前hashmap中存在sum-k,那么就是一个解 11 | * Tips:经典思路,记一下。lc437有类似思想。 12 | * lc303, lc437, lc560 13 | */ 14 | public class lc560 { 15 | public int subarraySum(int[] nums, int k) { 16 | HashMap hs = new HashMap(); 17 | hs.put(0,1); 18 | int res = 0; 19 | for (int sum = 0, i = 0; i < nums.length ; i++) { 20 | sum += nums[i]; 21 | res += hs.getOrDefault(sum-k,0); // sum1+sum2 = k ,说明sum2-sum1那一段是一个解 22 | hs.put(sum, hs.getOrDefault(sum,0)+1); 23 | } 24 | return res; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /code/lc572.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 572. Subtree of Another Tree 4 | * 题意:判断一棵树是否为另外一棵树的子树 5 | * 难度:Easy 6 | * 分类:Tree 7 | * 思路:两种方法,一种是先序遍历,然后比较字符串即可,注意每个节点开始前加个字符,null也要加进去。 8 | * 另一种递归的方法。 9 | * lc437 lc572 一样的递归思路 10 | * lc297 序列化 11 | * Tips: 12 | */ 13 | public class lc572 { 14 | public class TreeNode { 15 | int val; 16 | TreeNode left; 17 | TreeNode right; 18 | TreeNode(int x) { val = x; } 19 | } 20 | 21 | public boolean isSubtree(TreeNode s, TreeNode t) { 22 | if( s==null || t==null ) return s==t; 23 | return helper(s,t) || isSubtree(s.left, t) || isSubtree(s.right, t); // 注意递归方法的不同,是调用哪个函数 24 | } 25 | public boolean helper(TreeNode s, TreeNode t){ 26 | if( s==null || t==null ) return s==t; 27 | return s.val==t.val && helper(s.left, t.left) && helper(s.right, t.right); 28 | } 29 | 30 | public boolean isSubtree2(TreeNode s, TreeNode t) { 31 | StringBuilder tree1 = new StringBuilder(); 32 | StringBuilder tree2 = new StringBuilder(); 33 | helper2(s, tree1); 34 | helper2(s, tree2); 35 | return tree1.toString().contains(tree2.toString()); 36 | } 37 | public void helper2(TreeNode node, StringBuilder res){ 38 | if(node==null) 39 | res.append(",#"); //先放','表示一个新节点的开始,#代表null 40 | else { 41 | res.append( ","+node.val ); 42 | helper2(node.left, res); 43 | helper2(node.right, res); 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /code/lc58.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 58. Length of Last Word 4 | * 题意:最后一个单词的长度 5 | * 难度:Easy 6 | * 分类:String 7 | * 注意:要考虑空字符,串首尾空格等情况 8 | */ 9 | public class lc58 { 10 | public static void main(String[] args) { 11 | System.out.println(lengthOfLastWord("aaa")); 12 | } 13 | 14 | public static int lengthOfLastWord(String s) { 15 | int pointer = s.length()-1; 16 | while(pointer>=0 && s.charAt(pointer)==' ') 17 | pointer--; 18 | int end = pointer; 19 | while( pointer>=0 && s.charAt(pointer)!=' ') 20 | pointer--; 21 | return end-pointer; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /code/lc581.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 581. Shortest Unsorted Continuous Subarray 4 | * 题意:找出数组中需要排序的长度 5 | * 难度:Easy 6 | * 分类:Array 7 | * 思路: 8 | * Tips:直接写出来的 9 | */ 10 | public class lc581 { 11 | public int findUnsortedSubarray(int[] nums) { 12 | if(nums.length<2) 13 | return 0; 14 | int left =0, right = 0; 15 | int temp = nums[nums.length-1]; 16 | for (int i = nums.length-2; i >=0 ; i--) { 17 | if(nums[i]>temp) left = i; //小于最小值就不用排序了,大于的话记录一下 18 | if(nums[i]temp) temp = nums[i]; 24 | } 25 | return left==right? 0 : right-left+1; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /code/lc589.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /* 7 | * 589. N-ary Tree Preorder Traversal 8 | * 题意:多叉树先序遍历 9 | * 难度:Easy 10 | * 分类:Tree 11 | * 思路: 12 | * Tips: 13 | */ 14 | public class lc589 { 15 | class Node { 16 | public int val; 17 | public List children; 18 | 19 | public Node() {} 20 | 21 | public Node(int _val,List _children) { 22 | val = _val; 23 | children = _children; 24 | } 25 | } 26 | 27 | List res; 28 | public List preorder(Node root) { 29 | res = new ArrayList<>(); 30 | helper(root); 31 | return res; 32 | } 33 | 34 | public void helper(Node root){ 35 | if(root==null) return; 36 | res.add(root.val); 37 | for(Node nd:root.children){ 38 | helper(nd); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/lc590.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class lc590 { 7 | class Node { 8 | public int val; 9 | public List children; 10 | 11 | public Node() {} 12 | 13 | public Node(int _val,List _children) { 14 | val = _val; 15 | children = _children; 16 | } 17 | } 18 | 19 | List res; 20 | public List postorder(Node root) { 21 | res = new ArrayList<>(); 22 | helper(root); 23 | return res; 24 | } 25 | 26 | public void helper(Node root){ 27 | if(root==null) return; 28 | for(Node nd:root.children){ 29 | helper(nd); 30 | } 31 | res.add(root.val); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/lc617.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 617. Merge Two Binary Trees 4 | * 题意:合并两个二叉树 5 | * 难度:Easy 6 | * 分类:Tree 7 | * 思路:递归的方法 8 | * Tips:对比下自己的代码和别人的代码,为什么别人的更简洁。自己的思路还是有些乱,应该先想清楚递归的子问题,再开始写。 9 | * 想明白了再写,不要修修补补的。 10 | */ 11 | public class lc617 { 12 | public class TreeNode { 13 | int val; 14 | TreeNode left; 15 | TreeNode right; 16 | TreeNode(int x) { val = x; } 17 | } 18 | public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { 19 | if(t1==null) return t2; 20 | if(t2==null) return t1; 21 | if(t1!=null && t2!=null) t1.val = t1.val + t2.val; 22 | helper(t1, t2); 23 | return t1; 24 | } 25 | public void helper(TreeNode t1, TreeNode t2){ 26 | if(t1.left==null) { 27 | t1.left = t2.left; 28 | return; 29 | } 30 | if(t1.right==null) { 31 | t1.right = t2.right; 32 | return; 33 | } 34 | if( t1.left!=null && t2.left!=null ) { 35 | t1.left.val = t1.left.val + t2.left.val; 36 | helper(t1.left, t2.left); 37 | } 38 | if( t1.right!=null && t2.right!=null ) { 39 | t1.right.val = t1.right.val + t2.right.val; 40 | helper(t1.right, t2.right); 41 | } 42 | } 43 | 44 | public TreeNode mergeTrees2(TreeNode t1, TreeNode t2) { 45 | if(t1==null) return t2; //这里注意一下,比较难想明白,可以记一下 46 | if(t2==null) return t1; 47 | t1.left = mergeTrees(t1.left, t2.left); //搞定下层指针 48 | t1.right = mergeTrees(t1.right, t2.right); //前边判断过了,两个都不为null 49 | t1.val += t2.val; 50 | return t1; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /code/lc62.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 62. Unique Paths 4 | * 题意:求从数组[0,0]走到[m,n]的不同路径数 5 | * 难度:Medium 6 | * 分类:Array, Dynamic Programming 7 | * 思路:和lc63, lc64思路一样, arr存储的内容由路径数换成了和 8 | */ 9 | public class lc62 { 10 | public static void main(String[] args) { 11 | System.out.println(uniquePaths(7,3)); 12 | } 13 | 14 | public static int uniquePaths(int m, int n) { 15 | int[][] arr = new int[m][n]; 16 | for (int i = 0; i < m ; i++) { 17 | for (int j = 0; j < n ; j++) { 18 | if(i==0 && j==0) 19 | arr[i][j] = 1; 20 | else if(i==0) 21 | arr[i][j] = arr[i][j-1]; 22 | else if(j==0) 23 | arr[i][j] = arr[i-1][j]; 24 | else 25 | arr[i][j] = arr[i-1][j]+arr[i][j-1]; 26 | } 27 | } 28 | return arr[m-1][n-1]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/lc621.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 621. Task Scheduler 4 | * 题意:一系列任务,相同任务之间至少有n个时间间隔,问最少执行时间 5 | * 难度:Medium 6 | * 分类:Array, Greedy, Tree 7 | * 思路:统计出出现次数最多的那个任务的出现次数,再统计下和他相同次数的任务个数,返回 (max-1)*(n+1)+count 即可 8 | * Tips: 9 | */ 10 | public class lc621 { 11 | public int leastInterval(char[] tasks, int n) { 12 | int[] map = new int[26]; 13 | int max = 0; 14 | for (char ch : tasks ) { 15 | map[ch-'A'] += 1; 16 | max = Math.max(map[ch-'A'], max); 17 | } 18 | int count = 0; 19 | for(int i: map){ 20 | if(i==max) count++; 21 | } 22 | return Math.max(tasks.length, (max-1)*(n+1)+count ); // max-1 不算最后一个周期, 最后一个周期时间是count,间隔为n,周期为n+1 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/lc63.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | /* 4 | * 63. Unique Paths II 5 | * 题意:路径数,添加了障碍 6 | * 难度:Medium 7 | * 分类:Array, Dynamic Programming 8 | * 思路:和lc64, lc62思路一样 9 | * Tips:可以用一维数组减小空间复杂度 10 | */ 11 | public class lc63 { 12 | public static void main(String[] args) { 13 | int[][] arr = { 14 | {0, 0, 0}, 15 | {0, 1, 0}, 16 | {0, 0, 0} 17 | }; 18 | System.out.println(uniquePathsWithObstacles(arr)); 19 | } 20 | 21 | 22 | public static int uniquePathsWithObstacles(int[][] obstacleGrid) { 23 | int[][] m = new int[obstacleGrid.length][obstacleGrid[0].length]; 24 | for (int i = 0; i < obstacleGrid.length; i++) { 25 | for (int j = 0; j =0 && right=0 ; i--) { 18 | if(digits[i]<9) { 19 | digits[i]++; 20 | return digits; 21 | }else{ 22 | //进位,下一位+1 23 | digits[i] = 0; 24 | } 25 | } 26 | // 全为9 27 | int[] res = new int[digits.length+1]; 28 | res[0] = 1; 29 | return res; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /code/lc673.java: -------------------------------------------------------------------------------- 1 | public static int findNumberOfLIS(int[] arr) { 2 | if(arr.length<=1) return arr.length; 3 | 4 | int n=arr.length; 5 | int[] dp=new int[n]; 6 | int[] count=new int[n]; 7 | 8 | int maxLen=0; 9 | int maxCount=0; 10 | 11 | for(int i=0;iarr[j]){ 16 | if(dp[j] + 1 > dp[i]){ 17 | dp[i]=dp[j]+1; 18 | count[i]=count[j]; 19 | }else if(dp[j]+1==dp[i]){ 20 | count[i]+=count[j]; 21 | } 22 | } 23 | } 24 | 25 | if(dp[i]>maxLen){ 26 | maxLen=dp[i]; 27 | maxCount=count[i]; 28 | }else if(dp[i]==maxLen){ 29 | maxCount+=count[i]; 30 | } 31 | } 32 | 33 | return maxCount; 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /code/lc69.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 69. Sqrt(x) 4 | * 题意:返回x的平方根, int取整 5 | * 难度:Easy 6 | * 分类:Math, Binary Search 7 | * 注意:返回的值是向下取整 8 | */ 9 | public class lc69 { 10 | public static void main(String[] args) { 11 | System.out.println(mySqrt(8)); 12 | } 13 | 14 | public static int mySqrt(int x) { 15 | int left = 1, right = x; 16 | while(left<=right){ // 等于时继续循环,保证向下取整 17 | int mid = (left + right)/2; 18 | if(mid==x/mid) 19 | return mid; 20 | else if(mid>x/mid) 21 | right = mid - 1; 22 | else 23 | left = mid + 1; 24 | } 25 | // 返回的是 right = mid-1 保证向下取整 26 | return right; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/lc7.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 7. Reverse Integer 4 | * 题意:反转一个整数 5 | * 难度:Easy 6 | * 分类:Math 7 | * 注意:如何判断溢出 8 | */ 9 | public class lc7 { 10 | public static void main(String[] args) { 11 | System.out.println(reverse(-987)); 12 | } 13 | 14 | public static int reverse(int x) { 15 | int result =0; 16 | while(x!=0){ 17 | int temp = result *10 + x%10; 18 | if(temp/10!=result) 19 | return 0; 20 | result = temp; 21 | x = x/10; 22 | } 23 | return result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/lc70.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 70. Climbing Stairs 4 | * 题意:上楼梯问题,一次走一步或两步 5 | * 难度:Easy 6 | * 分类:Dynamic Programming 7 | */ 8 | public class lc70 { 9 | public static void main(String[] args) { 10 | System.out.println(climbStairs(3)); 11 | } 12 | 13 | public static int climbStairs(int n) { 14 | if(n==1) 15 | return 1; 16 | if(n==2) 17 | return 2; 18 | int[] dp = new int[n]; 19 | dp[0] = 1; 20 | dp[1] = 2; 21 | for (int i = 2; i < n ; i++) { 22 | dp[i] = dp[i-1] + dp[i-2]; 23 | } 24 | return dp[n-1]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /code/lc714.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 714. Best Time to Buy and Sell Stock with Transaction Fee 4 | * 题意:买卖股票,不限次数,但有交易费用,求最大利润 5 | * 难度:Medium 6 | * 分类:Array, Dynamic Programming, Greedy 7 | * 思路:和309思路一致,每次卖出的时候减去交易费用 8 | * buy[i] = max( buy[i-1], sell[i-1]-price[i] ) 9 | * sell[i] = max( sell[i-1], buy[i-1]+price[i]-2 ) 10 | * Tips: 11 | * 总结一下买卖股票的问题 交易1次,2次,任意多次都可在O(N)完成交易 12 | * 交易k次时,时间复杂度为O(NM),M为交易次数 13 | * 冷却时间和交易费用的解法一致,都是分买和卖两个状态,进行dp 14 | */ 15 | public class lc714 { 16 | public int maxProfit(int[] prices, int fee) { 17 | if(prices.length==0) return 0; 18 | int b1 = -prices[0]; 19 | int s1=0, b = 0, s = 0; 20 | for (int i = 0; i < prices.length ; i++) { 21 | b = Math.max(b1, s1-prices[i]); 22 | s = Math.max(s1, b1+prices[i]-fee); 23 | s1 = s; 24 | b1 = b; 25 | } 26 | return Math.max(s,b); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/lc72.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 72. Edit Distance 4 | * 题意:编辑距离 5 | * 难度:Hard 6 | * 分类:String, Dynamic Programming 7 | * 思路:dp[i][j] 可以由 dp[i-1][j], dp[i][j-1], dp[i-1][j-1] 变过来 8 | * Tips:很经典的题,注意如何初始化dp[0][i]和dp[i][0],以及dp更新规则。空间复杂度还可以优化。 9 | */ 10 | public class lc72 { 11 | public static void main(String[] args) { 12 | System.out.println(minDistance("horse","ros")); 13 | } 14 | public static int minDistance(String word1, String word2) { 15 | int[][] dp = new int[word1.length()+1][word2.length()+1]; 16 | for (int i = 0; i < word2.length()+1 ; i++) 17 | dp[0][i] = i; 18 | for (int i = 0; i < word1.length()+1 ; i++) 19 | dp[i][0] = i; 20 | for (int i = 1; i < word1.length()+1 ; i++) { 21 | for (int j = 1; j < word2.length()+1 ; j++) { 22 | int temp = Math.min(dp[i][j-1]+1,dp[i-1][j]+1); 23 | if(word1.charAt(i-1)==word2.charAt(j-1)) 24 | dp[i][j] = Math.min(dp[i-1][j-1],temp); 25 | else 26 | dp[i][j] = Math.min(dp[i-1][j-1]+1,temp); 27 | } 28 | } 29 | return dp[word1.length()][word2.length()]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /code/lc73.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 73. Set Matrix Zeroes 4 | * 题意:把含有0的行和列都设成0 5 | * 难度:Medium 6 | * 分类:Array 7 | * 思路:用第一行和第一列作为标志位。注意赋值的时候从后往前,防止标志位被改变 8 | * 两遍循环,先记录,再置位 9 | * Tips:注意赋值的顺序,防止标志位被改变 10 | * 思路是很简单,但有许多细节 11 | */ 12 | public class lc73 { 13 | public void setZeroes(int[][] matrix) { 14 | boolean col0 = false; //因为 matrix[0][0] 只有一个位置,所以用一个变量单独记录 15 | for (int i = 0; i < matrix.length ; i++) { 16 | if(matrix[i][0]==0) col0 = true; 17 | for (int j = 1; j < matrix[0].length ; j++) { 18 | if(matrix[i][j]==0){ 19 | matrix[i][0] = 0; 20 | matrix[0][j] = 0; 21 | } 22 | } 23 | } 24 | for (int i = matrix.length-1; i >= 0 ; i--) { //从后往前,标志位那一行最后改变 25 | for (int j = matrix[0].length-1; j >= 1 ; j--) { // j>=1 不包含j==0 26 | if( matrix[i][0]==0 || matrix[0][j]==0 ) matrix[i][j] = 0; 27 | } 28 | if(col0==true) matrix[i][0]=0; //要在for循环后,再把[i][0]改变 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /code/lc746.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 746. Min Cost Climbing Stairs 4 | * 题意:上楼梯,变了一下形 5 | * 难度:Easy 6 | * 分类:Array, Dynamic Programming 7 | * 思路: 8 | * Tips:Bingo! 9 | */ 10 | public class lc746 { 11 | public int minCostClimbingStairs(int[] cost) { 12 | if(cost.length==1) return cost[0]; 13 | int dp1 = cost[0], dp2 = cost[1], dp3 = Integer.MAX_VALUE; 14 | for(int i=2; ii 9 | */ 10 | public class lc75 { 11 | public static void main(String[] args) { 12 | int[] nums = {1,0,2}; 13 | sortColors(nums); 14 | for (int i = 0; i < nums.length ; i++) { 15 | System.out.println(nums[i]); 16 | } 17 | } 18 | public static void sortColors(int[] nums) { 19 | int l = 0; 20 | int r = nums.length-1; 21 | for (int i = 0; i <= r ; i++) { // i<=r而不是length, 否则又换回来了 22 | if(nums[i]==0 && i!=l ){ //避免自己与自己交换 23 | int temp = nums[l]; 24 | nums[l] = nums[i]; 25 | nums[i] = temp; 26 | l++; 27 | i--; 28 | }else if(nums[i]==2){ 29 | int temp = nums[r]; 30 | nums[r] = nums[i]; 31 | nums[i] = temp; 32 | r--; 33 | i--; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/lc771.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 771. Jewels and Stones 4 | * 题意:S中出现的字符,在J中也出现的个数 5 | * 难度:Easy 6 | * 分类:Hash Table 7 | * 思路: 8 | * Tips: 9 | */ 10 | public class lc771 { 11 | public int numJewelsInStones(String J, String S) { 12 | int res=0; 13 | for(char c : S.toCharArray()){ 14 | if(J.indexOf(c) != -1){ 15 | res++; 16 | } 17 | } 18 | return res; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/lc78.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 78. Subsets 4 | * 题意:求数组子集 5 | * 难度:Medium 6 | * 分类:Array, Backtracking, Bit Manipulation 7 | * 思路:回溯法 8 | * Tips:和lc46,39作比较.要找出子集,所以每次backtracking直接添加进res 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class lc78 { 14 | public static void main(String[] args) { 15 | int[] nums= {1,2,3}; 16 | System.out.println(subsets(nums).toString()); 17 | } 18 | public static List> subsets(int[] nums) { 19 | List> res = new ArrayList>(); 20 | res.add(new ArrayList<>()); 21 | if(nums.length==0) 22 | return res; 23 | backtracking(res,nums,new ArrayList(),-1); 24 | return res; 25 | } 26 | public static void backtracking(List> res, int[] nums, List l, int start){ 27 | if(start>=nums.length) 28 | return; 29 | for (int i = start+1; i < nums.length ; i++) { 30 | l.add(nums[i]); 31 | res.add(new ArrayList(l)); 32 | backtracking(res,nums,l,i); 33 | l.remove((Integer)nums[i]); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/lc79.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 79. Word Search 4 | * 题意:在字符数组中搜索字符串 5 | * 难度:Medium 6 | * 分类:Array, Backtracking 7 | * 思路:回溯法 8 | * Tips:访问过的格子要标记,不能重复访问。回溯法注意回来的时候要重置标志位。向下找的时候直接找4个方向的,回来的时候不用再找了,只需重置标志位。 9 | * 不用mem,因为 ABC ABAD 这种情况,不能仅仅从A一个字符就断定为不为true 10 | */ 11 | public class lc79 { 12 | public static void main(String[] args) { 13 | char[][] board = {{'A','B','C','E'},{'S','F','C','S'},{'A','D','E','E'}}; 14 | System.out.println(exist(board,"SEE")); 15 | } 16 | 17 | public static boolean exist(char[][] board, String word) { 18 | if(board.length==0) 19 | return false; 20 | boolean [][] flag = new boolean[board.length][board[0].length]; 21 | for (int i = 0; i < board.length ; i++) { 22 | for (int j = 0; j < board[0].length ; j++) { 23 | if(search(board,word,i,j,0,flag)) 24 | return true; 25 | } 26 | } 27 | return false; 28 | } 29 | 30 | public static boolean search(char[][] board, String word, int i, int j, int sum, boolean[][] flag){ 31 | if(sum==word.length()) 32 | return true; 33 | if(i<0||j<0||i>=board.length||j>=board[0].length) 34 | return false; 35 | if(board[i][j]!=word.charAt(sum)||flag[i][j]==true) 36 | return false; 37 | flag[i][j] = true; 38 | sum++; 39 | boolean r = search(board, word, i, j+1, sum, flag) || search(board, word, i, j-1, sum, flag) || search(board, word, i+1, j, sum, flag) ||search(board, word, i-1, j, sum, flag); 40 | flag[i][j] = false; 41 | return r; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc8.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 8. String to Integer (atoi) 4 | * 题意:字符串转数字,按题目要求转换。(题出的不好,没什么意义) 5 | * 难度:Medium 6 | * 分类:Math, String 7 | * 注意:如何判断溢出 8 | */ 9 | public class lc8 { 10 | public static void main(String[] args) { 11 | System.out.println(myAtoi(" -42")); 12 | } 13 | 14 | public static int myAtoi(String str) { 15 | char[] s = str.toCharArray(); 16 | int i = 0; 17 | int num = 0; 18 | int sign = 1; 19 | while( i='0' && s[i]<='9' ){ 30 | //sign 乘了两次,保证num为正,以便*10+下一位 31 | int temp = sign * (num * 10 + Integer.parseInt(String.valueOf(s[i]))); 32 | if( sign==1 && temp/10*sign != num ) 33 | return Integer.MAX_VALUE; 34 | else if( sign==-1 && temp/10*sign != num ) 35 | return Integer.MIN_VALUE; 36 | num = temp * sign; 37 | i++; 38 | } 39 | return sign * num; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/lc81.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 81. Search in Rotated Sorted Array II 4 | * 题意:在翻转有序数组中查找指定数,数组中可能有相等的元素 5 | * 难度:Medium 6 | * 分类:Array, Binary Search 7 | * 思路:多加了一种情况,就是 nums[mid]==nums[begin]==nums[end] 8 | * Tips:注意边界判断,是否有等号 9 | * lc33 10 | */ 11 | public class lc81 { 12 | public boolean search(int[] nums, int target) { 13 | int begin = 0, end = nums.length-1; 14 | while(begin<=end){ 15 | int mid = (begin+end)/2; 16 | if(target==nums[mid]) return true; 17 | if(nums[begin]==nums[end]&& nums[end]==nums[mid]) end--; 18 | else if(nums[begin]<=nums[mid]){ //左边有序 19 | if(target>=nums[begin]&&targetnums[mid]&&target<=nums[end]){ 26 | begin = mid+1; 27 | }else{ 28 | end = mid-1; 29 | } 30 | }else{ 31 | end--; 32 | } 33 | } 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/lc83.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 83. Remove Duplicates from Sorted List 4 | * 题意:移除重复值的节点,链表已排序 5 | * 难度:Easy 6 | * 分类: 7 | * 思路: 8 | * Tips: 9 | */ 10 | public class lc83 { 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | ListNode(int x) { 15 | val = x; 16 | } 17 | } 18 | public ListNode deleteDuplicates(ListNode head) { 19 | if(head==null) return head; 20 | ListNode curr = head; 21 | ListNode res = head; 22 | while(curr!=null){ 23 | while( head!=null && head.val==curr.val) head = head.next; 24 | curr.next = head; 25 | curr = head; 26 | } 27 | return res; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /code/lc85.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Stack; 4 | 5 | /* 6 | * 85. Maximal Rectangle 7 | * 题意:为1的组成的最大矩形面积 8 | * 难度:Hard 9 | * 分类:Array, Hash Table, Dynamic Programming, Stack 10 | * 思路:将问题转化为 84.Largest Rectangle in Histogram 11 | * Tips:很难,lc84就够难了,没写过的谁能想到。。。 12 | */ 13 | public class lc85 { 14 | public static void main(String[] args) { 15 | char[][] matrix = {{'1','0','1','0','0'}, 16 | {'1','0','1','1','1'}, 17 | {'1','1','1','1','1'}, 18 | {'1','0','0','1','0'}}; 19 | System.out.println(maximalRectangle(matrix)); 20 | } 21 | public static int maximalRectangle(char[][] matrix) { 22 | if(matrix.length==0||matrix[0].length==0) 23 | return 0; 24 | int col = matrix[0].length; 25 | int[] row = new int[col]; // 用来记录直方图高度 26 | int res =0; 27 | for (int i = 0; i < matrix.length; i++) { 28 | for (int j = 0; j < col ; j++) { 29 | if(matrix[i][j]=='0') 30 | row[j] =0; 31 | else 32 | row[j] = row[j]+1; 33 | } 34 | // 求直方图最大面积 35 | Stack st = new Stack(); 36 | for (int j = 0; j <= col ; j++) { 37 | int h = ( j==col ? 0 : row[j] ); 38 | if(st.isEmpty() || h>row[st.peek()]){ 39 | st.add(j); 40 | }else{ 41 | int index = st.pop(); 42 | res = Math.max(res, row[index]*(j- ( st.isEmpty() ? -1 : st.peek() ) -1)); 43 | j--; 44 | } 45 | } 46 | } 47 | return res; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/lc87.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 87. Scramble String 4 | * 题意:把字符串写成二叉树的形式,问是否可以交换非叶子节点的左右孩子,生成新的字符串 5 | * 难度:Hard 6 | * 分类:String, Dynamic Programming 7 | * 思路:递归的方法,判断交换两段是否满足 8 | * Tips:注意先判断两个字符串是否字符一样,用map的方法,否则长的字符串会超时 9 | */ 10 | public class lc87 { 11 | public boolean isScramble(String s1, String s2) { 12 | if(s1.equals(s2)) return true; 13 | if(s1.length()!=s2.length()) return false; 14 | int[] cur_map = new int[26]; 15 | for(int i=0; i0; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /code/lc88.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 88. Merge Sorted Array 4 | * 题意:归并数组 5 | * 难度:Easy 6 | * 分类:Array, Two Pointers 7 | * 注意:实际上 nums1.length = m+n , 不会>m+n ,题意没说清楚. 用一个指针指向nums的末端,从后往前走 8 | */ 9 | public class lc88 { 10 | public static void main(String[] args) { 11 | int[] nums1 = {4,5,6,0,0,0}; 12 | int[] nums2 = {1,2,3}; 13 | int m = 3; 14 | int n = 3; 15 | merge(nums1,m,nums2,n); 16 | for(int i:nums1) 17 | System.out.println(i); 18 | } 19 | 20 | public static void merge(int[] nums1, int m, int[] nums2, int n) { 21 | int ptr1 = m-1; 22 | int ptr2 = n-1; 23 | int cur = m+n-1; 24 | while(ptr1>=0 && ptr2>=0){ 25 | if(nums1[ptr1]>nums2[ptr2]) { 26 | nums1[cur--] = nums1[ptr1--]; 27 | } 28 | else { 29 | nums1[cur--] = nums2[ptr2--]; 30 | } 31 | } 32 | while(ptr2>=0) 33 | nums1[cur--] = nums2[ptr2--]; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/lc9.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 9. Palindrome Number 4 | * 题意:判断数字是否是回文数字 5 | * 难度:Easy 6 | * 分类:Math 7 | * 思路:不转换字符串的思路就是把数字反转了以后,比较是否相等 8 | * Tips:lc5, lc9, lc125, lc131, lc234, lc647 9 | */ 10 | public class lc9 { 11 | public boolean isPalindrome(int x) { 12 | int rev = 0; 13 | int temp = x; 14 | while(x>0){ 15 | rev = rev*10 + x%10; 16 | x = x/10; 17 | } 18 | return rev == temp; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/lc91.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 91. Decode Ways 4 | * 题意:1~26代表了26个字母 5 | * 难度:Medium 6 | * 分类:String, Dynamic Programming 7 | * 思路:动态规划,和上台阶问题很像 8 | * Tips:Bingo! 9 | */ 10 | public class lc91 { 11 | public static void main(String[] args) { 12 | System.out.println(numDecodings("99")); 13 | } 14 | public static int numDecodings(String s) { 15 | if(s.length()==0) return 0; 16 | int[] dp = new int[s.length()+1]; 17 | dp[0] = 1; 18 | int ch = s.charAt(0)-'0'; 19 | if( ch<1 || ch>9 ) return 0; //判断第一个字符是否符合规范 20 | else dp[1] = 1; 21 | for (int i = 2; i < s.length()+1 ; i++) { 22 | int a = s.charAt(i-2)-'0'; 23 | int b = s.charAt(i-1)-'0'; 24 | if( (a*10+b)<=26 && (a*10+b)>=10 ) //可能存在两个字符10符合,但一个字符0不符合的情况,所以+= 25 | dp[i] += dp[i-2]; 26 | if( b>0 && b<=9 ) 27 | dp[i] += dp[i-1]; 28 | if(dp[i]==0) return 0; //解析错误 29 | } 30 | return dp[s.length()]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/lc921.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Stack; 4 | /* 5 | * 921. Minimum Add to Make Parentheses Valid 6 | * 题意:最少添加符号个数,使得表达式有效 7 | * 难度:Medium 8 | * 分类:Stack, Greedy 9 | * 思路:匹配的都出栈,最后剩下的栈中没匹配的个数,就是需要添加的个数 10 | * Tips:lc301 11 | */ 12 | public class lc921 { 13 | public int minAddToMakeValid(String S) { 14 | char[] ch_arr = S.toCharArray(); 15 | Stack st = new Stack<>(); 16 | for (int i = 0; i < ch_arr.length ; i++) { 17 | if(ch_arr[i]==')' && !st.isEmpty() && st.peek()=='('){ 18 | st.pop(); 19 | }else{ 20 | st.push(ch_arr[i]); 21 | } 22 | } 23 | return st.size(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /code/lc922.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 922. Sort Array By Parity II 4 | * 题意:奇数位置上都是奇数,偶数位置上都是偶数 5 | * 难度:Easy 6 | * 分类:Array, Sort 7 | * 思路:题看似简单,但最优的方法并不好写 8 | * Tips: 9 | */ 10 | public class lc922 { 11 | public int[] sortArrayByParityII(int[] A) { //O(N^2) 12 | for (int i = 0; i < A.length ; i++) { 13 | if( A[i]%2==i%2 ) continue; 14 | for (int j = i+1; j < A.length ; j++) { 15 | if(A[i]%2!=A[j]%2) { 16 | int temp = A[i]; 17 | A[i] = A[j]; 18 | A[j] = temp; 19 | break; 20 | } 21 | } 22 | } 23 | return A; 24 | } 25 | 26 | public int[] sortArrayByParityII2(int[] A) { //很巧妙的方法 O(N)时间, O(1)空间 27 | int cur = 1; //奇数位置的位置 28 | for (int i = 0; i < A.length ; i+=2) { //这里+2 只判断偶数位置上是否符合 29 | if(A[i]%2==1){ 30 | while(A[cur]%2==1) cur+=2; 31 | int temp = A[cur]; 32 | A[cur] = A[i]; 33 | A[i] = temp; 34 | } 35 | } 36 | return A; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/lc94.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 94. Binary Tree Inorder Traversal 4 | * 题意: 5 | * 难度:Medium 6 | * 分类:HashTable, Stack, Tree 7 | * 思路:左节点依次入栈二叉树中序遍历 8 | * Tips:和lc144前序,lc145后序一起看, lc102层次遍历 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Stack; 13 | 14 | public class lc94 { 15 | public class TreeNode { 16 | int val; 17 | TreeNode left; 18 | TreeNode right; 19 | TreeNode(int x) { val = x; } 20 | } 21 | public List inorderTraversal(TreeNode root) { 22 | List res = new ArrayList<>(); 23 | if(root==null) return res; 24 | Stack st = new Stack(); 25 | while( !st.isEmpty() || root!=null ) { //注意停止条件 26 | while (root != null) { 27 | st.push(root); 28 | root = root.left; 29 | } 30 | root = st.pop(); 31 | res.add(root.val); 32 | root = root.right; 33 | } 34 | return res; 35 | } 36 | 37 | List res = new ArrayList(); 38 | public List inorderTraversal2(TreeNode root) { //递归 39 | helper(root); 40 | return res; 41 | } 42 | public void helper(TreeNode root){ 43 | if(root==null) return; 44 | helper(root.left); 45 | res.add(root.val); 46 | helper(root.right); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /code/lc940 java: -------------------------------------------------------------------------------- 1 | public static int distinctSubseqII(String S) { 2 | int[] dp=new int[S.length()+1]; 3 | int[] lastSeen=new int[26]; 4 | dp[0]=1; 5 | int mod=(int)1e9+7; 6 | 7 | for(int i=1;i generateTrees(int n) { 24 | if(n==0) return new LinkedList(); 25 | return generateSubtrees(1, n); 26 | } 27 | 28 | private List generateSubtrees(int s, int e) { 29 | List res = new LinkedList(); 30 | if (s > e) { 31 | res.add(null); // empty tree 32 | return res; 33 | } 34 | 35 | for (int i = s; i <= e; ++i) { 36 | List leftSubtrees = generateSubtrees(s, i - 1); 37 | List rightSubtrees = generateSubtrees(i + 1, e); 38 | 39 | for (TreeNode left : leftSubtrees) { 40 | for (TreeNode right : rightSubtrees) { 41 | TreeNode root = new TreeNode(i); 42 | root.left = left; 43 | root.right = right; 44 | res.add(root); 45 | } 46 | } 47 | } 48 | return res; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /code/lc96.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 96. Unique Binary Search Trees 4 | * 题意:给定n,多少棵二叉搜索树,1~n 5 | * 难度:Medium 6 | * 分类:Dynamic Programming, Tree 7 | * 思路:1~n都可以做根节点,分成左右两个子问题 dp[i] * dp[n-1-i] 8 | * Tips: 9 | */ 10 | public class lc96 { 11 | public static void main(String[] args) { 12 | System.out.println(numTrees(3)); 13 | } 14 | public static int numTrees(int n) { 15 | if(n<2) 16 | return 1; 17 | int[] dp = new int[n+1]; 18 | dp[0] = 1; 19 | dp[1] = 1; 20 | for (int i = 2; i < n+1; i++) { 21 | for (int j = 0; j A[i - 1]) { 18 | inc = dec + 1; 19 | dec = 1; 20 | } else { 21 | inc = 1; 22 | dec = 1; 23 | } 24 | result = Math.max(result, Math.max(dec, inc)); 25 | } 26 | return result; 27 | } 28 | 29 | public int maxTurbulenceSize2(int[] A) { 30 | int[] arr = new int[A.length-1]; 31 | for(int i=1; iA[i-1]) arr[i-1] = 1; 34 | else arr[i-1] = -1; 35 | } 36 | int res = 1; 37 | boolean flag = false; //判断下是否全是0, 返回的时候就不+1 38 | int count = 1; 39 | for(int i=1; i st = new Stack(); 35 | while(root!=null || !st.isEmpty()){ 36 | while(root!=null){ 37 | st.add(root); 38 | root = root.left; 39 | } 40 | root = st.pop(); 41 | if(pre!=null && pre.val>root.val && tn1==null) 42 | tn1 = pre; 43 | if(pre!=null && pre.val>root.val && tn1!=null) //可能被执行多次 eg 3 2 1 tn2 先被赋值2 后被赋值1 44 | tn2 = root; 45 | pre = root; 46 | root = root.right; 47 | } 48 | } 49 | } 50 | --------------------------------------------------------------------------------