diff --git a/Week_01/id_1/NOTE.md b/Week_01/id_1/NOTE.md index f0988620..38a762c1 100644 --- a/Week_01/id_1/NOTE.md +++ b/Week_01/id_1/NOTE.md @@ -1,3 +1,5 @@ +# 学习笔记 +======= ### 一. 第一周学习总结 #### 1. 关于链表题目的做题总结 diff --git a/Week_01/id_80/LeetCode_20_80.java b/Week_01/id_80/LeetCode_20_80.java new file mode 100644 index 00000000..2c8cacf8 --- /dev/null +++ b/Week_01/id_80/LeetCode_20_80.java @@ -0,0 +1,39 @@ +/** + * + * https://leetcode-cn.com/problems/valid-parentheses/ + */ +class Solution { + private HashMap mappings; + public Solution(){ + this.mappings = new HashMap(); + this.mappings.put('(', ')'); + this.mappings.put('{', '}'); + this.mappings.put('[', ']'); + + } + public boolean isValid(String s) { + Stack stack=new Stack<>(); + char[] chars = s.toCharArray(); + for(char c:chars){ + if(stack.size()==0){ + stack.push(c); + }else if(isSym(stack.peek(),c)){ + stack.pop(); + }else{ + stack.push(c); + } + } + return stack.isEmpty(); + } + + private boolean isSym(char c1, char c2) { + if(mappings.containsKey(c1)){ + if(mappings.get(c1)!=c2){ + return false; + }else{ + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/Week_01/id_80/LeetCode_21_80.java b/Week_01/id_80/LeetCode_21_80.java new file mode 100644 index 00000000..3197c0df --- /dev/null +++ b/Week_01/id_80/LeetCode_21_80.java @@ -0,0 +1,42 @@ +/** + * https://leetcode-cn.com/problems/merge-two-sorted-lists/ + * + * Definition for singly-linked list. + * public class ListNode { int val; ListNode + * next; ListNode(int x) { val = x; } } + */ +class Solution { + public ListNode mergeTwoLists(ListNode l1, ListNode l2) { + if (l2 == null) + return l1; + if (l1 == null) + return l2; + ListNode p1 = l1; + ListNode p2 = l2; + ListNode start; + if (l1.val < l2.val) { + start = l1; + } else { + start = l2; + } + do { + if (p2.val <= p1.val) { + while (p2.next != null && p2.next.val <= p1.val) { + p2 = p2.next; + } + l2 = p2.next; + p2.next = p1; + } else { + while (p1.next != null && p1.next.val < p2.val) { + p1 = p1.next; + } + l2 = p2.next; + p2.next = p1.next; + p1.next = p2; + } + + p2 = l2; + } while (p2 != null); + return start; + } +} \ No newline at end of file diff --git a/Week_01/id_80/LeetCode_83_80.java b/Week_01/id_80/LeetCode_83_80.java new file mode 100644 index 00000000..a68ab595 --- /dev/null +++ b/Week_01/id_80/LeetCode_83_80.java @@ -0,0 +1,23 @@ +/** + * https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/ + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { val = x; } + * } + */ +class Solution { + public ListNode deleteDuplicates(ListNode head) { + ListNode current=head; + while(current!=null&¤t.next!=null){ + ListNode next=current.next; + if(current.val==next.val){ + current.next=next.next; + }else{ + current=current.next; + } + } + return head; + } +} \ No newline at end of file diff --git a/Week_01/id_80/LeetCode_905_80.java b/Week_01/id_80/LeetCode_905_80.java new file mode 100644 index 00000000..8ff21db4 --- /dev/null +++ b/Week_01/id_80/LeetCode_905_80.java @@ -0,0 +1,25 @@ +class Solution { + public int[] sortArrayByParity(int[] A) { + int length=A.length; + if(length>=1&&length<=5000){ + int[] B=new int[length]; + int l=0; + int r=0; + for(int i=0;i sMap = new HashMap<>(); + //HashMap tMap = new HashMap<>(); + char[] chars = s.toCharArray(); + char[] chart = t.toCharArray(); + for (char cs:chars){ + if (sMap.containsKey(cs)) { + int count = sMap.get(cs); + count++; + sMap.put(cs, count); + } else { + sMap.put(cs, 1); + } + } + for (char ct:chart){ + if(sMap.containsKey(ct)){ + int count=sMap.get(ct); + count--; + if(count==0){ + sMap.remove(ct); + }else{ + sMap.put(ct,count); + } + }else{ + return false; + } + } + return sMap.keySet().size() == 0; + } else { + return false; + } + + } +} \ No newline at end of file diff --git a/Week_02/id_80/LeetCode_671_80.java b/Week_02/id_80/LeetCode_671_80.java new file mode 100644 index 00000000..e69de29b diff --git a/Week_02/id_80/LeetCode_692_80.java b/Week_02/id_80/LeetCode_692_80.java new file mode 100644 index 00000000..2ee8ea97 --- /dev/null +++ b/Week_02/id_80/LeetCode_692_80.java @@ -0,0 +1,58 @@ +class Solution { + + + public List topKFrequent1(String[] words, int k) { + Map count = new HashMap(); + for (String word: words) { + count.put(word, count.getOrDefault(word, 0) + 1); + } + List candidates = new ArrayList(count.keySet()); + Collections.sort(candidates, (w1, w2) -> count.get(w1).equals(count.get(w2)) ? + w1.compareTo(w2) : count.get(w2) - count.get(w1)); + + return candidates.subList(0, k); + } + + public List topKFrequent(String[] words, int k) { + Map countMap = new HashMap<>(); + for (String str : words) { + Integer count = countMap.get(str); + if (count != null) { + count++; + } else { + count = 1; + } + countMap.put(str, count); + } + Map> listMap = new HashMap<>(); + + for (String key : countMap.keySet()) { + Integer count = countMap.get(key); + List stringList = listMap.get(count); + if (stringList == null) { + stringList = new ArrayList<>(); + } + stringList.add(key); + listMap.put(count, stringList); + } + + Set keySet = listMap.keySet(); + Object[] keyArray = keySet.toArray(); + Arrays.sort(keyArray); + List resultList = new ArrayList<>(); + for (int i = keyArray.length - 1; i >= 0; i--) { + Object count = keyArray[i]; + List sl = listMap.get(count); + Object[] ss = sl.toArray(); + Arrays.sort(ss); + for (Object s : ss) { + if (resultList.size() < k) { + resultList.add(String.valueOf(s)); + } else { + return resultList; + } + } + } + return resultList; + } +} \ No newline at end of file diff --git a/Week_02/id_80/LeetCode_783_80.java b/Week_02/id_80/LeetCode_783_80.java new file mode 100644 index 00000000..92476ddf --- /dev/null +++ b/Week_02/id_80/LeetCode_783_80.java @@ -0,0 +1,48 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + + int last = -1000000; + int res = 1000000; + public int minDiffInBST(TreeNode root) { + if (root == null) { + return 0; + } + minDiffInBST(root.left); + res = Math.min(root.val - last, res); + last = root.val; + minDiffInBST(root.right); + return res; + } + + + //此答案对应题目:返回相邻两节点差的最小值。 + public int minDiffInBST1(TreeNode root) { + int minDiff=getDiff(root,0); + return minDiff; + } + + public int getDiff(TreeNode root,int val){ + if(root!=null){ + int currentMin=Math.abs(root.val-val); + if(root.left!=null){ + currentMin=Math.min(getDiff(root.left,root.val),currentMin); + } + if(root.right!=null){ + currentMin=Math.min(getDiff(root.right,root.val),currentMin); + } + + return currentMin; + }else{ + return Integer.MAX_VALUE; + } + + } +} \ No newline at end of file diff --git a/Week_02/id_80/LeetCode_938_80.java b/Week_02/id_80/LeetCode_938_80.java new file mode 100644 index 00000000..8e02db43 --- /dev/null +++ b/Week_02/id_80/LeetCode_938_80.java @@ -0,0 +1,99 @@ +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +class Solution { + int sum=0; + //迭代法 + public int rangeSumBST(TreeNode root, int L, int R) { + if(L > R) return 0; + if(root == null) return 0; + Stack stack = new Stack<>(); + TreeNode cur = root; + while(!stack.isEmpty() || cur != null){ + if(cur != null){ + stack.push(cur); + cur = cur.left; + }else{ + cur = stack.pop(); + if(cur.val >= L && cur.val <= R){ + sum += cur.val; + } + cur = cur.right; + } + + } + return sum; + } + + //递归 + //后序法 + public int rangeSumBST_1(TreeNode root, int L, int R) { + if(root!=null){ + if(root.left!=null){ + rangeSumBST(root.left,L,R); + } + if(root.right!=null){ + rangeSumBST(root.right,L,R); + } + if(root.val>=L&&root.val<=R){ + sum+=root.val; + } + } + return sum; + } + + //中序法 + public int rangeSumBST0(TreeNode root, int L, int R) { + if(root!=null){ + if(root.left!=null){ + rangeSumBST(root.left,L,R); + } + if(root.val>=L&&root.val<=R){ + sum+=root.val; + } + if(root.right!=null){ + rangeSumBST(root.right,L,R); + } + } + return sum; + } + + + //前序法 + public int rangeSumBST1(TreeNode root, int L, int R) { + if(root!=null){ + if(root.val>=L&&root.val<=R){ + sum+=root.val; + } + + rangeSumBST(root.left,L,R); + + rangeSumBST(root.right,L,R); + + } + return sum; + } + + //前序法 + public int rangeSumBST2(TreeNode root, int L, int R) { + int sum=0; + if(root!=null){ + if(root.val>=L&&root.val<=R){ + sum+=root.val; + } + if(root.left!=null){ + sum+=rangeSumBST(root.left,L,R); + } + if(root.right!=null){ + sum+=rangeSumBST(root.right,L,R); + } + } + return sum; + } +} \ No newline at end of file diff --git a/Week_02/id_80/NOTE.md b/Week_02/id_80/NOTE.md index c684e62f..cf9b3d56 100644 --- a/Week_02/id_80/NOTE.md +++ b/Week_02/id_80/NOTE.md @@ -1 +1,8 @@ -# 学习笔记 \ No newline at end of file +# week2 作业总结 + +1. 在做leetcode783 作业的过程中。由于对题目理解有误 导致解决思路完全,最后在提交的时候会不成功,再次审题才发现问题,不过先前解决的题目的思路也可当作做另外一个题目的答案,也算有所一点收获。 +2. 二叉树 复习的过程心得,在项目生产环境中,算法只是解决问题的工具。不能把为了使用某种算法而某种使用算法,有些算法的适用场景,比如散列表和二叉树的选择问题: + 1. 散列表数据是无序存储的,如果要输出有序数据需要进行排序,而二叉查找树,只需要中序遍历即可 + 2. 散列表扩容耗时比较多,而且当遇到散列冲突的时候,性能不稳定,尽管二叉查找树性能不稳定,但在工程中,我们常用的平衡二叉查找树性能非常稳定,时间复杂度稳定在O(logn). + 3. 笼统的来说,散列表由于有哈希冲突的存在,时间复杂度不一定比比O(longn)小。加上哈希函数的耗时,也不一定比平衡二叉树的效率高。 + 4. 散列表的构造比二叉查找树要复杂,需要考虑的东西很多。为了避免过多的散列冲突,散列表装载因子不能太大,特别是基于开放寻址法解决冲突的散列表,不然会浪费一定的存储空间。 diff --git a/Week_03/id_80/LeetCode_210_80.java b/Week_03/id_80/LeetCode_210_80.java new file mode 100644 index 00000000..32d760d5 --- /dev/null +++ b/Week_03/id_80/LeetCode_210_80.java @@ -0,0 +1,31 @@ +class Solution { + + public int[] findOrder(int numCourses, int[][] prerequisites) { + + LinkedList[] neiList = new LinkedList[numCourses]; + for(int i=0;i(); + //source[i] 记录节点i有几个邻居指向节点i + int[] source = new int[numCourses]; + for(int[] pair:prerequisites) { + neiList[pair[1]].add(pair[0]); + source[pair[0]]++; + } + //unreachable记录不可达的节点 + int[] unreachable = new int[numCourses]; + int cur = 0; + for(int i=0;i q ; + final int k ; + public KthLargest(int k, int[] nums) { + this.k = k ; + q = new PriorityQueue<>(k); + for(int i : nums ){ + add(i); + } + } + + public int add(int n) { + // 返回第K大的数字 + if(q.size() < k ){ + q.offer(n); + }else if(q.peek() < n) { + q.poll(); + q.offer(n); + } + return q.peek(); + } + + } + + /** + * Your KthLargest object will be instantiated and called as such: + * KthLargest obj = new KthLargest(k, nums); + * int param_1 = obj.add(val); + */ \ No newline at end of file diff --git a/Week_03/id_80/LeetCode_997_80.java b/Week_03/id_80/LeetCode_997_80.java new file mode 100644 index 00000000..0e9f193c --- /dev/null +++ b/Week_03/id_80/LeetCode_997_80.java @@ -0,0 +1,18 @@ +//通过出度入度 来判断 +//如果是秘密法官,则入度 =N-1,出度 =0; +class Solution { + public int findJudge(int N, int[][] trust) { + int[][] peoples = new int[N][2]; + for(int[] people : trust){ + int out = people[0]; + int in = people[1]; + peoples[out - 1][0] ++; + peoples[in - 1][1] ++; + } + for(int i = 0; i < N; i++){ + if(peoples[i][0] == 0 && peoples[i][1] == N - 1) + return i + 1; + } + return -1; + } +} \ No newline at end of file diff --git a/Week_03/id_80/NOTE.md b/Week_03/id_80/NOTE.md index c684e62f..e0333ae2 100644 --- a/Week_03/id_80/NOTE.md +++ b/Week_03/id_80/NOTE.md @@ -1 +1,125 @@ -# 学习笔记 \ No newline at end of file +# 学习笔记 +针对图 进行了一次重新学习 +用自己的语言和作图工具做了一篇新的总结 + +## 一. 是什么? + +1. 图 和 树一样都属于 非线性表数据结构,图是一种更加复杂的非线性表结构。 + +2. 图中元素 叫做**顶点**,图中顶点与其他顶点建立连接关系。这种建立的关系叫做 **边**, 与顶点相链接的边的条数叫做 **度**。 + +3. 图 分为根据**边**是否有方向,分为 **有向图** 和 **无向图**。ex:A 用户关注了 B 用户,则 A 指向 B. + +4. 有向图 把度 分为 **入度** 和 **出度**,**入度** 表示有多少条边指向顶点。**出度** 表示以这个顶点为起点,指向其他顶点。ex:微博入度表示有多少粉丝,出度就是关注了多少人。 +5. **带权图**,表示每条表都有权重(weight)。ex:QQ 好友间的亲密度 + + + + +## 二. 如何实现的?怎么使用? +##### 存储方式 +**1. 邻接矩阵存储方法** + +邻接矩阵的底层依赖一个二维数组。对于无向图来说,如果顶点 i 与 顶点 j 之间 有边,我们就将 A[i][j] 和 A[j][i] 标记为 1; + +对于有向图来说,如果顶点 i 到 顶点 j 之间,有一条箭头从顶点 i 指向顶点 j 的边,那我们就将 A[i][j]标记为1.同理,如果有一条箭头从顶点 j 指向 顶点 i 的边,我们就将A[j][i] 标记为 1 。 + +对于带权图,数组中就存储相应的权重。 + + +![邻接矩阵](https://raw.githubusercontent.com/brokge/drawio/master/android-draw/%E5%9B%BE_%E9%82%BB%E6%8E%A5%E7%9F%A9%E9%98%B5.png) + + +1. 用邻接矩阵来表示一个图,虽然简单、直观,但是比较浪费存储空间。 +2. 因为基于数组,所以获取两个顶点的关系时,就非常高效。 +3. 其次用邻接矩阵存储图的另外一个好处是方便计算,这是因为用邻接矩阵的方式存储图,可以将很多图的运算转换成矩阵之间的运算。 + + + +**2. 邻接表存储方法** + +邻接表有点像散列表,每个顶点对应一条链表,链表中存储的是与这个顶点相连接的其他顶点。图中画的是一个有向图的邻接表存储方式,每个顶点对应的链表里面,存储的是指向的顶点。对于无向图来说也是类似,不过每个顶点的链表存储的,是跟这个顶点有边相连的顶点。 + +![邻接表](https://raw.githubusercontent.com/brokge/drawio/master/android-draw/%E5%9B%BE_%E9%82%BB%E6%8E%A5%E8%A1%A8.png) + +**时间、空间复杂度互换思想** + +邻接矩阵存储起来比较浪费空间,但是使用起来比较节省时间。 +邻接表存储起来比较节省空间,但是使用起来比较耗时间。 + +基于邻接表可以把采用 基于链表法解决冲突的散列表中。可以把链表替换成更加高效的数据结构,比如二叉查找树、红黑树、跳表、散列表、有序动态数组(通过二分查找方法快速定位两个顶点是否存在边) + + +## 三,可以解决什么问题?实际应用举例 + +微博 和 微信 +微博是有向图,微信是无向图。 + +数据结构是为算法服务的,所以具体选择哪种存储方法,与期望支持的操作有关系。针对微博用户关系,假设我们需要支持下面这样几个操作。 + +1. 判断用户 A 是否关注了 用户 B; +2. 判断用户 A 是否是用户 B 的粉丝; +3. 用户 A 关注了用户 B; +4. 用户 A 取消关注用户 B; +5. 根据用户名称的首字母排序,分页获取用户的粉丝列表; +6. 根据用户名称的首字母排序,分页获取用户的关注列表; + + +如何存储一张图,前面我们讲到两种主要的存储方法,邻接矩阵法 和 邻接表。因为社交网络是一张稀疏图,使用邻接矩阵法浪费存储空间。所以这里我们采用邻接表来存储。 + +但是,单纯的用邻接表来存储这种有向图,是不够的。查找某个用户关注了哪些用户非常容易,但是如果要想知道某个用户都被哪些用户关注了,也就是用户的粉丝列表,是非常困难的。 + +所以,我们需要一个逆邻接表。邻接表存储的是用户的关注关系,逆邻接表存储的是用户的被关注关系。 + + +![image](https://raw.githubusercontent.com/brokge/drawio/master/android-draw/%E5%9B%BE_%E9%80%86%E9%82%BB%E6%8E%A5%E8%A1%A8.png) + + +**邻接表 改进** + +基础的邻接表不适合快速判断两个用户之间是否是关注与被关注的关系,所以我们选择改进版,将邻接表中的链表改为支持快速查找的动态数据结构。 + +因为需要按照用户名称的首字母排序,分页来获取用户的粉丝列表或者被关注列表,用**跳表**就非常合适了。这是因为跳表插入、删除、查找都非常高效,时间复杂度是 O(logn),空间复杂度稍高,是 O(n)。 + +更重要的一点,跳表中存储的数据本来就是有序的了,分页获取粉丝列表或关注列表,就非常高效。 + + +**大规模数据** + +小规模数据存储在内容中,上面的解决思路是没有问题的。如果像微博那样有上亿的用户,数据规模太大,我们就无法全部存储在内容中了,怎么办?? + +- 思路一 + +我们可以通过哈希算法等数据分片方式,将邻接表存储在不同的机器上。 + + + +- 思路二 + +利用外部存储(比如硬盘),因为外部存储的存储空间要比内存宽裕很多。数据库是我们经常用来外部持久化存储关系数据的,所以可以采用数据库的存储方式。 + +比如为了支持上述定义的操作,我们可以在表上建立多个索引,比如第一列、第二列,给这两列建立索引。 + +user_id | follower_id +---|--- +1 | 4 +2 | 1 +2 | 4 +3 | 2 +3 | 5 +4 | 2 +4 | 5 +5 | 2 + + + + + + + + + + + + + diff --git a/Week_04/id_80/LeetCode_169_80.java b/Week_04/id_80/LeetCode_169_80.java new file mode 100644 index 00000000..3e6fc697 --- /dev/null +++ b/Week_04/id_80/LeetCode_169_80.java @@ -0,0 +1,23 @@ +class Solution { + //摩尔投票法 + //假设数组非空、总是存在众数。 + public static int majorityElement(int[] nums) + { + int count=0;//计算当前的数字出现的次数 + int mj=0;//当前判断的元素 + for (int i = 0; i < nums.length; i++) + { + if(count==0){//当次数为0时,则换下一判断元素 + mj=nums[i]; + count=1; + } + else if (nums[i]==mj) { + count++;//当前元素等于判断元素,次数加1 + } + else { + count--;//不等于则次数减一 + } + } + return mj; + } + } diff --git a/Week_04/id_80/LeetCode_720_80.java b/Week_04/id_80/LeetCode_720_80.java new file mode 100644 index 00000000..7d947351 --- /dev/null +++ b/Week_04/id_80/LeetCode_720_80.java @@ -0,0 +1,72 @@ +class Solution { + private String longestWord = ""; + + public String longestWord(String[] words) { + + Trie trie = new Trie(); + for (String word : words) { + trie.insert(word.toCharArray()); + } + + searchLongestWord(new StringBuilder(), trie.root.children); + return longestWord; + } + + private void searchLongestWord(StringBuilder sb, Trie.TrieNode[] children) { + if (children == null) + return; + for (Trie.TrieNode node : children) { + if (node != null && node.isEndingChar) { // 该节点必须为某个单词的结束字符 + sb.append(node.data); + if (sb.length() > longestWord.length()) + longestWord = sb.toString(); + searchLongestWord(sb, node.children); + sb.deleteCharAt(sb.length() - 1); + } + } + } + + class Trie { + private TrieNode root = new TrieNode('/'); // 存储无意义字符 + + // 往 Trie 树中插入一个字符串 + public void insert(char[] text) { + TrieNode p = root; + for (int i = 0; i < text.length; ++i) { + int index = text[i] - 'a'; + if (p.children[index] == null) { + TrieNode newNode = new TrieNode(text[i]); + p.children[index] = newNode; + } + p = p.children[index]; + } + p.isEndingChar = true; + } + + // 在 Trie 树中查找一个字符串 + public boolean find(char[] pattern) { + TrieNode p = root; + for (int i = 0; i < pattern.length; ++i) { + int index = pattern[i] - 'a'; + if (p.children[index] == null) { + return false; // 不存在 pattern + } + p = p.children[index]; + } + if (p.isEndingChar == false) + return false; // 不能完全匹配,只是前缀 + else + return true; // 找到 pattern + } + + class TrieNode { + public char data; + public TrieNode[] children = new TrieNode[26]; + public boolean isEndingChar = false; + + public TrieNode(char data) { + this.data = data; + } + } + } +} diff --git a/Week_04/id_80/NOTE.md b/Week_04/id_80/NOTE.md index c684e62f..be837f13 100644 --- a/Week_04/id_80/NOTE.md +++ b/Week_04/id_80/NOTE.md @@ -1 +1,11 @@ -# 学习笔记 \ No newline at end of file +# 学习笔记 + +通过再次学习王争老师专栏,写文章的方法有很多值得学习的地方 + +根据提纲自己总结了一下以下几点: +1. 是什么?解决什么问题? +2. 如何实现的?怎么使用? +3. 有没有其他代替方案?若有,对比优缺点是什么? +4. 如果我来做,如何做? + +以上思路,套用其他知识的学习,发现也适用。现在才明白这个思路,希望不会太晚。