From 6e70e3a7f7298918483b69301c78b8c3ab71ed56 Mon Sep 17 00:00:00 2001 From: liu13 <1099976891@qq.com> Date: Wed, 27 Feb 2019 10:26:35 +0800 Subject: [PATCH] 20190227 --- code/lc218.java | 53 ++++++++++++++++++++++++++++++++++++++++++ code/lc227.java | 48 ++++++++++++++++++++++++++++++++++++++ code/lc230.java | 37 +++++++++++++++++++++++++++++ code/lc289.java | 49 ++++++++++++++++++++++++++++++++++++++ code/lc295.java | 28 ++++++++++++++++++++++ code/lc315.java | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ readme.md | 1 + 7 files changed, 278 insertions(+) create mode 100644 code/lc218.java create mode 100644 code/lc227.java create mode 100644 code/lc230.java create mode 100644 code/lc289.java create mode 100644 code/lc295.java create mode 100644 code/lc315.java diff --git a/code/lc218.java b/code/lc218.java new file mode 100644 index 0000000..021387b --- /dev/null +++ b/code/lc218.java @@ -0,0 +1,53 @@ +package code; + +import java.util.*; +/* + * 218. The Skyline Problem + * 题意:高楼轮廓 + * 难度:Hard + * 分类:Divide and Conquer, Heap, Binary indexed Tree, Segment Tree + * 思路:转化为坐标,按x排序。左端点add,右端点remove,用优先队列输出y坐标,如果y更改了就输出。 + * Tips: + */ +public class lc218 { + public static void main(String[] args) { + int[][] buildings = {{0,2,3}, {2,5,3}}; + getSkyline(buildings); + } + public static List getSkyline(int[][] buildings) { + List res = new ArrayList<>(); + int[][] arr = new int[buildings.length*2][2]; + for (int i = 0, j=0; i < buildings.length ; i++) { //转换成坐标 + arr[j][0] = buildings[i][0]; + arr[j][1] = buildings[i][2]; + j++; + arr[j][0] = buildings[i][1]; + arr[j][1] = -buildings[i][2]; //结束节点y用负数表示 + j++; + } + Arrays.sort(arr, new Comparator() { //定义比较方法 + @Override + public int compare(int[] o1, int[] o2) { + if(o1[0]!=o2[0]) + return o1[0] - o2[0]; + else + return o2[1] - o1[1]; //注意这一点,防止 {{0,2,3}, {2,5,3}} case。 两个点重合了不会连续输出。 + } + }); + PriorityQueue pr = new PriorityQueue(); + pr.add(0); + int pre = 0; + for (int i = 0; i < arr.length ; i++) { + if(arr[i][1]>0){ + pr.add(-arr[i][1]); + }else{ + pr.remove(arr[i][1]); + } + if(pr.peek()!=pre){ + res.add(new int[]{arr[i][0], -pr.peek()}); + pre = pr.peek(); + } + } + return res; + } +} diff --git a/code/lc227.java b/code/lc227.java new file mode 100644 index 0000000..6655777 --- /dev/null +++ b/code/lc227.java @@ -0,0 +1,48 @@ +package code; + +import java.util.Stack; + +/* + * 227. Basic Calculator II + * 题意:表达式计算 + * 难度:Medium + * 分类:String + * 思路:很巧妙的方法,每次遍历到下一个符号的时候,计算前一个符号的运算,泥面膜了复杂的逻辑。 + * + - 运算直接入栈,* / 运算则计算后将结果入栈,实现了 * / 优先运算 + * Tips:自己想的方法会非常麻烦。这个解法非常聪明。 + */ +public class lc227 { + public int calculate(String s) { + char[] chs = s.replace(" ","").toCharArray(); + int num = 0; + char sign = '+'; + Stack st = new Stack(); + for (int i = 0; i < chs.length ; i++) { + if(Character.isDigit(chs[i])){ + num = num * 10 + chs[i]-'0'; + } + if( !Character.isDigit(chs[i]) || i==chs.length-1 ){ //便利到最后,即使不是符号,也要计算 + if(sign=='+'){ + st.push(num); + } + else if(sign=='-'){ + st.push(-num); + } + else if(sign=='*'){ + st.push(st.pop()*num); + } + else if(sign=='/'){ + st.push(st.pop()/num); + } + num = 0; + sign = chs[i]; //非常聪明 + } + } + int res = 0; + for(Integer i : st){ + System.out.println(i); + res += i; + } + return res; + } +} diff --git a/code/lc230.java b/code/lc230.java new file mode 100644 index 0000000..016ab39 --- /dev/null +++ b/code/lc230.java @@ -0,0 +1,37 @@ +package code; + +import java.util.Stack; + +/* + * 230. Kth Smallest Element in a BST + * 题意:二叉搜索树种第k小的数 + * 难度:Medium + * 分类:Binary Search, Tree + * 思路:每次找到最小的值,k--。中序遍历。 + * Tips:非递归中序遍历还是不熟练。。。 + */ +public class lc230 { + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + } + } + public int kthSmallest(TreeNode root, int k) { + Stack st = new Stack(); + while(!st.isEmpty()||root!=null){ + while(root!=null) { + st.add(root); + root = root.left; + } + root = st.pop(); + k--; + if(k==0) return root.val; + root = root.right; + } + return 0; + } +} diff --git a/code/lc289.java b/code/lc289.java new file mode 100644 index 0000000..b8bdd25 --- /dev/null +++ b/code/lc289.java @@ -0,0 +1,49 @@ +package code; +/* + * 289. Game of Life + * 题意:按照游戏规则,计算下一个时刻的矩阵,inpalce + * 难度:Medium + * 分类:Array + * 思路:和lc130的trick很类似,先替换为其他值,最后再置回 + * 需要注意几点,用2-bit表示状态转移,用&和位移操作省时 + * 需要更新下规则与现在的表示一致 + * Tips: + */ +public class lc289 { + public void gameOfLife(int[][] board) { + if (board == null || board.length == 0) return; + int m = board.length, n = board[0].length; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + int lives = liveNeighbors(board, m, n, i, j); + + // In the beginning, every 2nd bit is 0; + // So we only need to care about when will the 2nd bit become 1. + if (board[i][j] == 1 && lives >= 2 && lives <= 3) { + board[i][j] = 3; // Make the 2nd bit 1: 01 ---> 11 + } + if (board[i][j] == 0 && lives == 3) { + board[i][j] = 2; // Make the 2nd bit 1: 00 ---> 10 + } + } + } + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + board[i][j] >>= 1; // Get the 2nd state. + } + } + } + + public int liveNeighbors(int[][] board, int m, int n, int i, int j) { + int lives = 0; + for (int x = Math.max(i - 1, 0); x <= Math.min(i + 1, m - 1); x++) { // 用max,min判断边界 + for (int y = Math.max(j - 1, 0); y <= Math.min(j + 1, n - 1); y++) { + lives += board[x][y] & 1; + } + } + lives -= board[i][j] & 1; //减去自己 + return lives; + } +} diff --git a/code/lc295.java b/code/lc295.java new file mode 100644 index 0000000..3807af3 --- /dev/null +++ b/code/lc295.java @@ -0,0 +1,28 @@ +package code; + +import java.util.PriorityQueue; + +public class lc295 { + class MedianFinder { + PriorityQueue pq1; //默认是最小,右半边 + PriorityQueue pq2; //左半边 + + /** initialize your data structure here. */ + public MedianFinder() { + this.pq1 = new PriorityQueue(); + this.pq2 = new PriorityQueue(); + } + + public void addNum(int num) { + pq1.add(num); //两个队列都过一遍 + pq2.add(-pq1.poll()); + if (pq1.size() < pq2.size()) //如果中位数是一个数,就存在左半边 + pq1.add(-pq2.poll()); + } + + public double findMedian() { + if(pq1.size()==pq2.size()+1) return pq1.peek(); + return -((double)(-pq1.peek()+pq2.peek()))/2; + } + } +} diff --git a/code/lc315.java b/code/lc315.java new file mode 100644 index 0000000..61defc0 --- /dev/null +++ b/code/lc315.java @@ -0,0 +1,62 @@ +package code; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +/* + * 315. Count of Smaller Numbers After Self + * 题意:给一个数组,计算这个数右边比这个数小的数的个数 + * 难度:Hard + * 分类:Divide and Conquer, Binary indexed Tree, Segment Tree, Binary Search Tree + * 思路:两种思路,一种用二叉搜索树这类数据结构 https://leetcode.com/problems/count-of-smaller-numbers-after-self/discuss/76580/9ms-short-Java-BST-solution-get-answer-when-building-BST + * 一种归并排序的思路,归并的时候统计左右交换数目。如果一个数从这个数的右边交换到左边,则+1。因为有重复数字,所以用将ndex进行排序 + * https://leetcode.com/problems/count-of-smaller-numbers-after-self/discuss/76583/11ms-JAVA-solution-using-merge-sort-with-explanation + * 再有一种复杂度稍微高点的思路,从后往前插入排序,插入的时候二分搜索 + * https://leetcode.com/problems/count-of-smaller-numbers-after-self/discuss/76576/My-simple-AC-Java-Binary-Search-code + * Tips:好难呀,我日! + */ +public class lc315 { + class TreeNode{ + int val; + int dup_num; + int sum; + TreeNode left; + TreeNode right; + TreeNode(int val, int dup_num, int sum){ + this.val = val; + this.dup_num = dup_num; //相同点的数目 + this.sum = sum; //该节点左下节点个数,也就是比该节点值小的 + } + } + + TreeNode root; + public List countSmaller(int[] nums) { + if(nums.length<1) return new ArrayList<>(); + Integer[] res_arr = new Integer[nums.length]; //用res_arr保存结果,否则结束了还要遍历数来找结果 + root = new TreeNode(nums[nums.length-1], 1, 0); + res_arr[nums.length-1] = 0; + for (int i = nums.length-2; i >=0 ; i--) { + insert(root, nums[i], res_arr, i, 0); + } + return Arrays.asList(res_arr); //数组转换为list + } + + public TreeNode insert(TreeNode tn, int n, Integer[] res_arr, int i, int path){ //path记录了路径上比该点小的节点的个数 + if(tn==null) { + tn = new TreeNode(n, 1, 0); + res_arr[i] = path; + System.out.print(i); + System.out.println("----"+path); + } + else if(tn.val==n){ + tn.dup_num++; + res_arr[i] = path + tn.sum; + }else if(tn.val>n){ + tn.sum++; + tn.left = insert(tn.left, n, res_arr, i, path); + }else{ + tn.right = insert(tn.right, n, res_arr, i, path + tn.dup_num + tn.sum); + } + return tn; //递归,返回的结果为节点,供上层节点赋值 + } +} diff --git a/readme.md b/readme.md index a67f2b1..3d9ccf8 100644 --- a/readme.md +++ b/readme.md @@ -135,6 +135,7 @@ Language: Java | 301 [Java](./code/lc301.java) | 309 [Java](./code/lc309.java) | 312 [Java](./code/lc312.java) + | 322 [Java](./code/lc322.java) | 337 [Java](./code/lc337.java) | 338 [Java](./code/lc338.java) -- GitLab