├── .gitignore ├── Top100.md ├── TopInterview.md ├── code ├── lc1.java ├── lc10.java ├── lc100.java ├── lc101.java ├── lc102.java ├── lc103.java ├── lc104.java ├── lc105.java ├── lc108.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 ├── 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 ├── 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 ├── 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 ├── 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 ├── 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 ├── lc494.java ├── lc5.java ├── lc50.java ├── lc53.java ├── lc538.java ├── lc54.java ├── lc543.java ├── lc55.java ├── lc56.java ├── lc560.java ├── lc572.java ├── lc58.java ├── lc581.java ├── lc617.java ├── lc62.java ├── lc621.java ├── lc63.java ├── lc64.java ├── lc647.java ├── lc66.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 ├── lc84.java ├── lc85.java ├── lc877.java ├── lc88.java ├── lc9.java ├── lc91.java ├── lc94.java ├── lc95.java ├── lc96.java ├── lc98.java └── lc983.java └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | */.DS_Store 3 | /kickstart/* 4 | test.java 5 | -------------------------------------------------------------------------------- /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()){ 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/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/lc105.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 105. Construct Binary Tree from Preorder and Inorder Traversal 4 | * 题意:根据先序和中序,构造二叉树 5 | * 难度:Medium 6 | * 分类:Array, Tree, Depth-first Search 7 | * 思路:通过递归的方式,找左节点和右节点 8 | * Tips:思路记一下,自己想不起来。递归的方法,每次把inorder数组分为两半,设置一个pre_index,每次根据pre_index建立节点,向下递归。 9 | */ 10 | public class lc105 { 11 | public static class TreeNode { 12 | int val; 13 | TreeNode left; 14 | TreeNode right; 15 | TreeNode(int x) { val = x; } 16 | } 17 | 18 | public static void main(String[] args) { 19 | int[] preorder = {3,9,20,15,7}; 20 | int[] inorder = {9,3,15,20,7}; 21 | buildTree(preorder,inorder); 22 | } 23 | public static TreeNode buildTree(int[] preorder, int[] inorder) { 24 | return recursion(preorder, inorder, 0, 0, inorder.length-1); 25 | } 26 | public static TreeNode recursion(int[] preorder, int[] inorder, int pre_index, int start, int end){ //start,end代表在inorder上搜索的范围 27 | if(start>end || start >inorder.length) 28 | return null; 29 | TreeNode tn = new TreeNode(preorder[pre_index]); 30 | int in_index = 0; 31 | for (int i = 0; i <= end; i++) { 32 | if(preorder[pre_index]==inorder[i]) 33 | in_index = i; 34 | } 35 | tn.left = recursion(preorder, inorder, pre_index+1, start, in_index-1); 36 | tn.right = recursion(preorder, inorder, pre_index+in_index-start+1, in_index+1, end); //注意右孩子节点index参数 37 | return tn; //记住函数的返回值的设置,返回Node,递归的构造子树 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /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(left> pathSum(TreeNode root, int sum) { 23 | List> res = new ArrayList<>(); 24 | helper(res, root, sum, 0, new ArrayList<>()); 25 | return res; 26 | } 27 | public void helper(List> res, TreeNode root, int sum, int curr, List curr_ls) { 28 | if(root==null) return; 29 | curr_ls.add(root.val); 30 | if(curr+root.val==sum && root.left==null && root.right==null) { //到叶子节点 31 | res.add(new ArrayList<>(curr_ls)); 32 | curr_ls.remove(curr_ls.size()-1); 33 | return; 34 | } 35 | helper(res, root.left, sum, curr+root.val, curr_ls); 36 | helper(res, root.right, sum, curr+root.val, curr_ls); 37 | curr_ls.remove(curr_ls.size()-1); 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: 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 | * 122. 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)); 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 =board.length||col<0||col>=board[0].length) return; 46 | if(board[row][col]=='O') { //是 O 的话才继续递归 47 | board[row][col] = '1'; 48 | dfs(board, row + 1, col); 49 | dfs(board, row - 1, col); 50 | dfs(board, row, col + 1); 51 | dfs(board, row, col - 1); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /code/lc131.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | /* 6 | * 131. Palindrome Partitioning 7 | * 题意:回文切割,找出所有切法 8 | * 难度:Medium 9 | * 分类:Backtracking 10 | * 思路:典型回溯法,注意向res添加内容时要重新new一下 11 | * Tips:lc39 12 | */ 13 | public class lc131 { 14 | public static void main(String[] args) { 15 | List res = partition("aab"); 16 | System.out.println(); 17 | } 18 | public static List> partition(String s) { 19 | List> res = new ArrayList<>(); 20 | helper(s, res, new ArrayList<>()); 21 | return res; 22 | } 23 | 24 | public static void helper(String s, List> res, List curr){ 25 | if(s.length()==0) { 26 | res.add(new ArrayList<>(curr)); //新new一个 27 | } 28 | for (int i = 1; i <= s.length() ; i++) { 29 | String curr_str = s.substring(0,i); 30 | if(isPalindrome(curr_str)){ 31 | curr.add(curr_str); 32 | helper(s.substring(i), res, curr); 33 | curr.remove(curr.size()-1); //不要用curr.remove(curr_str); 会把集合内顺序打乱,AC不了 34 | } 35 | } 36 | } 37 | 38 | public static boolean isPalindrome(String s){ //判断是否为回文 39 | int b =0; 40 | int e = s.length()-1; 41 | while(b=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 | * lc140 10 | */ 11 | import java.util.List; 12 | 13 | public class lc139 { 14 | public boolean wordBreak(String s, List wordDict) { 15 | boolean[] dp = new boolean[s.length()+1]; 16 | dp[0] = true; 17 | for (int i = 1; i < dp.length ; i++) { 18 | for (int j = 0; j < i ; j++) { //遍历之前计算出来的结果 19 | if( dp[j]==true && wordDict.contains(s.substring(j,i))) 20 | dp[i] = true; 21 | } 22 | } 23 | return dp[s.length()+1]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /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) 18 | return false; 19 | ListNode faster = head; 20 | ListNode slow = head; 21 | while( faster.next!=null && faster.next.next!=null){ //注意判断条件,slow一定不等于null,不用判断了 22 | slow = slow.next; 23 | faster = faster.next.next; 24 | if(slow==faster) 25 | return true; 26 | } 27 | return false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /code/lc144.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 144. Binary Tree Preorder Traversal 4 | * 题意:二叉树先序遍历 5 | * 难度:Medium 6 | * 分类:Stack, Tree 7 | * 思路:左节点依次入栈 8 | * Tips:和lc94中序,lc145后序一起看 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) 24 | return res; 25 | Stack st = new Stack(); 26 | while(!st.isEmpty()||root!=null){ 27 | while(root!=null) { 28 | st.add(root); 29 | res.add(root.val); 30 | root = root.right; //先遍历右节点 31 | } 32 | root = st.pop(); 33 | root =root.left; //再左节点 34 | } 35 | Collections.reverse(res); //反转链表 36 | return res; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/lc148.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 148. Sort List 4 | * 题意:链表排序 5 | * 难度:Medium 6 | * 分类:Linked List, Sort 7 | * 思路:快慢指针把链表分成两半,在merge两个链表 8 | * Tips:空间复杂度不是O(1)的,但是几个高票答案都是这样写的,面试给出这样的代码应该也够了 9 | */ 10 | public class lc148 { 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | ListNode(int x) { val = x; } 15 | } 16 | 17 | public ListNode sortList(ListNode head) { 18 | if( head==null || head.next == null ){ 19 | return head; 20 | } 21 | ListNode slow = head; 22 | ListNode fast = head.next; 23 | while( fast.next!=null && fast.next.next!=null ){ //把链表分成两半 24 | slow = slow.next; 25 | fast = fast.next.next; 26 | } 27 | ListNode l2 = sortList(slow.next); 28 | slow.next = null; 29 | ListNode l1 = sortList(head); 30 | return mergeList(l1, l2); 31 | } 32 | 33 | public ListNode mergeList(ListNode l1, ListNode l2){ 34 | ListNode res = new ListNode(0); 35 | ListNode head = res; 36 | while( l1!=null && l2!=null ){ 37 | if(l1.val> 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 | */ 9 | import java.util.*; 10 | 11 | public class lc15 { 12 | public static void main(String[] args) { 13 | int[] nums = {-1, 0, 1, 2, -1, -4}; 14 | System.out.println(threeSum(nums).toString()); 15 | } 16 | 17 | public static List> threeSum(int[] nums) { 18 | List> result = new ArrayList(); 19 | Arrays.sort(nums); 20 | for (int i = 0; i < nums.length-2 ; i++) { 21 | if( i>0 && nums[i]==nums[i-1] ) //防止重复添加相同内容List 22 | continue; 23 | int left = i+1, right = nums.length-1; 24 | 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; //注意maxh会被替换,先保存下 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/lc155.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 155. Min Stack 4 | * 题意:设计一个栈,这个栈有一个getmin方法 5 | * 难度:Easy 6 | * 分类:Stack, Design 7 | * 思路:每次替换最小值时,把当前最小值入栈用以记录,以便之后更新最小值 8 | * Tips: 9 | */ 10 | import java.util.Stack; 11 | 12 | public class lc155 { 13 | class MinStack { 14 | Stack 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: 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/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 qu = new ArrayDeque(); 30 | int[] res = new int[numCourses]; 31 | int sum = 0; 32 | for (int i = 0; i < degrees.length ; i++) { 33 | if(degrees[i]==0) { 34 | qu.add(i); 35 | res[sum] = i; 36 | sum++; 37 | } 38 | } 39 | while(!qu.isEmpty()){ 40 | int curr_course = qu.remove(); 41 | for (int i = 0; i < numCourses ; i++) { 42 | if(graph[curr_course][i]==1){ 43 | degrees[i]--; 44 | if(degrees[i]==0){ 45 | qu.add(i); 46 | res[sum] = i; 47 | sum++; 48 | } 49 | } 50 | } 51 | } 52 | return sum==numCourses ? res : new int[0]; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /code/lc212.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 212. Word Search II 4 | * 题意:找出字符数组中路径可以拼出的字符串 5 | * 难度:Hard 6 | * 分类:Backtracking, Trie 7 | * 思路:暴力搜索回溯法就可以AC 8 | * 更好的方法是借助字典树数据结构进行剪枝,减少重复的搜索路径 9 | * https://leetcode.com/problems/word-search-ii/discuss/59780/Java-15ms-Easiest-Solution-(100.00) 10 | * Tips: 11 | */ 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | public class lc212 { 16 | public List 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 | */ 10 | public class lc215 { 11 | public static void main(String[] args) { 12 | int[] nums = {3,2,3,1,2,4,5,5,6}; 13 | System.out.println(findKthLargest(nums, 4)); 14 | } 15 | public static int findKthLargest(int[] nums, int k) { 16 | return quickSort(nums, 0, nums.length-1, k); 17 | } 18 | 19 | public static int quickSort(int[] nums, int left, int right, int k){ 20 | int origin_l = left; //left 和 right 移动,但要保存一下原始的值,方便递归调用 21 | int origin_r = right; 22 | int cur = nums[left]; 23 | while(left= cur) 28 | left++; 29 | nums[right] = nums[left]; 30 | } 31 | nums[left] = cur; 32 | if(left==k-1) return cur; 33 | else if(left>k-1) return quickSort(nums, origin_l, left-1, k); 34 | else return quickSort(nums, left+1, origin_r, k); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /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) 17 | return 0; 18 | int[][] dp = new int[matrix.length][matrix[0].length]; 19 | int max = 0; 20 | for (int i = 0; i < matrix.length ; i++) { 21 | for (int j = 0; j < matrix[0].length ; j++) { 22 | if(i==0 || j==0) { 23 | dp[i][j] = matrix[i][j]-'0'; 24 | max = Math.max(dp[i][j],max); 25 | } 26 | else{ 27 | if(matrix[i][j]=='1') { 28 | dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; //dp[i][j] 最大正方形边长 29 | max = Math.max(dp[i][j], max); 30 | } 31 | } 32 | } 33 | } 34 | return max*max; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /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) 23 | return null; 24 | TreeNode temp = root.left; 25 | root.left = root.right; 26 | root.right = temp; 27 | invertTree(root.left); 28 | invertTree(root.right); 29 | return root; 30 | } 31 | 32 | public TreeNode invertTree2(TreeNode root) { 33 | //迭代 34 | if(root==null) 35 | return null; 36 | Stack st = new Stack(); 37 | st.add(root); 38 | while(!st.isEmpty()){ 39 | TreeNode tn = st.pop(); 40 | TreeNode temp = tn.left; 41 | tn.left = tn.right; 42 | tn.right = temp; 43 | if(tn.left!=null) 44 | st.add(tn.left); 45 | if(tn.right!=null) 46 | st.add(tn.right); 47 | } 48 | return root; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /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 | */ 10 | public class lc234 { 11 | public class ListNode { 12 | int val; 13 | ListNode next; 14 | ListNode(int x) { val = x; } 15 | } 16 | 17 | public boolean isPalindrome(ListNode head) { 18 | if(head==null||head.next==null) 19 | return true; 20 | ListNode slow = head; 21 | ListNode fast = head; 22 | while (fast.next != null && fast.next.next != null) { 23 | slow = slow.next; 24 | fast = fast.next.next; 25 | } 26 | ListNode head2 = reverse(slow.next,null); 27 | slow.next = null; //注意截断一下 28 | while(head2!=null&&head!=null){ 29 | if(head2.val!=head.val) 30 | return false; 31 | head = head.next; 32 | head2 = head2.next; 33 | } 34 | return true; 35 | } 36 | public ListNode reverse(ListNode head, ListNode pre){ 37 | ListNode next = head.next; 38 | head.next = pre; 39 | if(next==null) 40 | return head; 41 | return reverse(next, head); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /code/lc236.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.*; 4 | 5 | /* 6 | * 236. Lowest Common Ancestor of a Binary Tree 7 | * 题意:二叉树上两个节点的公共祖先 8 | * 难度:Medium 9 | * 分类:Tree 10 | * 思路:递归,迭代两种方法 11 | * Tips:注意递归时怎么返回。很经典的题目。 12 | */ 13 | public class lc236 { 14 | public class TreeNode { 15 | int val; 16 | TreeNode left; 17 | TreeNode right; 18 | TreeNode(int x) { val = x; } 19 | } 20 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {//递归 21 | if( root==null || root==p || root==q ) 22 | return root; 23 | TreeNode left = lowestCommonAncestor(root.left, p, q); 24 | TreeNode right = lowestCommonAncestor(root.right, p, q); 25 | if( left!=null && right!=null ) //回溯返回。哪边不为空,返回哪边,否则返回自己。 26 | return root; 27 | else if(left!=null) 28 | return left; 29 | else return right; 30 | } 31 | 32 | public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) { 33 | Map parent = new HashMap<>(); //用map存储节点的父亲节点,便于查找 34 | Stack stack = new Stack<>(); 35 | parent.put(root, null); 36 | stack.push(root); 37 | 38 | while (!parent.containsKey(p) || !parent.containsKey(q)) { //遍历了一遍节点,把节点的父节点信息记录了一下 39 | TreeNode node = stack.pop(); 40 | if (node.left != null) { 41 | parent.put(node.left, node); 42 | stack.push(node.left); 43 | } 44 | if (node.right != null) { 45 | parent.put(node.right, node); 46 | stack.push(node.right); 47 | } 48 | } 49 | Set ancestors = new HashSet<>(); 50 | while (p != null) { //p的路径节点添加到hashset中 51 | ancestors.add(p); 52 | p = parent.get(p); 53 | } 54 | while (!ancestors.contains(q)) //第一个hashset中遇到的节点,就是最近公共祖先 55 | q = parent.get(q); 56 | return q; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /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 | ListNode pre = new ListNode(-1); 21 | while(node.next!=null) { 22 | node.val = node.next.val; 23 | pre = node; 24 | node = node.next; 25 | } 26 | pre.next = null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /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.ArrayDeque; 11 | import java.util.Deque; 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 ArrayDeque(); //队列里是递减的 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: 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 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/lc297.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Arrays; 4 | import java.util.Deque; 5 | import java.util.LinkedList; 6 | 7 | /* 8 | * 297. Serialize and Deserialize Binary Tree 9 | * 题意:序列化,反序列化树 10 | * 难度:Hard 11 | * 分类:Tree, Design 12 | * 思路: 13 | * Tips: 14 | */ 15 | public class lc297 { 16 | public class TreeNode { 17 | int val; 18 | TreeNode left; 19 | TreeNode right; 20 | TreeNode(int x) { val = x; } 21 | } 22 | public class Codec { 23 | private static final String spliter = ","; 24 | private static final String NN = "X"; 25 | 26 | // Encodes a tree to a single string. 27 | public String serialize(TreeNode root) { 28 | StringBuilder sb = new StringBuilder(); 29 | buildString(root, sb); 30 | return sb.toString(); 31 | } 32 | 33 | private void buildString(TreeNode node, StringBuilder sb) { 34 | if (node == null) { 35 | sb.append(NN).append(spliter); 36 | } else { 37 | sb.append(node.val).append(spliter); 38 | buildString(node.left, sb); 39 | buildString(node.right,sb); 40 | } 41 | } 42 | // Decodes your encoded data to tree. 43 | public TreeNode deserialize(String data) { 44 | Deque nodes = new LinkedList<>(); 45 | nodes.addAll(Arrays.asList(data.split(spliter))); 46 | return buildTree(nodes); 47 | } 48 | 49 | private TreeNode buildTree(Deque nodes) { 50 | String val = nodes.remove(); 51 | if (val.equals(NN)) return null; 52 | else { 53 | TreeNode node = new TreeNode(Integer.valueOf(val)); 54 | node.left = buildTree(nodes); 55 | node.right = buildTree(nodes); 56 | return node; 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /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 | */ 9 | import java.util.HashMap; 10 | 11 | public class lc3 { 12 | public static void main(String[] args) { 13 | String s = "abba"; 14 | System.out.println(lengthOfLongestSubstring(s)); 15 | } 16 | 17 | public static int lengthOfLongestSubstring(String s) { 18 | HashMap hm = new HashMap<>(); 19 | int max = 0; 20 | int j = 0; 21 | for (int i = 0; i nums[j]){ 22 | dp[i] = Math.max(dp[j]+1, dp[i]); 23 | } 24 | } 25 | res = Math.max(res, dp[i]); 26 | } 27 | return res; 28 | } 29 | 30 | public int lengthOfLIS2(int[] nums) { 31 | if(nums.length<2) 32 | return nums.length; 33 | int size = 0; //size指dp中递增的长度。 dp[0~i] 表示了长度为 i+1 的递增子数组,且最后一个值是最小值 34 | int[] dp = new int[nums.length]; //dp存储递增的数组,之后更新这个数组。如果x>最后一个值,则插入到末尾,否则更新对应位置上的值为该值。 35 | for (int i = 0; i < nums.length ; i++) { 36 | int left = 0; 37 | int right = size; 38 | while(left!=right){ //得到要插入的位置 39 | int mid = (left+right)/2; 40 | if(dp[mid] removeInvalidParentheses(String s) { 19 | HashSet res = new HashSet(); 20 | StringBuilder sb = new StringBuilder(); 21 | helper(s, res, 0, 0, new char[]{'(',')'}); 22 | return new ArrayList<>(res); 23 | } 24 | public static void helper(String s, HashSet res, int pos, int pos2, char[] chs){ 25 | int count = 0; 26 | char[] str_arr = s.toCharArray(); 27 | for (int i = pos; i < s.length() ; i++) { 28 | if( str_arr[i]==chs[0] ) 29 | count++; 30 | else if( str_arr[i]==chs[1] ) 31 | count--; 32 | if (count < 0) { //需要删除一个 ')' 33 | for (int j = pos2; j <= i; j++) { // pos2 避免重复的情况又算一次 34 | if (str_arr[j] == chs[1] && j == 0) 35 | helper(s.substring(0,j)+s.substring(j+1), res, i, j,chs); 36 | if (str_arr[j] == chs[1] && j > 0 && str_arr[j - 1] != chs[1]) 37 | helper(s.substring(0,j)+s.substring(j+1), res, i, j,chs); //把截取后的s传到递归函数里, i不用+1,因为已经删掉一个字符了 38 | } 39 | return; 40 | } 41 | } 42 | s = new StringBuilder(s).reverse().toString(); 43 | if(chs[0]=='(') 44 | helper(s, res, 0, 0, new char[]{')','('}); //反转 45 | else 46 | res.add(s); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /code/lc303.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 303. Range Sum Query - Immutable 4 | * 题意:i到j的和 5 | * 难度:Easy 6 | * 分类:Dynamic Programming 7 | * 思路: 8 | * Tips:Bingo! 9 | * lc303, lc437, lc560 10 | */ 11 | public class lc303 { 12 | class NumArray { 13 | int[] arr; 14 | public NumArray(int[] nums) { 15 | arr = nums; 16 | for(int i=1; i0&&nums[ptr-1]>=nums[ptr]){// 注意是 >= {5,1,1} , 等于-- 24 | ptr--; 25 | } 26 | 27 | if(ptr!=0){ 28 | //从这个数之后的数中找出第一个比x大的数 29 | int n = nums[ptr]; 30 | int ptr2 = ptr; 31 | for(int i=ptr+1; inums[ptr-1] && nums[i]<=n ) {//注意 <= {2,3,1,3,3} 33 | n = nums[i]; 34 | ptr2 = i; 35 | } 36 | } 37 | nums[ptr2] = nums[ptr-1]; 38 | nums[ptr-1] = n; 39 | } 40 | 41 | //把之后的数逆序 42 | ReverseNums(nums,ptr,nums.length-1); 43 | } 44 | public static void ReverseNums(int[] nums, int start, int end){ 45 | int l = end+start; 46 | for (int i = start; i < (start+end+1)/2 ; i++) { 47 | int temp = nums[i]; 48 | nums[i] = nums[l-i]; 49 | nums[l-i] = temp; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /code/lc32.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Stack; 4 | 5 | /* 6 | * 32. Longest Valid Parentheses 7 | * 题意:最长括号匹配 8 | * 难度:Hard 9 | * 分类:Dynamic Programming, String 10 | * 思路:两种常规方法,一是dp,每个位置记录以该位置结尾的最长长度。另一种是用栈,把位置索引入栈。 11 | * Tips:想到了用dp,也想到了用数组记录位置结尾的解,但没有想好如何进行更新迭代计算。把位置索引入栈的方法很典型,关注一下。 12 | */ 13 | public class lc32 { 14 | public static void main(String[] args) { 15 | System.out.println(longestValidParentheses2("()(())")); 16 | } 17 | 18 | public static int longestValidParentheses(String s) { 19 | if(s.length()==0) 20 | return 0; 21 | // dp 方法 22 | int[] dp = new int[s.length()+1]; 23 | int res=0; 24 | for (int i = 2; i =0 && s.charAt(i-2-dp[i-1])=='('){ // 这种情况:()(()) 31 | dp[i] = dp[i-1] + dp[i-2-dp[i-1]]+2; 32 | } 33 | } 34 | if(dp[i]>res) 35 | res = dp[i]; 36 | } 37 | return res; 38 | } 39 | 40 | public static int longestValidParentheses2(String s) { 41 | //栈方法 ()(()) 42 | Stack st = new Stack(); 43 | st.add(-1); 44 | int res = 0; 45 | for (int i = 0; i < s.length() ; i++) { 46 | char ch = s.charAt(i); 47 | if(ch=='(') 48 | st.add(i); 49 | else if(ch==')'){ 50 | st.pop(); 51 | if(st.isEmpty()) 52 | st.push(i); 53 | res = Math.max(res,i-st.peek()); 54 | } 55 | } 56 | return res; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code/lc322.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 322. Coin Change 4 | * 题意:不同面额零钱组合成总值,用的零钱数最少 5 | * 难度:Medium 6 | * 分类:Dynamic Programming 7 | * 思路:和lc279一样的思路,注意下没解的情况 8 | * Tips:不用Set, 加一个dp[0]=0,可以直接递归出结果 9 | */ 10 | import java.util.Arrays; 11 | import java.util.HashSet; 12 | 13 | public class lc322 { 14 | public static void main(String[] args) { 15 | System.out.println(coinChange(new int[]{2}, 3)); 16 | } 17 | public static int coinChange(int[] coins, int amount) { 18 | if(amount==0) return 0; 19 | int[] dp = new int[amount]; 20 | Arrays.fill(dp, Integer.MAX_VALUE); 21 | HashSet s = new HashSet(); 22 | for (int i = 0; i < coins.length ; i++) { 23 | s.add(coins[i]); 24 | } 25 | for (int i = 0; i < amount ; i++) { 26 | if(s.contains(i+1)) 27 | dp[i] = 1; 28 | else{ 29 | for (int j = 0; j < coins.length ; j++) { 30 | if( i+1-coins[j]>0 && dp[i - coins[j]]!=Integer.MAX_VALUE ) { // 注意子结构没解的情况 31 | dp[i] = Math.min(dp[i - coins[j]] + 1, dp[i]); 32 | } 33 | } 34 | } 35 | } 36 | return dp[amount-1]==Integer.MAX_VALUE ? -1 : dp[amount-1]; //没解返回-1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /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(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] mem){ 28 | if(root==null) 29 | return 0; 30 | if(mem.containsKey(root)) //用mem去记忆一下子情况的结果,防止重复计算 31 | return mem.get(root); 32 | int val =0; 33 | if(root.left!=null){ 34 | val += helper(root.left.left, mem); 35 | val += helper(root.left.right, mem); 36 | } 37 | if(root.right!=null){ 38 | val += helper(root.right.left, mem); 39 | val += helper(root.right.right, mem); 40 | } 41 | int res = Math.max(root.val+val, helper(root.left, mem)+helper(root.right, mem)); 42 | mem.put(root, res); 43 | return res; 44 | } 45 | 46 | public int rob2(TreeNode root) { 47 | return Math.max(helper2(root)[0], helper2(root)[1]); 48 | } 49 | public int[] helper2(TreeNode root){ 50 | int[] res = new int[2]; 51 | if(root==null) return res; 52 | int[] left = helper2(root.left); 53 | int[] right = helper2(root.right); 54 | res[0] = root.val + left[1] + right[1]; // res[0] 表示该节点被抢的最大结果,下层节点不能被抢 55 | res[1] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]); // res[1] 表示该节点不抢的最大结果。注意不抢该节点,下层节点可能被抢,也可能不被抢,取大的。 56 | return res; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code/lc338.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 338. Counting Bits 4 | * 题意:0~n数字上1的个数 5 | * 难度:Medium 6 | * 分类:Dynamic Programming, Bit Maniputation 7 | * 思路:把前几个数的二进制写出来,就很容易看出来dp公式,前边的值+1即可 8 | * Tips:注意细节,边界情况 9 | */ 10 | public class lc338 { 11 | public static void main(String[] args) { 12 | int[] res = countBits(0); 13 | for (int i = 0; i < res.length ; i++) { 14 | System.out.print(res[i]); 15 | System.out.print(" "); 16 | } 17 | } 18 | public static int[] countBits(int num) { 19 | int[] dp = new int[num+1]; 20 | int i = 1; 21 | while(i<=num) { 22 | dp[i] = 1; 23 | int max = i; 24 | for (int j = 0; jtarget){ 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/lc341.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | import java.util.Stack; 6 | 7 | public class lc341 { 8 | public interface NestedInteger { 9 | // @return true if this NestedInteger holds a single integer, rather than a nested list. 10 | public boolean isInteger(); 11 | // @return the single integer that this NestedInteger holds, if it holds a single integer 12 | // Return null if this NestedInteger holds a nested list 13 | public Integer getInteger(); 14 | // @return the nested list that this NestedInteger holds, if it holds a nested list 15 | // Return null if this NestedInteger holds a single integer 16 | public List getList(); 17 | } 18 | /** 19 | * Your NestedIterator object will be instantiated and called as such: 20 | * NestedIterator i = new NestedIterator(nestedList); 21 | * while (i.hasNext()) v[f()] = i.next(); 22 | */ 23 | public class NestedIterator implements Iterator { 24 | Stack stack = new Stack<>(); 25 | public NestedIterator(List nestedList) { 26 | for(int i = nestedList.size() - 1; i >= 0; i--) { 27 | stack.push(nestedList.get(i)); 28 | } 29 | } 30 | 31 | @Override 32 | public Integer next() { 33 | return stack.pop().getInteger(); 34 | } 35 | 36 | @Override 37 | public boolean hasNext() { 38 | while(!stack.isEmpty()) { 39 | NestedInteger curr = stack.peek(); 40 | if(curr.isInteger()) { 41 | return true; 42 | } 43 | stack.pop(); 44 | for(int i = curr.getList().size() - 1; i >= 0; i--) { 45 | stack.push(curr.getList().get(i)); 46 | } 47 | } 48 | return false; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /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/lc378.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.Comparator; 4 | import java.util.PriorityQueue; 5 | 6 | /* 7 | * 378. Kth Smallest Element in a Sorted Matrix 8 | * 题意:在矩阵中搜索第k大的数,横轴和纵轴都是有序的 9 | * 难度:Medium 10 | * 分类:Binary Search, Heap 11 | * 思路:两种思路。 1是类似多个有序链表合并的思路,优先队列。 12 | * 2是二分,二分的是val,看比这个val小的数是不是k 13 | * Tips:lc23方法很像 14 | * lc240 15 | */ 16 | public class lc378 { 17 | class Cell{ 18 | int val, row, col; 19 | Cell(int v, int r, int c){ 20 | val = v; 21 | row = r; 22 | col = c; 23 | } 24 | } 25 | public int kthSmallest(int[][] matrix, int k) { 26 | PriorityQueue pq = new PriorityQueue(new Comparator() { 27 | @Override 28 | public int compare(Cell o1, Cell o2) { 29 | return o1.val-o2.val; 30 | } 31 | }); 32 | for (int i = 0; i < matrix.length ; i++) pq.add(new Cell(matrix[i][0], i, 0)); 33 | while(k>1){ 34 | Cell c = pq.remove(); 35 | if(c.col+11){ 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/lc380.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | /* 8 | * 380. Insert Delete GetRandom O(1) 9 | * 题意:设计一个数据结构,插入,删除,随机获得一个元素 这三个操作的复杂度都为O(1) 10 | * 难度:Medium 11 | * 分类:Array, Hash Table, Design 12 | * 思路:List 的插入和删除都是O(1), 通过hashmap绑定来使得Get也为O(1) 13 | * Tips: 14 | */ 15 | public class lc380 { 16 | public class RandomizedSet { 17 | 18 | HashMap valToInd; 19 | List list; 20 | int ind = 0; 21 | 22 | /** Initialize your data structure here. */ 23 | public RandomizedSet() { 24 | valToInd = new HashMap<>(); 25 | list = new ArrayList<>(); 26 | } 27 | 28 | /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ 29 | public boolean insert(int val) { 30 | if(valToInd.containsKey(val)) return false; 31 | list.add(val); 32 | valToInd.put(val,list.size()-1); 33 | return true; 34 | } 35 | 36 | /** Removes a value from the set. Returns true if the set contained the specified element. */ 37 | public boolean remove(int val) { 38 | int ind = valToInd.getOrDefault(val,-1); 39 | if(ind == -1) return false; 40 | Collections.swap(list,ind,list.size()-1); 41 | int swappedWith = list.get(ind); 42 | valToInd.put(swappedWith,ind); 43 | list.remove(list.size()-1); 44 | valToInd.remove(val); 45 | return true; 46 | } 47 | 48 | /** Get a random element from the set. */ 49 | public int getRandom() { 50 | int max = list.size(); 51 | int min = 0; 52 | int ind = (int)(Math.random() * (max - min) + min); 53 | return list.get(ind); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /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)); 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) 24 | return res; 25 | List l = new ArrayList(); 26 | backtracking(res,candidates,target,l,0,0); 27 | return res; 28 | } 29 | 30 | public static void backtracking(List> res, int[] candidates, int target, List l, int sum, int start){ 31 | for (int i = start; i < candidates.length; i++) { 32 | l.add(candidates[i]); 33 | if(sum+candidates[i]==target) { 34 | res.add(new ArrayList<>(l));//new 新的 List 35 | } else if(sum+candidates[i] st = new Stack(); 18 | int i = 0; 19 | char[] str_arr = s.toCharArray(); 20 | StringBuilder res = new StringBuilder(); 21 | 22 | while(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 | */ 10 | public class lc5 { 11 | public static void main(String[] args) { 12 | String s = "cbbd"; 13 | System.out.println(longestPalindrome(s)); 14 | } 15 | 16 | public static String longestPalindrome(String s) { 17 | int n = s.length(); 18 | boolean[][] dp = new boolean[n][n]; 19 | String res = ""; 20 | for (int i = n-1; i>=0 ; i--) { 21 | for (int j = i; j res.length()) 26 | res = s.substring(i,j+1); // 起始索引,终止索引(不包括,所以+1) 27 | } 28 | } 29 | } 30 | return res; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /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/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 | */ 9 | public class lc53 { 10 | public static void main(String[] args) { 11 | int[] nums = {-2,1,-3,4,-1,2,1,-5,4}; 12 | System.out.println(maxSubArray(nums)); 13 | System.out.println(maxSubArray2(nums)); 14 | } 15 | 16 | public static int maxSubArray(int[] nums) { 17 | // dp[i] 表示以nums[i]结尾的最大和 18 | int[] dp = new int[nums.length]; 19 | dp[0] = nums[0]; 20 | int res = dp[0]; 21 | for (int i = 1; i 0 ? dp[i-1]+nums[i] : nums[i]; 23 | res = Math.max(res,dp[i]); 24 | } 25 | return res; 26 | } 27 | 28 | public static int maxSubArray2(int[] nums) { 29 | return DivideConquer(nums,0,nums.length-1); 30 | } 31 | 32 | public static int DivideConquer(int[] nums, int start, int end){ 33 | if(start == end) 34 | return nums[start]; 35 | else{ 36 | int mid = (start+end)/2; 37 | int left = DivideConquer(nums, start, mid); 38 | int right = DivideConquer(nums, mid+1, end); 39 | int temp = 0; 40 | int lmax = nums[mid]; 41 | for (int i = mid; i >=start ; i--) { 42 | temp += nums[i]; 43 | lmax = Math.max(temp,lmax); 44 | } 45 | temp = 0; 46 | int rmax = nums[mid+1]; 47 | for (int i = mid+1; i <= end ; i++) { 48 | temp += nums[i]; 49 | rmax = Math.max(temp,rmax); 50 | } 51 | return Math.max(Math.max(left,right),lmax+rmax); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /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/lc54.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 54. Spiral Matrix 4 | * 题意:螺旋输出矩阵 5 | * 难度:Medium 6 | * 分类:Array 7 | * 思路:很直接的思路,就是循环打印 8 | * Tips:需要注意很多细节,最后调试成功 9 | */ 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class lc54 { 14 | public static void main(String[] args) { 15 | int[][] matrix = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; 16 | System.out.println(spiralOrder(matrix)); 17 | } 18 | public static List spiralOrder(int[][] matrix) { 19 | List res = new ArrayList<>(); 20 | if(matrix.length==0) return res; 21 | int r=0, c=-1; // -1开始,循环内首先++ 22 | int row_r = matrix.length; 23 | int col_r = matrix[0].length; 24 | int row_l = -1; 25 | int col_l =-1; 26 | while( row_l+1col_l){ 47 | while(c>col_l){ 48 | res.add(matrix[r][c]); 49 | c--; 50 | } 51 | }else 52 | return res; 53 | c++; 54 | r--; 55 | if(r>row_l+1) { 56 | while (r > row_l + 1) { 57 | res.add(matrix[r][c]); 58 | r--; 59 | } 60 | }else 61 | return res; 62 | r++; 63 | row_l++; 64 | row_r--; 65 | col_l++; 66 | col_r--; 67 | } 68 | return res; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /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/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 | * Tips: 10 | */ 11 | public class lc572 { 12 | public class TreeNode { 13 | int val; 14 | TreeNode left; 15 | TreeNode right; 16 | TreeNode(int x) { val = x; } 17 | } 18 | 19 | public boolean isSubtree(TreeNode s, TreeNode t) { 20 | if (s == null) return false; 21 | return helper(s,t) || isSubtree(s.left,t) ||isSubtree(s.right,t); // 注意递归方法的不同,是调用哪个函数 22 | } 23 | public boolean helper(TreeNode s, TreeNode t){ 24 | if( s==null && t==null ) return true; 25 | if( s==null || t==null || s.val!=t.val ) return false; 26 | return helper(s.left, t.left) && helper(s.right, t.right); 27 | } 28 | 29 | public boolean isSubtree2(TreeNode s, TreeNode t) { 30 | StringBuilder tree1 = new StringBuilder(); 31 | StringBuilder tree2 = new StringBuilder(); 32 | helper2(s, tree1); 33 | helper2(s, tree2); 34 | return tree1.toString().contains(tree2.toString()); 35 | } 36 | public void helper2(TreeNode node, StringBuilder res){ 37 | if(node==null) 38 | res.append(",#"); //先放','表示一个新节点的开始,#代表null 39 | else { 40 | res.append( ","+node.val ); 41 | helper2(node.left, res); 42 | helper2(node.right, res); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /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/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); 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/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("intention","execution")); 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> 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 | * 31. 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/lc877.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 877. Stone Game 4 | * 题意:两个人拿石头堆,每次只能从最左边或最右边拿 5 | * 难度:Medium 6 | * 分类:Math, Dynamic Programming, Minimax 7 | * 思路:之前做过有印象,先拿的人一定赢的。 8 | * dp的思路需要借鉴一下的, dp[i][j] 表示数组 i~j 的最优解 9 | * 向两边拓展的dp, 用一个变量表示 size 这个dp。想想一下三角形的区域是怎么一步步被填满的,斜线斜线的,最后是一个点 10 | * 拿了piles[i], 则dp[i+1][j]就被另一个人拿了,结果是 piles[i] - dp[i + 1][j] 11 | * 拿了piles[j], 则dp[i][j-1]就被另一个人拿了,结果是 piles[j] - dp[i][j - 1] 12 | * Tips: 13 | */ 14 | public class lc877 { 15 | public boolean stoneGame(int[] piles) { 16 | return true; 17 | } 18 | 19 | public boolean stoneGame2(int[] piles) { 20 | int[][] dp = new int[piles.length][piles.length]; 21 | for (int i = 0; i < piles.length ; i++) dp[i][i] = piles[i]; //最后是第二个人拿的,用符号 22 | for (int size = 1; size < piles.length ; size++) { //外循环是 size 23 | for (int i = 0; i+size < piles.length ; i++) { //size0; 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: 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/lc94.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 94. Binary Tree Inorder Traversal 4 | * 题意: 5 | * 难度:Medium 6 | * 分类:HashTable, Stack, Tree 7 | * 思路:左节点依次入栈二叉树中序遍历 8 | * Tips:和lc144前序,lc145后序一起看 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) 24 | return res; 25 | Stack st = new Stack(); 26 | while( !st.isEmpty() || root!=null ) { //注意停止条件 27 | while (root != null) { 28 | st.push(root); 29 | root = root.left; 30 | } 31 | root = st.pop(); 32 | res.add(root.val); 33 | root = root.right; 34 | } 35 | return res; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /code/lc95.java: -------------------------------------------------------------------------------- 1 | package code; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | 6 | /* 7 | * 95. Unique Binary Search Trees II 8 | * 题意:1~n可以组成的二叉搜索树 9 | * 难度:Medium 10 | * 分类:Dynamic Programming, Tree 11 | * 思路:96只要求计算数量,dp就行,当要把所有情况都输出的时候,往往递归更方便一些 12 | * 返回的的是跟的List,不用把整颗数的节点都复制了,所以下层的叶子节点是被多个父节点指向 13 | * 暴力,子情况被计算了多遍,为什么不用mem呢??? 14 | * Tips:lc96 15 | */ 16 | public class lc95 { 17 | public class TreeNode { 18 | int val; 19 | TreeNode left; 20 | TreeNode right; 21 | TreeNode(int x) { val = x; } 22 | } 23 | public List 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 = max_bound || root.val <= min_bound) return false; 33 | return dfs(root.left, min_bound, root.val) && dfs(root.right, root.val, max_bound); 34 | } 35 | 36 | public static boolean isValidBST2(TreeNode root) { 37 | if(root == null) 38 | return true; 39 | Stack st = new Stack(); 40 | TreeNode pre = null; 41 | while( !st.isEmpty() || root!=null ){ 42 | while(root!=null){ 43 | st.add(root); 44 | root = root.left; 45 | } 46 | root = st.pop(); 47 | if( pre!=null && root.val<=pre.val ) //先序遍历,自下而上,孩子节点小于父节点 48 | return false; 49 | pre = root; 50 | root = root.right; 51 | } 52 | return true; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /code/lc983.java: -------------------------------------------------------------------------------- 1 | package code; 2 | /* 3 | * 983. Minimum Cost For Tickets 4 | * 题意:两个数组,days代表那一天得去玩,costs表示玩1天,2天,7天的花费,问怎么玩可以把days覆盖,并且花费最少 5 | * 难度:Medium 6 | * 分类:Dynamic Programming 7 | * 思路:猛一看题,感觉很难 8 | * 想了以后,会发现就是典型的数组dp,难的地方主要在于数组不代表每天,如何把days中的天全部覆盖到 9 | * 方法是将days转换为一个365长的arr,代表每一天 10 | * 如果这一天不在days中,则 dp[i] = dp[i-1], 否则 dp[i] = min(d p[i-1]+cost , dp[i-2]+cost ,dp[i-7]+cost ) 11 | * Tips: 12 | */ 13 | public class lc983 { 14 | public int mincostTickets(int[] days, int[] costs) { 15 | int[] dp = new int[366]; //366,把0空出来 16 | int days_cur = 0; 17 | for (int i = 1; i < dp.length ; i++) { 18 | if(i==days[days_cur]) { //在days中 19 | int minCost = dp[Math.max(0, i-1)]+costs[0]; 20 | minCost = Math.min( minCost, dp[Math.max(0, i-7)]+costs[1] ); 21 | minCost = Math.min( minCost, dp[Math.max(0, i-30)]+costs[2] ); 22 | dp[i] = minCost; 23 | if(days_cur