diff --git a/week01/NOTE.md b/week01/NOTE.md index 50de3041..15129064 100644 --- a/week01/NOTE.md +++ b/week01/NOTE.md @@ -1 +1,3 @@ -学习笔记 \ No newline at end of file +学习笔记 + +双指针的运用很巧妙,可能减少无谓的操作步骤。 \ No newline at end of file diff --git "a/week01/[1]\344\270\244\346\225\260\344\271\213\345\222\214.java" "b/week01/[1]\344\270\244\346\225\260\344\271\213\345\222\214.java" new file mode 100644 index 00000000..3bc640d3 --- /dev/null +++ "b/week01/[1]\344\270\244\346\225\260\344\271\213\345\222\214.java" @@ -0,0 +1,19 @@ +class Solution { + public int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + for (int i = 1; i < nums.length; i++) + map.put(nums[i], i); + + int[] result = new int[2]; + for (int i = 0; i < nums.length; i++) { + int k = target - nums[i]; + Integer j = map.get(k); + if (j != null && i != j) { + result[0] = i; + result[1] = j; + break; + } + } + return result; + } +} diff --git "a/week01/[26]\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" "b/week01/[26]\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" new file mode 100644 index 00000000..e01e29fb --- /dev/null +++ "b/week01/[26]\345\210\240\351\231\244\346\216\222\345\272\217\346\225\260\347\273\204\344\270\255\347\232\204\351\207\215\345\244\215\351\241\271.java" @@ -0,0 +1,11 @@ +class Solution { + public int removeDuplicates(int[] nums) { + int i = 0; + for (int j = 1; j < nums.length; j++) { + if (nums[j] != nums[i] && j - i++ > 1) { + nums[i] = nums[j]; + } + } + return i + 1; + } +} diff --git "a/week01/[283]\347\247\273\345\212\250\351\233\266.java" "b/week01/[283]\347\247\273\345\212\250\351\233\266.java" new file mode 100644 index 00000000..33149883 --- /dev/null +++ "b/week01/[283]\347\247\273\345\212\250\351\233\266.java" @@ -0,0 +1,33 @@ +//给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 +// +// 示例: +// +// 输入: [0,1,0,3,12] +//输出: [1,3,12,0,0] +// +// 说明: +// +// +// 必须在原数组上操作,不能拷贝额外的数组。 +// 尽量减少操作次数。 +// +// Related Topics 数组 双指针 + +class Solution { + public void moveZeroes(int[] nums) { + int j = 1; + for (int i = 0; i < nums.length - 1; i++) { + if (nums[i] == 0) { + for (; j < nums.length; j++) { + if (nums[j] != 0) { + nums[i] = nums[j]; + nums[j++] = 0; + break; + } + } + } else { + j++; + } + } + } +} \ No newline at end of file diff --git "a/week01/[66]\345\212\240\344\270\200.java" "b/week01/[66]\345\212\240\344\270\200.java" new file mode 100644 index 00000000..1b1acf13 --- /dev/null +++ "b/week01/[66]\345\212\240\344\270\200.java" @@ -0,0 +1,40 @@ +//给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。 +// +// 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 +// +// 你可以假设除了整数 0 之外,这个整数不会以零开头。 +// +// 示例 1: +// +// 输入: [1,2,3] +//输出: [1,2,4] +//解释: 输入数组表示数字 123。 +// +// +// 示例 2: +// +// 输入: [4,3,2,1] +//输出: [4,3,2,2] +//解释: 输入数组表示数字 4321。 +// +// Related Topics 数组 +class Solution { + public int[] plusOne(int[] digits) { + for (int i = digits.length- 1 ; i >= 0; i--) { + int value = ++digits[i]; + if (value < 10) + break; + else + digits[i] = value % 10; + + if (i == 0) { + int[] newDigits = new int[digits.length + 1]; + System.arraycopy(digits, 0, newDigits, 1, digits.length); + newDigits[0] = 1; + return newDigits; + } + + } + return digits; + } +} \ No newline at end of file diff --git a/week02/NOTE.md b/week02/NOTE.md index 50de3041..3e187f6b 100644 --- a/week02/NOTE.md +++ b/week02/NOTE.md @@ -1 +1,21 @@ -学习笔记 \ No newline at end of file +学习笔记 + +## HashMap小结 + +#### 初始大小 +HashMap 默认的初始大小是 16,当然这个默认值是可以设置的,如果事先知道大概的数据量有多大,可以通过修改默认初始大小,减少动态扩容的次数,这样会大大提高 HashMap 的性能。 + +#### 装载因子 +最大装载因子默认是 0.75,当 HashMap 中元素个数超过 0.75*capacity(capacity 表示散列表的容量)的时候,就会启动扩容,每次扩容都会扩容为原来的两倍大小。 + +#### hash函数 + +``` +static final int hash(Object key) { + int h; + return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); + } +``` + +#### hash冲突 +HashMap 底层采用链表法来解决冲突。即使负载因子和散列函数设计得再合理,也免不了会出现拉链过长的情况,一旦出现拉链过长,则会严重影响 HashMap 的性能。于是,在 JDK1.8 版本中,为了对 HashMap 做进一步优化,我们引入了红黑树。而当链表长度太长(默认超过 8)时,链表就转换为红黑树。我们可以利用红黑树快速增删改查的特点,提高 HashMap 的性能。当红黑树结点个数少于 8 个的时候,又会将红黑树转化为链表。因为在数据量较小的情况下,红黑树要维护平衡,比起链表来,性能上的优势并不明显。 diff --git "a/week02/[102]\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" "b/week02/[102]\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..fe8bd725 --- /dev/null +++ "b/week02/[102]\344\272\214\345\217\211\346\240\221\347\232\204\345\261\202\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,68 @@ +//给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。 +// +// +// +// 示例: +//二叉树:[3,9,20,null,null,15,7], +// +// 3 +// / \ +// 9 20 +// / \ +// 15 7 +// +// +// 返回其层次遍历结果: +// +// [ +// [3], +// [9,20], +// [15,7] +//] +// +// Related Topics 树 广度优先搜索 + + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ + +// https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ +// +// 解决思路: +// 1.首先根元素入队 +// 2.当队列不为空的时候,求当前队列的长度size,依次从队列中取size个元素进行拓展,然后进入下一次迭代 +// +// 时间复杂度:O(n),每个节点进出队列一次 +// +// 空间复杂度:O(n), 队列中元素的个数不超过n个 + +class Solution { + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + + Queue queue = new ArrayDeque<>(); + + if (root != null) queue.add(root); + + while (!queue.isEmpty()) { + List levelValues = new ArrayList<>(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode cur = queue.poll(); + levelValues.add(cur.val); + if (cur.left != null) queue.add(cur.left); + if (cur.right != null) queue.add(cur.right); + } + result.add(levelValues); + } + + return result; + } +} diff --git "a/week02/[144]\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/week02/[144]\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..324cdfaa --- /dev/null +++ "b/week02/[144]\344\272\214\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,84 @@ +//给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 +// +// +// +// 示例 1: +// +// +//输入:root = [1,null,2,3] +//输出:[1,2,3] +// +// +// 示例 2: +// +// +//输入:root = [] +//输出:[] +// +// +// 示例 3: +// +// +//输入:root = [1] +//输出:[1] +// +// +// 示例 4: +// +// +//输入:root = [1,2] +//输出:[1,2] +// +// +// 示例 5: +// +// +//输入:root = [1,null,2] +//输出:[1,2] +// +// +// +// +// 提示: +// +// +// 树中节点数目在范围 [0, 100] 内 +// -100 <= Node.val <= 100 +// +// +// +// +// 进阶:递归算法很简单,你可以通过迭代算法完成吗? +// Related Topics 栈 树 +// 👍 441 👎 0 + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + + +class Solution { + public List preorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + preorder(root, result); + return result; + } + private void preorder(TreeNode root, List result) { + if (root == null) return; + result.add(root.val); + preorder(root.left, result); + preorder(root.right, result); + } +} \ No newline at end of file diff --git "a/week02/[145]\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" "b/week02/[145]\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..58930865 --- /dev/null +++ "b/week02/[145]\344\272\214\345\217\211\346\240\221\347\232\204\345\220\216\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,45 @@ +//给定一个二叉树,返回它的 后序 遍历。 +// +// 示例: +// +// 输入: [1,null,2,3] +// 1 +// \ +// 2 +// / +// 3 +// +//输出: [3,2,1] +// +// 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +// Related Topics 栈 树 + +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + public List postorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + postorder(root, result); + return result; + } + + private void postorder(TreeNode root, List result) { + if (root == null) return; + postorder(root.left, result); + postorder(root.right, result); + result.add(root.val); + } +} \ No newline at end of file diff --git "a/week02/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" "b/week02/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" new file mode 100644 index 00000000..540b6592 --- /dev/null +++ "b/week02/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" @@ -0,0 +1,52 @@ +//ַ s t дһж t Ƿ s ĸλʡ +// +// ʾ 1: +// +// : s = "anagram", t = "nagaram" +//: true +// +// +// ʾ 2: +// +// : s = "rat", t = "car" +//: false +// +// ˵: +//ԼַֻСдĸ +// +// : +//ַ unicode ַô죿ܷĽⷨӦ +// Related Topics ϣ + +//https://leetcode-cn.com/problems/valid-anagram/ +// +// ˼·: +// жַǷȣֱӷ false +// ȣʼ 26 ĸϣַ s t, s ڶӦλӣt ڶӦλü +// ϣֵΪ 0ĸλ +// +// ʱ临Ӷ:O(n),ʼһ̶ʱ +// +// ռ临Ӷ:O(1),ʹ˶Ŀռ䣬ǿռĸ O(1)O(1)Ϊ NN ж󣬱ĴСֲ䡣 + +class Solution { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) + return false; + char[] sChars = s.toCharArray(); + char[] tChars = t.toCharArray(); + + int[] table = new int[26]; + + for (char c : sChars) + table[c - 'a']++; + for (char c : tChars) + table[c - 'a']--; + + for (int value : table) + if (value != 0) + return false; + + return true; + } +} \ No newline at end of file diff --git "a/week02/[347]\345\211\215 K \344\270\252\351\253\230\351\242\221\345\205\203\347\264\240.java" "b/week02/[347]\345\211\215 K \344\270\252\351\253\230\351\242\221\345\205\203\347\264\240.java" new file mode 100644 index 00000000..6ce3e3be --- /dev/null +++ "b/week02/[347]\345\211\215 K \344\270\252\351\253\230\351\242\221\345\205\203\347\264\240.java" @@ -0,0 +1,68 @@ +//给定一个非空的整数数组,返回其中出现频率前 k 高的元素。 +// +// +// +// 示例 1: +// +// 输入: nums = [1,1,1,2,2,3], k = 2 +//输出: [1,2] +// +// +// 示例 2: +// +// 输入: nums = [1], k = 1 +//输出: [1] +// +// +// +// 提示: +// +// +// 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。 +// 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。 +// 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。 +// 你可以按任意顺序返回答案。 +// +// Related Topics 堆 哈希表 + +// https://leetcode-cn.com/problems/top-k-frequent-elements/ +// +// 解题思路: +// 用map记录每个元素出现次数 +// 以元素出现次数为下标,将对应元素集合存入数组 +// 从数组倒序取前k个高频元素 +// +// 时间复杂度:O(n),遍历nums统计元素出现频率的时间复杂度为O(n),插入排序数组的时间复杂度也为O(n),总的时间复杂度为O(n). + +// 空间复杂度:O(n),没有线性增长 + +class Solution { + public int[] topKFrequent(int[] nums, int k) { + + Map map = new HashMap<>(); + for (int num : nums) { + Integer count = map.putIfAbsent(num, 1); + if (count != null) map.put(num, count + 1); + } + + List[] table = new List[nums.length + 1]; + for (Map.Entry entry : map.entrySet()) { + Integer num = entry.getKey(); + Integer count = entry.getValue(); + if (table[count] == null) + table[count] = new ArrayList<>(); + table[count].add(num); + } + + int[] result = new int[k]; + for (int i = table.length - 1, j = 0; i >=0 && j < k; i--) { + if (table[i] != null) { + for (Integer num : table[i]) { + result[j++] = num; + } + } + } + + return result; + } +} \ No newline at end of file diff --git "a/week02/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.java" "b/week02/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.java" new file mode 100644 index 00000000..b0d4ae2c --- /dev/null +++ "b/week02/[49]\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215\345\210\206\347\273\204.java" @@ -0,0 +1,51 @@ +//给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。 +// +// 示例: +// +// 输入: ["eat", "tea", "tan", "ate", "nat", "bat"] +//输出: +//[ +// ["ate","eat","tea"], +// ["nat","tan"], +// ["bat"] +//] +// +// 说明: +// +// +// 所有输入均为小写字母。 +// 不考虑答案输出的顺序。 +// +// Related Topics 哈希表 字符串 + +//https://leetcode-cn.com/problems/group-anagrams/ + +// 解决思路: +// 当且仅当它们的排序字符串相等时,两个字符串是字母异位词 +// +// 时间复杂度: +// O(NKlogK)),其中 N 是 strs 的长度,而 K 是 strs 中字符串的最大长度。 +// 当我们遍历每个字符串时,外部循环具有的复杂度为 O(N)。然后,我们在 O(Klog K) 的时间内对每个字符串排序。 + +// +// 空间复杂度: +// O(NK),排序存储在 ans 中的全部信息内容。 + +class Solution { + public List> groupAnagrams(String[] strs) { + Map> result = new HashMap<>(); + for (int i = 0; i < strs.length; i++) { + char[] chars = strs[i].toCharArray(); + Arrays.sort(chars); + String key = String.valueOf(chars); + if (!result.containsKey(key)) { + List list = new ArrayList<>(); + list.add(strs[i]); + result.put(key, list); + } else { + result.get(key).add(strs[i]); + } + } + return new ArrayList<>(result.values()); + } +} diff --git "a/week02/[589]N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" "b/week02/[589]N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..12731429 --- /dev/null +++ "b/week02/[589]N\345\217\211\346\240\221\347\232\204\345\211\215\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,49 @@ +//给定一个 N 叉树,返回其节点值的前序遍历。 +// +// 例如,给定一个 3叉树 : +// +// +// +// +// +// +// +// 返回其前序遍历: [1,3,5,6,2,4]。 +// +// +// +// 说明: 递归法很简单,你可以使用迭代法完成此题吗? Related Topics 树 +// Definition for a Node. +/*class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +};*/ + + +class Solution { + public List preorder(Node root) { + List result = new ArrayList<>(); + doPreorder(root, result); + return result; + } + + private void doPreorder(Node root, List result) { + if (root == null) return; + result.add(root.val); + List child = root.children; + if (child == null) return; + for (Node node : child) + doPreorder(node, result); + } +} \ No newline at end of file diff --git "a/week02/[94]\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" "b/week02/[94]\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" new file mode 100644 index 00000000..84ea6806 --- /dev/null +++ "b/week02/[94]\344\272\214\345\217\211\346\240\221\347\232\204\344\270\255\345\272\217\351\201\215\345\216\206.java" @@ -0,0 +1,76 @@ +//给定一个二叉树,返回它的中序 遍历。 +// +// 示例: +// +// 输入: [1,null,2,3] +// 1 +// \ +// 2 +// / +// 3 +// +//输出: [1,3,2] +// +// 进阶: 递归算法很简单,你可以通过迭代算法完成吗? +// Related Topics 栈 树 哈希表 +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + +// https://leetcode-cn.com/problems/binary-tree-inorder-traversal/ +// +// 解题思路: +// 迭代法 +// +// 时间复杂度: +// O(n),其中 n 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。 +// +// 空间复杂度: +// O(n)。空间复杂度取决于栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。 + +class Solution { + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + Deque deque =new ArrayDeque<>(); + TreeNode cur = root; + while (cur != null || !deque.isEmpty()) { + if (cur != null) { + deque.push(cur); + cur = cur.left; + } else { + cur = deque.pop(); + result.add(cur.val); + cur = cur.right; + } + } + return result; + } +} + +// 递归解法 +class Solution_1 { + public List inorderTraversal(TreeNode root) { + List result = new ArrayList<>(); + inorder(root, result); + return result; + } + + private void inorder(TreeNode root, List result) { + if (root == null) return; + inorder(root.left, result); + result.add(root.val); + inorder(root.right, result); + } +} \ No newline at end of file diff --git "a/week03/[105]\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" "b/week03/[105]\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 00000000..8f5f8dc3 --- /dev/null +++ "b/week03/[105]\344\273\216\345\211\215\345\272\217\344\270\216\344\270\255\345\272\217\351\201\215\345\216\206\345\272\217\345\210\227\346\236\204\351\200\240\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,49 @@ +//根据一棵树的前序遍历与中序遍历构造二叉树。 +// +// 注意: +//你可以假设树中没有重复的元素。 +// +// 例如,给出 +// +// 前序遍历 preorder = [3,9,20,15,7] +//中序遍历 inorder = [9,3,15,20,7] +// +// 返回如下的二叉树: +// +// 3 +// / \ +// 9 20 +// / \ +// 15 7 +// Related Topics 树 深度优先搜索 数组 + +class Solution { + private Map inorderMap = new HashMap<>(); + public TreeNode buildTree(int[] preorder, int[] inorder) { + for (int i = 0; i < inorder.length; i++) + inorderMap.put(inorder[i], i); + + return doBuild(preorder, inorder, 0, inorder.length - 1, 0, inorder.length -1 ); + } + + private TreeNode doBuild(int[] preorder, int[] inorder, int pre_start, int pre_end, int in_start, int in_end) { + if (pre_start > pre_end) + return null; + + int preorder_root = pre_start; + int inorder_root = inorderMap.get(preorder[preorder_root]); + + TreeNode root = new TreeNode(preorder[preorder_root]); + + // 左子树节点数目 + int left_num = inorder_root - in_start; + + // build left subtree + root.left = doBuild(preorder, inorder, pre_start + 1, pre_start + left_num, in_start, inorder_root - 1); + + // build right subtree + root.right = doBuild(preorder, inorder, pre_start + left_num + 1, pre_end, inorder_root + 1, in_end); + + return root; + } +} \ No newline at end of file diff --git "a/week03/[235]\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/week03/[235]\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" new file mode 100644 index 00000000..5f475186 --- /dev/null +++ "b/week03/[235]\344\272\214\345\217\211\346\220\234\347\264\242\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -0,0 +1,49 @@ +//给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 +// +// 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大( +//一个节点也可以是它自己的祖先)。” +// +// 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5] +// +// +// +// +// +// 示例 1: +// +// 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 +//输出: 6 +//解释: 节点 2 和节点 8 的最近公共祖先是 6。 +// +// +// 示例 2: +// +// 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 +//输出: 2 +//解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。 +// +// +// +// 说明: +// +// +// 所有节点的值都是唯一的。 +// p、q 为不同节点且均存在于给定的二叉搜索树中。 +// +// Related Topics 树 + + +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if ((root.val - p.val) * (root.val - q.val) <= 0) + return root; + return lowestCommonAncestor(p.val < root.val ? root.left : root.right, p, q); + } +} + + // 如果p,q都小于root,则最近公共祖先在root的左子树上 + // 如果p,q都大于root,则最近公共祖先在root的右子树上 + // 如果p,q一个大小于root,一个大于root,则root即为最近公共祖先 + + // 时间复杂度:O(n) + // 空间复杂度:O(1) diff --git "a/week03/[236]\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/week03/[236]\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" new file mode 100644 index 00000000..b08986f7 --- /dev/null +++ "b/week03/[236]\344\272\214\345\217\211\346\240\221\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -0,0 +1,53 @@ +//给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 +// +// 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大( +//一个节点也可以是它自己的祖先)。” +// +// 例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4] +// +// +// +// +// +// 示例 1: +// +// 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 +//输出: 3 +//解释: 节点 5 和节点 1 的最近公共祖先是节点 3。 +// +// +// 示例 2: +// +// 输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 +//输出: 5 +//解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。 +// +// +// +// +// 说明: +// +// +// 所有节点的值都是唯一的。 +// p、q 为不同节点且均存在于给定的二叉树中。 +// +// Related Topics 树 + +class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + + if (root == null || root == p || root == q) + return root; + + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left == null) return right; + if (right == null) return left; + + return root; + } +} + +// p 和 q 在 root 的子树中,且分列 root 的 异侧(即分别在左、右子树中); +// p = root,且 q 在 root 的左或右子树中; +// q = root,且 p 在 root 的左或右子树中 \ No newline at end of file diff --git "a/week03/[77]\347\273\204\345\220\210.java" "b/week03/[77]\347\273\204\345\220\210.java" new file mode 100644 index 00000000..fb66b060 --- /dev/null +++ "b/week03/[77]\347\273\204\345\220\210.java" @@ -0,0 +1,37 @@ +//给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 +// +// 示例: +// +// 输入: n = 4, k = 2 +//输出: +//[ +// [2,4], +// [3,4], +// [2,3], +// [1,2], +// [1,3], +// [1,4], +//] +// Related Topics 回溯算法 + +class Solution { + public List> combine(int n, int k) { + List> result = new ArrayList<>(); + Deque path = new ArrayDeque<>(); + dfs(n, k, 1, path, result); + return result; + } + + private void dfs(int n, int k, int begin, Deque path, List> result) { + if (path.size() == k) { + result.add(new ArrayList<>(path)); + return; + } + + for (int i = begin; i <= n; i++) { + path.addLast(i); + dfs(n, k, i + 1, path, result); + path.removeLast(); + } + } +} \ No newline at end of file diff --git a/week04/NOTE.md b/week04/NOTE.md index 50de3041..8119c9fb 100644 --- a/week04/NOTE.md +++ b/week04/NOTE.md @@ -1 +1,29 @@ -学习笔记 \ No newline at end of file +学习笔记 + +## 二分查找 +每次通过跟区间中的中间元素对比,将待查找的区间缩小为一半,直到找到要查找的元素,或者区间被缩小为0。 + +## 贪心算法 + + +## 使用二分查找,寻找一个半有序数组 [4, 5, 6, 7, 0, 1, 2] 中间无序的地方 + +### 解题思路 + +. 要查找的元素大于前一个元素并且小于后一个元素。 +. 如果中间元素比最后一个元素大,说明目标元素在中间元素之后,否则在中间元素之前。 + +``` +public int searchFirst(int[] nums) { + int left = 0, right = nums.length - 1, mid; + while (left <= right) { + mid = (right - left) / 2 + left; + if (mid > 0 && nums[mid] < nums[mid - 1] && (mid == nums.length - 1 || nums[mid] < nums[mid + 1])) + return mid; + else if (nums[mid] > nums[nums.length - 1]) + left = mid + 1; + else + right = mid - 1; + } + return -1; +``` \ No newline at end of file diff --git "a/week04/[122]\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II.java" "b/week04/[122]\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II.java" new file mode 100644 index 00000000..5dd01f49 --- /dev/null +++ "b/week04/[122]\344\271\260\345\215\226\350\202\241\347\245\250\347\232\204\346\234\200\344\275\263\346\227\266\346\234\272 II.java" @@ -0,0 +1,53 @@ +//给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。 +// +// 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 +// +// 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 +// +// +// +// 示例 1: +// +// 输入: [7,1,5,3,6,4] +//输出: 7 +//解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +//  随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。 +// +// +// 示例 2: +// +// 输入: [1,2,3,4,5] +//输出: 4 +//解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 +//  注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 +//  因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。 +// +// +// 示例 3: +// +// 输入: [7,6,4,3,1] +//输出: 0 +//解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。 +// +// +// +// 提示: +// +// +// 1 <= prices.length <= 3 * 10 ^ 4 +// 0 <= prices[i] <= 10 ^ 4 +// +// Related Topics 贪心算法 数组 +class Solution { + public int maxProfit(int[] prices) { + if (prices.length < 2) + return 0; + int result = 0; + for (int i = 1; i < prices.length; i++) { + int diff = prices[i] - prices[i - 1]; + if (diff > 0) + result += diff; + } + return result; + } +} \ No newline at end of file diff --git "a/week04/[33]\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204.java" "b/week04/[33]\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204.java" new file mode 100644 index 00000000..ac23d238 --- /dev/null +++ "b/week04/[33]\346\220\234\347\264\242\346\227\213\350\275\254\346\216\222\345\272\217\346\225\260\347\273\204.java" @@ -0,0 +1,68 @@ +//给你一个整数数组 nums ,和一个整数 target 。 +// +// 该整数数组原本是按升序排列,但输入时在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] +// )。 +// +// 请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。 +// +// +// 示例 1: +// +// +//输入:nums = [4,5,6,7,0,1,2], target = 0 +//输出:4 +// +// +// 示例 2: +// +// +//输入:nums = [4,5,6,7,0,1,2], target = 3 +//输出:-1 +// +// 示例 3: +// +// +//输入:nums = [1], target = 0 +//输出:-1 +// +// +// +// +// 提示: +// +// +// 1 <= nums.length <= 5000 +// -10^4 <= nums[i] <= 10^4 +// nums 中的每个值都 独一无二 +// nums 肯定会在某个点上旋转 +// -10^4 <= target <= 10^4 +// +// Related Topics 数组 二分查找 + +class Solution { + public int search(int[] nums, int target) { + if (nums.length == 1) + return nums[0] == target ? 0 : -1; + + int left = 0, right = nums.length - 1, mid; + while (left <= right) { + mid = (right - left) / 2 + left; + + if (nums[mid] == target) + return mid; + + if (nums[mid] >= nums[0]) { + if (target >= nums[0] && target < nums[mid]) + right = mid - 1; + else + left = mid + 1; + } else { + if (target > nums[mid] && target <= nums[nums.length - 1]) + left = mid + 1; + else + right = mid - 1; + } + } + return -1; + } +} diff --git "a/week04/[455]\345\210\206\345\217\221\351\245\274\345\271\262.java" "b/week04/[455]\345\210\206\345\217\221\351\245\274\345\271\262.java" new file mode 100644 index 00000000..3fd6f028 --- /dev/null +++ "b/week04/[455]\345\210\206\345\217\221\351\245\274\345\271\262.java" @@ -0,0 +1,54 @@ +//假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 +// +// 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i +//],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。 +// +// +// 示例 1: +// +// +//输入: g = [1,2,3], s = [1,1] +//输出: 1 +//解释: +//你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 +//虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 +//所以你应该输出1。 +// +// +// 示例 2: +// +// +//输入: g = [1,2], s = [1,2,3] +//输出: 2 +//解释: +//你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 +//你拥有的饼干数量和尺寸都足以让所有孩子满足。 +//所以你应该输出2. +// +// +// +// +// 提示: +// +// +// 1 <= g.length <= 3 * 104 +// 0 <= s.length <= 3 * 104 +// 1 <= g[i], s[j] <= 231 - 1 +// +// Related Topics 贪心算法 + +class Solution { + public int findContentChildren(int[] g, int[] s) { + Arrays.sort(g); + Arrays.sort(s); + int result = 0; + int s_index = s.length - 1; + for (int i = g.length - 1; i >= 0; i--) { + if (s_index >= 0 && s[s_index] >= g[i]) { + result++; + s_index--; + } + } + return result; + } +} \ No newline at end of file diff --git "a/week04/[704]\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/week04/[704]\344\272\214\345\210\206\346\237\245\346\211\276.java" new file mode 100644 index 00000000..9b41b3f7 --- /dev/null +++ "b/week04/[704]\344\272\214\345\210\206\346\237\245\346\211\276.java" @@ -0,0 +1,44 @@ +//给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否 +//则返回 -1。 +// +// +//示例 1: +// +// 输入: nums = [-1,0,3,5,9,12], target = 9 +//输出: 4 +//解释: 9 出现在 nums 中并且下标为 4 +// +// +// 示例 2: +// +// 输入: nums = [-1,0,3,5,9,12], target = 2 +//输出: -1 +//解释: 2 不存在 nums 中因此返回 -1 +// +// +// +// +// 提示: +// +// +// 你可以假设 nums 中的所有元素是不重复的。 +// n 将在 [1, 10000]之间。 +// nums 的每个元素都将在 [-9999, 9999]之间。 +// +// Related Topics 二分查找 + +class Solution { + public int search(int[] nums, int target) { + int left = 0, right = nums.length - 1, mid; + while (left <= right) { + mid = (right - left) / 2 + left; + if (nums[mid] == target) + return mid; + if (nums[mid] < target) + left = mid + 1; + else + right = mid - 1; + } + return -1; + } +} \ No newline at end of file diff --git "a/week04/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.java" "b/week04/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.java" new file mode 100644 index 00000000..5bddf42c --- /dev/null +++ "b/week04/[860]\346\237\240\346\252\254\346\260\264\346\211\276\351\233\266.java" @@ -0,0 +1,79 @@ +//在柠檬水摊上,每一杯柠檬水的售价为 5 美元。 +// +// 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 +// +// 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 +// +// 注意,一开始你手头没有任何零钱。 +// +// 如果你能给每位顾客正确找零,返回 true ,否则返回 false 。 +// +// 示例 1: +// +// 输入:[5,5,5,10,20] +//输出:true +//解释: +//前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。 +//第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。 +//第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。 +//由于所有客户都得到了正确的找零,所以我们输出 true。 +// +// +// 示例 2: +// +// 输入:[5,5,10] +//输出:true +// +// +// 示例 3: +// +// 输入:[10,10] +//输出:false +// +// +// 示例 4: +// +// 输入:[5,5,10,10,20] +//输出:false +//解释: +//前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。 +//对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。 +//对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。 +//由于不是每位顾客都得到了正确的找零,所以答案是 false。 +// +// +// +// +// 提示: +// +// +// 0 <= bills.length <= 10000 +// bills[i] 不是 5 就是 10 或是 20 +// +// Related Topics 贪心算法 + +class Solution { + public boolean lemonadeChange(int[] bills) { + int five = 0, ten = 0; + for (int bill : bills) { + if (bill == 5) { + five++; + } else if (bill == 10) { + if (five == 0) + return false; + five--; + ten++; + } else { + if (five > 0 && ten > 0) { + five--; + ten--; + } else if (five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; + } +} \ No newline at end of file diff --git a/week06/NOTE.md b/week06/NOTE.md index 50de3041..d5c8468d 100644 --- a/week06/NOTE.md +++ b/week06/NOTE.md @@ -1 +1,11 @@ -学习笔记 \ No newline at end of file +学习笔记 + +动态规划与分治都是通过组合子问题的解来求解原问题。 +分治方法将问题划分为互不相交的子问题,递归地求解子问题,再将它们的解组合起来,求出原问题的解。 +与之相反,动态规划应用于子问题重叠的情况,即不同的子问题具有具有公共的子子问题(子问题的求解是递归进行的,将其划分为更小的子子问题)。在这种情况下分治算法会做很多不必要的重复工作,它会反复地求解那些公共子问题。而动态规划算法对每个子子问题只求解一次,将其解保存在一个表格中,避免了不必要的计算。 + +## 4步聚设计一个动态规划算法 +1. 刻画一个最优解的结构特征。 +2. 递归的定义最优解的值。 +3. 计算最优解的值,通常采用自底向上的方法。 +4. 利用计算出的信息构造一个最优解。 \ No newline at end of file diff --git "a/week06/[221]\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" "b/week06/[221]\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" new file mode 100644 index 00000000..eeaea841 --- /dev/null +++ "b/week06/[221]\346\234\200\345\244\247\346\255\243\346\226\271\345\275\242.java" @@ -0,0 +1,40 @@ +//在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。 +// +// +// +// 示例: +// +// +//输入: +//matrix = [["1","0","1","0","0"], +// ["1","0","1","1","1"], +// ["1","1","1","1","1"], +// ["1","0","0","1","0"]] +// +//输出:4 +// Related Topics 动态规划 +class Solution { + public int maximalSquare(char[][] matrix) { + + int maxSide = 0; + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) + return maxSide; + + int rows = matrix.length; + int columns = matrix[0].length; + int[][] dp = new int[rows][columns]; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + if (matrix[i][j] == '1') { + if (i == 0 || j == 0) + dp[i][j] = 1; + else + dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; + maxSide = Math.max(maxSide, dp[i][j]); + } + } + } + return maxSide * maxSide; + } +} \ No newline at end of file diff --git "a/week06/[62]\344\270\215\345\220\214\350\267\257\345\276\204.java" "b/week06/[62]\344\270\215\345\220\214\350\267\257\345\276\204.java" new file mode 100644 index 00000000..e8c24d2e --- /dev/null +++ "b/week06/[62]\344\270\215\345\220\214\350\267\257\345\276\204.java" @@ -0,0 +1,50 @@ +//一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 +// +// 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 +// +// 问总共有多少条不同的路径? +// +// +// +// 例如,上图是一个7 x 3 的网格。有多少可能的路径? +// +// +// +// 示例 1: +// +// 输入: m = 3, n = 2 +//输出: 3 +//解释: +//从左上角开始,总共有 3 条路径可以到达右下角。 +//1. 向右 -> 向右 -> 向下 +//2. 向右 -> 向下 -> 向右 +//3. 向下 -> 向右 -> 向右 +// +// +// 示例 2: +// +// 输入: m = 7, n = 3 +//输出: 28 +// +// +// +// 提示: +// +// +// 1 <= m, n <= 100 +// 题目数据保证答案小于等于 2 * 10 ^ 9 +// +// Related Topics 数组 动态规划 +class Solution { + public int uniquePaths(int m, int n) { + + int[] cur = new int[n]; + Arrays.fill(cur, 1); + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + cur[j] += cur[j -1]; + } + } + return cur[n - 1]; + } +} \ No newline at end of file diff --git "a/week06/[63]\344\270\215\345\220\214\350\267\257\345\276\204 II.java" "b/week06/[63]\344\270\215\345\220\214\350\267\257\345\276\204 II.java" new file mode 100644 index 00000000..76b94d43 --- /dev/null +++ "b/week06/[63]\344\270\215\345\220\214\350\267\257\345\276\204 II.java" @@ -0,0 +1,64 @@ +//一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 +// +// 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 +// +// 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? +// +// +// +// 网格中的障碍物和空位置分别用 1 和 0 来表示。 +// +// +// +// 示例 1: +// +// +//输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]] +//输出:2 +//解释: +//3x3 网格的正中间有一个障碍物。 +//从左上角到右下角一共有 2 条不同的路径: +//1. 向右 -> 向右 -> 向下 -> 向下 +//2. 向下 -> 向下 -> 向右 -> 向右 +// +// +// 示例 2: +// +// +//输入:obstacleGrid = [[0,1],[0,0]] +//输出:1 +// +// +// +// +// 提示: +// +// +// m == obstacleGrid.length +// n == obstacleGrid[i].length +// 1 <= m, n <= 100 +// obstacleGrid[i][j] 为 0 或 1 +// +// Related Topics 数组 动态规划 +class Solution { + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + + int m = obstacleGrid.length; + int n = obstacleGrid[0].length; + int[] dp = new int[n]; + + dp[0] = 1; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (obstacleGrid[i][j] == 1) { + dp[j] = 0; + } else if (j >= 1 && obstacleGrid[i][j - 1] == 0) { + dp[j] += dp[j - 1]; + } + } + } + + return dp[n - 1]; + } +} \ No newline at end of file diff --git "a/week06/[64]\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" "b/week06/[64]\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" new file mode 100644 index 00000000..19672015 --- /dev/null +++ "b/week06/[64]\346\234\200\345\260\217\350\267\257\345\276\204\345\222\214.java" @@ -0,0 +1,57 @@ +//给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 +// +// 说明:每次只能向下或者向右移动一步。 +// +// +// +// 示例 1: +// +// +//输入:grid = [[1,3,1],[1,5,1],[4,2,1]] +//输出:7 +//解释:因为路径 1→3→1→1→1 的总和最小。 +// +// +// 示例 2: +// +// +//输入:grid = [[1,2,3],[4,5,6]] +//输出:12 +// +// +// +// +// 提示: +// +// +// m == grid.length +// n == grid[i].length +// 1 <= m, n <= 200 +// 0 <= grid[i][j] <= 100 +// +// Related Topics 数组 动态规划 +class Solution { + public int minPathSum(int[][] grid) { + + int m = grid.length; + int n = grid[0].length; + int[][] dp = new int[m][n]; + dp[0][0] = grid[0][0]; + + // the first column + for (int i = 1; i < m; i++) + dp[i][0] = dp[i - 1][0] + grid[i][0]; + + // the first row + for (int i = 1; i < n; i++) + dp[0][i] = dp[0][i - 1] + grid[0][i]; + + for (int i = 1; i < m; i++) { + for (int j = 1; j < n; j++) { + dp[i][j] = grid[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]); + } + } + + return dp[m -1][n - 1]; + } +} \ No newline at end of file diff --git "a/week07/[127]\345\215\225\350\257\215\346\216\245\351\276\231.java" "b/week07/[127]\345\215\225\350\257\215\346\216\245\351\276\231.java" new file mode 100644 index 00000000..d1eab137 --- /dev/null +++ "b/week07/[127]\345\215\225\350\257\215\346\216\245\351\276\231.java" @@ -0,0 +1,101 @@ +//给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则: +// +// +// +// 每次转换只能改变一个字母。 +// 转换过程中的中间单词必须是字典中的单词。 +// +// +// 说明: +// +// +// 如果不存在这样的转换序列,返回 0。 +// 所有单词具有相同的长度。 +// 所有单词只由小写字母组成。 +// 字典中不存在重复的单词。 +// 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。 +// +// +// 示例 1: +// +// 输入: +//beginWord = "hit", +//endWord = "cog", +//wordList = ["hot","dot","dog","lot","log","cog"] +// +//输出: 5 +// +//解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", +// 返回它的长度 5。 +// +// +// 示例 2: +// +// 输入: +//beginWord = "hit" +//endWord = "cog" +//wordList = ["hot","dot","dog","lot","log"] +// +//输出: 0 +// +//解释: endWord "cog" 不在字典中,所以无法进行转换。 +// Related Topics 广度优先搜索 +class Solution { + Map wordId = new HashMap(); + List> edge = new ArrayList>(); + int nodeNum = 0; + + public int ladderLength(String beginWord, String endWord, List wordList) { + for (String word : wordList) { + addEdge(word); + } + addEdge(beginWord); + if (!wordId.containsKey(endWord)) { + return 0; + } + int[] dis = new int[nodeNum]; + Arrays.fill(dis, Integer.MAX_VALUE); + int beginId = wordId.get(beginWord), endId = wordId.get(endWord); + dis[beginId] = 0; + + Queue que = new LinkedList(); + que.offer(beginId); + while (!que.isEmpty()) { + int x = que.poll(); + if (x == endId) { + return dis[endId] / 2 + 1; + } + for (int it : edge.get(x)) { + if (dis[it] == Integer.MAX_VALUE) { + dis[it] = dis[x] + 1; + que.offer(it); + } + } + } + return 0; + } + + public void addEdge(String word) { + addWord(word); + int id1 = wordId.get(word); + char[] array = word.toCharArray(); + int length = array.length; + for (int i = 0; i < length; ++i) { + char tmp = array[i]; + array[i] = '*'; + String newWord = new String(array); + addWord(newWord); + int id2 = wordId.get(newWord); + edge.get(id1).add(id2); + edge.get(id2).add(id1); + array[i] = tmp; + } + } + + public void addWord(String word) { + if (!wordId.containsKey(word)) { + wordId.put(word, nodeNum++); + edge.add(new ArrayList()); + } + } +} \ No newline at end of file diff --git "a/week07/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).java" "b/week07/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).java" new file mode 100644 index 00000000..af23863b --- /dev/null +++ "b/week07/[208]\345\256\236\347\216\260 Trie (\345\211\215\347\274\200\346\240\221).java" @@ -0,0 +1,87 @@ +//实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。 +// +// 示例: +// +// Trie trie = new Trie(); +// +//trie.insert("apple"); +//trie.search("apple"); // 返回 true +//trie.search("app"); // 返回 false +//trie.startsWith("app"); // 返回 true +//trie.insert("app"); +//trie.search("app"); // 返回 true +// +// 说明: +// +// +// 你可以假设所有的输入都是由小写字母 a-z 构成的。 +// 保证所有输入均为非空字符串。 +// +// Related Topics 设计 字典树 +class Trie { + + private TrieNode root = new TrieNode('/'); + + /** Initialize your data structure here. */ + public Trie() { + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + TrieNode p = root; + char[] chars = word.toCharArray(); + for (int i = 0; i < chars.length; i++) { + int index = chars[i] - 'a'; + if (p.children[index] == null) { + TrieNode newNode = new TrieNode(chars[i]); + p.children[index] = newNode; + } + p = p.children[index]; + } + p.isEnd = true; + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + TrieNode p = root; + char[] chars = word.toCharArray(); + for (int i = 0; i < chars.length; i++) { + int index = chars[i] - 'a'; + if (p.children[index] == null) + return false; + p = p.children[index]; + } + if (!p.isEnd) return false; + else return true; + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + TrieNode p = root; + char[] chars = prefix.toCharArray(); + for (int i = 0; i < chars.length; i++) { + int index = chars[i] - 'a'; + if (p.children[index] == null) + return false; + p = p.children[index]; + } + return true; + } + + class TrieNode{ + public char data; + public TrieNode[] children = new TrieNode[26]; + public boolean isEnd = false; + public TrieNode(char data) { + this.data = data; + } + } +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ \ No newline at end of file diff --git "a/week07/[70]\347\210\254\346\245\274\346\242\257.java" "b/week07/[70]\347\210\254\346\245\274\346\242\257.java" new file mode 100644 index 00000000..5e847435 --- /dev/null +++ "b/week07/[70]\347\210\254\346\245\274\346\242\257.java" @@ -0,0 +1,50 @@ +//假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 +// +// 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? +// +// 注意:给定 n 是一个正整数。 +// +// 示例 1: +// +// 输入: 2 +//输出: 2 +//解释: 有两种方法可以爬到楼顶。 +//1. 1 阶 + 1 阶 +//2. 2 阶 +// +// 示例 2: +// +// 输入: 3 +//输出: 3 +//解释: 有三种方法可以爬到楼顶。 +//1. 1 阶 + 1 阶 + 1 阶 +//2. 1 阶 + 2 阶 +//3. 2 阶 + 1 阶 +// +// Related Topics 动态规划 +class Solution { + public int climbStairs(int n) { + int p = 0, q= 0, r =1; + for (int i = 1; i<= n; i++) { + p = q; + q = r; + r = p + q; + } + return r; + } +} + +class Solution_1 { + + Map memo = new HashMap<>(); + + public int climbStairs(int n) { + Integer cache = memo.get(n); + if (cache != null) return cache; + if (n == 1) return 1; + if (n == 2) return 2; + int result = climbStairs(n - 1) + climbStairs(n - 2); + memo.putIfAbsent(n, result); + return result; + } +} \ No newline at end of file diff --git a/week08/NOTE.md b/week08/NOTE.md index 50de3041..dcc0cbcd 100644 --- a/week08/NOTE.md +++ b/week08/NOTE.md @@ -1 +1,66 @@ -学习笔记 \ No newline at end of file +学习笔记 + +## 选择排序 + +. 寻找最小值放到待排序数组的起始位置 + +``` + public static void selectionSort(int[] array) { + int len = array.length; + int minIndex, temp; + for (int i = 0 ; i < len - 1; i++) { + minIndex = i; + + // 寻找最小数 + for (int j = i + 1; j < len; j++) { + if (array[j] < array[minIndex]) + minIndex = j; + } + + temp = array[i]; + array[i] = array[minIndex]; + array[minIndex] = temp; + + } + } + +``` + +## 插入排序 + +. 从前到后逐步构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入 + +``` + public static void insertionSort(int[] array) { + int cur, preIndex; + for (int j = 1; j < array.length; j++) { + cur = array[j]; + preIndex = j - 1; + while (preIndex >= 0 && array[preIndex] > cur) { + array[preIndex + 1] = array[preIndex--]; + } + array[preIndex + 1] = cur; + } + } +``` + +## 冒泡排序 + +. 嵌套循环,每次查看相邻的的元素,如果逆序则交换。 +. 越小的元素会经由交换,慢慢浮到数列的顶端。 + +``` + public static void bubbleSort(int[] array) { + int len = array.length; + for (int i = 0; i < len - 1; i++) { + for (int j = 0; j < len - 1 - i; j++) { + if (array[j] > array[j + 1]) { + int temp = array[j]; + array[j] = array[j + 1]; + array[j + 1] = temp; + } + } + } + } + +``` diff --git "a/week08/[1122]\346\225\260\347\273\204\347\232\204\347\233\270\345\257\271\346\216\222\345\272\217.java" "b/week08/[1122]\346\225\260\347\273\204\347\232\204\347\233\270\345\257\271\346\216\222\345\272\217.java" new file mode 100644 index 00000000..45f3f47d --- /dev/null +++ "b/week08/[1122]\346\225\260\347\273\204\347\232\204\347\233\270\345\257\271\346\216\222\345\272\217.java" @@ -0,0 +1,84 @@ +//给你两个数组,arr1 和 arr2, +// +// +// arr2 中的元素各不相同 +// arr2 中的每个元素都出现在 arr1 中 +// +// +// 对 arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末 +//尾。 +// +// +// +// 示例: +// +// +//输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6] +//输出:[2,2,2,1,4,3,3,9,6,7,19] +// +// +// +// +// 提示: +// +// +// 1 <= arr1.length, arr2.length <= 1000 +// 0 <= arr1[i], arr2[i] <= 1000 +// arr2 中的元素 arr2[i] 各不相同 +// arr2 中的每个元素 arr2[i] 都出现在 arr1 中 +// +// Related Topics 排序 数组 + class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + // x,y都在arr2中,则比较x,y在arr2中的下标 + // x,y都不在arr2中,则比较x,y本身 + // x,y只有一个在arr2中,出现在arr2中的那个元素较小 + + Map indexs = new HashMap<>(); + for (int i = 0; i < arr2.length; i++) + indexs.put(arr2[i], i); + + List list = Arrays.stream(arr1).boxed().collect(Collectors.toList()); + list.sort((x, y) -> { + if (indexs.containsKey(x)) + return indexs.containsKey(y) ? indexs.get(x) - indexs.get(y) : -1; + else + return indexs.containsKey(y) ? 1 : x - y; + }); + + return list.stream().mapToInt(Integer::intValue).toArray(); + } + } + + class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + // 计数排序 + /* + 1. 统计arr1中每个元素出现的次数n,存入数组f + 2. 遍历arr2 -> x, f(x)个x加入结果集, 将f(x)置0 + 3. 遍历f, 如果f(x) != 0, 则将x加入结果集 + */ + + int max = Arrays.stream(arr1).max().getAsInt(); + int[] f = new int[max + 1]; + for (int x : arr1) + f[x]++; + + int[] result = new int[arr1.length]; + int index = 0; + for (int x : arr2) { + for (int i = 0; i < f[x]; i++) { + result[index++] = x; + } + f[x] = 0; + } + + for (int x = 0; x <= max; x++) { + for (int i = 0; i < f[x]; i++) { + result[index++] = x; + } + } + + return result; + } + } \ No newline at end of file diff --git "a/week08/[191]\344\275\2151\347\232\204\344\270\252\346\225\260.java" "b/week08/[191]\344\275\2151\347\232\204\344\270\252\346\225\260.java" new file mode 100644 index 00000000..51ae4ee4 --- /dev/null +++ "b/week08/[191]\344\275\2151\347\232\204\344\270\252\346\225\260.java" @@ -0,0 +1,69 @@ +//编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。 +// +// +// +// 提示: +// +// +// 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的 +//还是无符号的,其内部的二进制表示形式都是相同的。 +// 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。 +// +// +// +// +// 进阶: +// +// +// 如果多次调用这个函数,你将如何优化你的算法? +// +// +// +// +// 示例 1: +// +// +//输入:00000000000000000000000000001011 +//输出:3 +//解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。 +// +// +// 示例 2: +// +// +//输入:00000000000000000000000010000000 +//输出:1 +//解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。 +// +// +// 示例 3: +// +// +//输入:11111111111111111111111111111101 +//输出:31 +//解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。 +// +// +// +// 提示: +// +// +// 输入必须是长度为 32 的 二进制串 。 +// +// +// +// +// +// +// Related Topics 位运算 +public class Solution { + // you need to treat n as an unsigned value + public int hammingWeight(int n) { + int count = 0; + while (n !=0) { + n &= (n - 1); + count++; + } + return count; + } +} \ No newline at end of file diff --git "a/week08/[231]2\347\232\204\345\271\202.java" "b/week08/[231]2\347\232\204\345\271\202.java" new file mode 100644 index 00000000..01344816 --- /dev/null +++ "b/week08/[231]2\347\232\204\345\271\202.java" @@ -0,0 +1,24 @@ +//给定一个整数,编写一个函数来判断它是否是 2 的幂次方。 +// +// 示例 1: +// +// 输入: 1 +//输出: true +//解释: 20 = 1 +// +// 示例 2: +// +// 输入: 16 +//输出: true +//解释: 24 = 16 +// +// 示例 3: +// +// 输入: 218 +//输出: false +// Related Topics 位运算 数学 +class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} \ No newline at end of file diff --git "a/week08/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" "b/week08/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" new file mode 100644 index 00000000..d4208940 --- /dev/null +++ "b/week08/[242]\346\234\211\346\225\210\347\232\204\345\255\227\346\257\215\345\274\202\344\275\215\350\257\215.java" @@ -0,0 +1,40 @@ +//给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。 +// +// 示例 1: +// +// 输入: s = "anagram", t = "nagaram" +//输出: true +// +// +// 示例 2: +// +// 输入: s = "rat", t = "car" +//输出: false +// +// 说明: +//你可以假设字符串只包含小写字母。 +// +// 进阶: +//如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况? +// Related Topics 排序 哈希表 +class Solution { + public boolean isAnagram(String s, String t) { + if (s.length() != t.length()) + return false; + char[] sChars = s.toCharArray(); + char[] tChars = t.toCharArray(); + + int[] table = new int[26]; + + for (char c : sChars) + table[c - 'a']++; + for (char c : tChars) + table[c - 'a']--; + + for (int value : table) + if (value != 0) + return false; + + return true; + } +} \ No newline at end of file diff --git a/week09/NOTE.md b/week09/NOTE.md index 50de3041..8915e851 100644 --- a/week09/NOTE.md +++ b/week09/NOTE.md @@ -1 +1,22 @@ -学习笔记 \ No newline at end of file +学习笔记 + +## 不同路径2状态转移方程 + +当[i][j]上无障碍物时:dp[i][j] = dp[i - 1][j] + dp[i][j - 1] +当[i][j]上有障碍物时:dp[i][j] = 0 + +## 字符串 + +### 大小写转换(位运算) + +大写变小写、小写变大写:字符 ^= 32; +大写变小写、小写变小写:字符 |= 32; +大写变大写、小写变大写:字符 &= 33; + +SCII码表中大写的A是65,小写的a是97,它们的差是32 +65 | 32 转为二进制(按8位来算)可以得到 0100 0001 | 0010 0000 = 0110 0001 = 97 = a + +### 匹配算法 + +Rabin-Karp +KMP \ No newline at end of file diff --git "a/week09/[151]\347\277\273\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215.java" "b/week09/[151]\347\277\273\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215.java" new file mode 100644 index 00000000..4d232c97 --- /dev/null +++ "b/week09/[151]\347\277\273\350\275\254\345\255\227\347\254\246\344\270\262\351\207\214\347\232\204\345\215\225\350\257\215.java" @@ -0,0 +1,75 @@ +//给定一个字符串,逐个翻转字符串中的每个单词。 +// +// 说明: +// +// +// 无空格字符构成一个 单词 。 +// 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 +// 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 +// +// +// +// +// 示例 1: +// +// 输入:"the sky is blue" +//输出:"blue is sky the" +// +// +// 示例 2: +// +// 输入:"  hello world!  " +//输出:"world! hello" +//解释:输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 +// +// +// 示例 3: +// +// 输入:"a good   example" +//输出:"example good a" +//解释:如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 +// +// +// 示例 4: +// +// 输入:s = " Bob Loves Alice " +//输出:"Alice Loves Bob" +// +// +// 示例 5: +// +// 输入:s = "Alice does not even like bob" +//输出:"bob like even not does Alice" +// +// +// +// +// 提示: +// +// +// 1 <= s.length <= 104 +// s 包含英文大小写字母、数字和空格 ' ' +// s 中 至少存在一个 单词 +// +// +// +// +// +// +// +// 进阶: +// +// +// 请尝试使用 O(1) 额外空间复杂度的原地解法。 +// +// Related Topics 字符串 +class Solution { + public String reverseWords(String s) { + + List words = Arrays.asList(s.trim().split("\\s+")); + + Collections.reverse(words); + + return String.join(" ", words); + } +} \ No newline at end of file diff --git "a/week09/[205]\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262.java" "b/week09/[205]\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262.java" new file mode 100644 index 00000000..35d9dd33 --- /dev/null +++ "b/week09/[205]\345\220\214\346\236\204\345\255\227\347\254\246\344\270\262.java" @@ -0,0 +1,41 @@ +//给定两个字符串 s 和 t,判断它们是否是同构的。 +// +// 如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。 +// +// 所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。 +// +// 示例 1: +// +// 输入: s = "egg", t = "add" +//输出: true +// +// +// 示例 2: +// +// 输入: s = "foo", t = "bar" +//输出: false +// +// 示例 3: +// +// 输入: s = "paper", t = "title" +//输出: true +// +// 说明: +//你可以假设 s 和 t 具有相同的长度。 +// Related Topics 哈希表 +class Solution { + public boolean isIsomorphic(String s, String t) { + char[] sChars = s.toCharArray(); + char[] tChars = t.toCharArray(); + int[] firstIndexOfs = new int[256]; + int[] firstIndexOft = new int[256]; + + for (int i = 0; i < sChars.length; i++) { + if (firstIndexOfs[sChars[i]] != firstIndexOft[tChars[i]]) + return false; + firstIndexOfs[sChars[i]] = i + 1; + firstIndexOft[tChars[i]] = i + 1; + } + return true; + } +} \ No newline at end of file diff --git "a/week09/[300]\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" "b/week09/[300]\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" new file mode 100644 index 00000000..f54f54d1 --- /dev/null +++ "b/week09/[300]\346\234\200\351\225\277\351\200\222\345\242\236\345\255\220\345\272\217\345\210\227.java" @@ -0,0 +1,60 @@ +//给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 +// +// 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序 +//列。 +// +// +// 示例 1: +// +// +//输入:nums = [10,9,2,5,3,7,101,18] +//输出:4 +//解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。 +// +// +// 示例 2: +// +// +//输入:nums = [0,1,0,3,2,3] +//输出:4 +// +// +// 示例 3: +// +// +//输入:nums = [7,7,7,7,7,7,7] +//输出:1 +// +// +// +// +// 提示: +// +// +// 1 <= nums.length <= 2500 +// -104 <= nums[i] <= 104 +// +// +// +// +// 进阶: +// +// +// 你可以设计时间复杂度为 O(n2) 的解决方案吗? +// 你能将算法的时间复杂度降低到 O(n log(n)) 吗? +// +// Related Topics 二分查找 动态规划 + class Solution { + public int lengthOfLIS(int[] nums) { + int[] dp = new int[nums.length]; + Arrays.fill(dp, 1); + int result = 0; + for (int i = 0; i < nums.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[i] > nums[j]) dp[i] = Math.max(dp[i], dp[j] + 1); + } + result = Math.max(dp[i], result); + } + return result; + } + } \ No newline at end of file diff --git "a/week09/[387]\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\347\254\254\344\270\200\344\270\252\345\224\257\344\270\200\345\255\227\347\254\246.java" "b/week09/[387]\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\347\254\254\344\270\200\344\270\252\345\224\257\344\270\200\345\255\227\347\254\246.java" new file mode 100644 index 00000000..7438960a --- /dev/null +++ "b/week09/[387]\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\347\254\254\344\270\200\344\270\252\345\224\257\344\270\200\345\255\227\347\254\246.java" @@ -0,0 +1,34 @@ +//给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 +// +// +// +// 示例: +// +// s = "leetcode" +//返回 0 +// +//s = "loveleetcode" +//返回 2 +// +// +// +// +// 提示:你可以假定该字符串只包含小写字母。 +// Related Topics 哈希表 字符串 +class Solution { + public int firstUniqChar(String s) { + + Map map = new HashMap<>(); + char[] chars = s.toCharArray(); + for (char c : chars) { + map.put(c, map.getOrDefault(c, 0) + 1); + } + + for (int i = 0; i < chars.length; i++) { + if (map.get(chars[i]) == 1) + return i; + } + + return -1; + } +} \ No newline at end of file diff --git "a/week09/[541]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262 II.java" "b/week09/[541]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262 II.java" new file mode 100644 index 00000000..ad6e1474 --- /dev/null +++ "b/week09/[541]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262 II.java" @@ -0,0 +1,42 @@ +//给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。 +// +// +// 如果剩余字符少于 k 个,则将剩余字符全部反转。 +// 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。 +// +// +// +// +// 示例: +// +// 输入: s = "abcdefg", k = 2 +//输出: "bacdfeg" +// +// +// +// +// 提示: +// +// +// 该字符串只包含小写英文字母。 +// 给定字符串的长度和 k 在 [1, 10000] 范围内。 +// +// Related Topics 字符串 +class Solution { + public String reverseStr(String s, int k) { + + char[] chars = s.toCharArray(); + for (int start = 0; start < chars.length; start += 2 * k) { + int i = start; + int j = Math.min(start + k - 1, chars.length - 1); + while (i < j) { + char tmp = chars[i]; + chars[i++] = chars[j]; + chars[j--] = tmp; + } + } + + return new String(chars); + + } +} \ No newline at end of file diff --git "a/week09/[557]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215 III.java" "b/week09/[557]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215 III.java" new file mode 100644 index 00000000..c9eb31e2 --- /dev/null +++ "b/week09/[557]\345\217\215\350\275\254\345\255\227\347\254\246\344\270\262\344\270\255\347\232\204\345\215\225\350\257\215 III.java" @@ -0,0 +1,37 @@ +//给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 +// +// +// +// 示例: +// +// 输入:"Let's take LeetCode contest" +//输出:"s'teL ekat edoCteeL tsetnoc" +// +// +// +// +// 提示: +// +// +// 在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。 +// +// Related Topics 字符串 +class Solution { + public String reverseWords(String s) { + char[] chars = s.toCharArray(); + int i = 0, j; + for (int k = 0; k <= chars.length; k++) { + if (k == chars.length || chars[k] == ' ' ) { + j = k - 1; + // swap + while (i < j) { + char tmp = chars[i]; + chars[i++] = chars[j]; + chars[j--] = tmp; + } + i = k + 1; + } + } + return new String(chars); + } +} \ No newline at end of file diff --git "a/week09/[680]\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\262 \342\205\241.java" "b/week09/[680]\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\262 \342\205\241.java" new file mode 100644 index 00000000..9d1f7407 --- /dev/null +++ "b/week09/[680]\351\252\214\350\257\201\345\233\236\346\226\207\345\255\227\347\254\246\344\270\262 \342\205\241.java" @@ -0,0 +1,49 @@ +//给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。 +// +// 示例 1: +// +// +//输入: "aba" +//输出: True +// +// +// 示例 2: +// +// +//输入: "abca" +//输出: True +//解释: 你可以删除c字符。 +// +// +// 注意: +// +// +// 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。 +// +// Related Topics 字符串 + class Solution { + public boolean validPalindrome(String s) { + int left = 0, right = s.length() - 1; + while (left < right) { + if (s.charAt(left) == s.charAt(right)) { + left++; right--; + } else { + boolean flag1 = true, flag2 = true; + for (int i = left, j = right - 1; i < j; i++, j--) { + if (s.charAt(i) != s.charAt(j)) { + flag1 = false; + break; + } + } + for (int i = left + 1, j = right; i < j; i++, j--) { + if (s.charAt(i) != s.charAt(j)) { + flag2 = false; + break; + } + } + return flag1 || flag2; + } + } + return true; + } + } \ No newline at end of file diff --git "a/week09/[917]\344\273\205\344\273\205\345\217\215\350\275\254\345\255\227\346\257\215.java" "b/week09/[917]\344\273\205\344\273\205\345\217\215\350\275\254\345\255\227\346\257\215.java" new file mode 100644 index 00000000..0024d63a --- /dev/null +++ "b/week09/[917]\344\273\205\344\273\205\345\217\215\350\275\254\345\255\227\346\257\215.java" @@ -0,0 +1,57 @@ +//给定一个字符串 S,返回 “反转后的” 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转。 +// +// +// +// +// +// +// 示例 1: +// +// 输入:"ab-cd" +//输出:"dc-ba" +// +// +// 示例 2: +// +// 输入:"a-bC-dEf-ghIj" +//输出:"j-Ih-gfE-dCba" +// +// +// 示例 3: +// +// 输入:"Test1ng-Leet=code-Q!" +//输出:"Qedo1ct-eeLg=ntse-T!" +// +// +// +// +// 提示: +// +// +// S.length <= 100 +// 33 <= S[i].ASCIIcode <= 122 +// S 中不包含 \ or " +// +// Related Topics 字符串 +class Solution { + public String reverseOnlyLetters(String S) { + + char[] chars = S.toCharArray(); + int k = 0; + for (int i = S.length() - 1; i >= 0; i--) { + char c = S.charAt(i); + if (c >= 'a' && c <='z' || c>='A' && c <= 'Z') { + while (k < chars.length) { + char target = chars[k]; + if (target >= 'a' && target <='z' || target>='A' && target <= 'Z') { + chars[k++] = c; + break; + } + k++; + } + } + } + + return new String(chars); + } +} \ No newline at end of file diff --git a/week10/NOTE.md b/week10/NOTE.md index 50de3041..b6ccfc8d 100644 --- a/week10/NOTE.md +++ b/week10/NOTE.md @@ -1 +1,12 @@ -学习笔记 \ No newline at end of file +学习笔记 + + + +一转眼两个多月就过去了,由于工作日要处理工作,只有在周末的时候有充分的时间去完成训练营的任务。 很辛苦,但也很充实。 + +虽然很多算法和数据结构很早之前就了解,但是细节点还是会随着时间经常淡忘。在这10周刷题过程中让我又一点一点回顾了所有的知识点,并学习了不少解题的方法,获益良多。老题总结的一些方法也非常的实用,比如:拒约人肉递归、找最近最简方法、不死磕等。 + +在计算机领域基础知识永远都是创新的源头,从本质上理解原理,对平时的项目开发、阅读开源代码、理解中间件架构设计等方面都能起到重要的指导作用。 + +虽然训练营结束了,但学习之路还要继续,以后还要坚持刷题,温故而知新。 +最后要感谢训练营的老师和相关工作人员的一路陪伴。 \ No newline at end of file